aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/jqLite.js112
-rw-r--r--test/jqLiteSpec.js44
2 files changed, 116 insertions, 40 deletions
diff --git a/src/jqLite.js b/src/jqLite.js
index 751d9eb1..48dfcc20 100644
--- a/src/jqLite.js
+++ b/src/jqLite.js
@@ -467,6 +467,50 @@ forEach({
};
});
+function createEventHandler(element) {
+ var eventHandler = function (event) {
+ if (!event.preventDefault) {
+ event.preventDefault = function() {
+ event.returnValue = false; //ie
+ };
+ }
+ if (!event.stopPropagation) {
+ event.stopPropagation = function() {
+ event.cancelBubble = true; //ie
+ };
+ }
+ if (!event.target) {
+ event.target = event.srcElement || document;
+ }
+
+ if (isUndefined(event.defaultPrevented)) {
+ var prevent = event.preventDefault;
+ event.preventDefault = function() {
+ event.defaultPrevented = true;
+ prevent.call(event);
+ };
+ event.defaultPrevented = false;
+ }
+
+ event.isDefaultPrevented = function() {
+ return event.defaultPrevented;
+ };
+
+ forEach(eventHandler.fns, function(fn){
+ fn.call(element, event);
+ });
+
+ // Remove monkey-patched methods (IE),
+ // as they would cause memory leaks in IE8.
+ // It shouldn't affect normal browsers, as their native methods are defined on prototype.
+ delete event.preventDefault;
+ delete event.stopPropagation;
+ delete event.isDefaultPrevented;
+ };
+ eventHandler.fns = [];
+ return eventHandler;
+};
+
//////////////////////////////////////////
// Functions iterating traversal.
// These functions chain results into a single
@@ -477,53 +521,41 @@ forEach({
dealoc: JQLiteDealoc,
- bind: function(element, type, fn){
+ bind: function bindFn(element, type, fn){
var bind = JQLiteData(element, 'bind');
+
+
if (!bind) JQLiteData(element, 'bind', bind = {});
forEach(type.split(' '), function(type){
var eventHandler = bind[type];
- if (!eventHandler) {
- bind[type] = eventHandler = function(event) {
- if (!event.preventDefault) {
- event.preventDefault = function() {
- event.returnValue = false; //ie
- };
- }
- if (!event.stopPropagation) {
- event.stopPropagation = function() {
- event.cancelBubble = true; //ie
- };
- }
- if (!event.target) {
- event.target = event.srcElement || document;
- }
-
- if (isUndefined(event.defaultPrevented)) {
- var prevent = event.preventDefault;
- event.preventDefault = function() {
- event.defaultPrevented = true;
- prevent.call(event);
- };
- event.defaultPrevented = false;
- }
- event.isDefaultPrevented = function() {
- return event.defaultPrevented;
- };
- forEach(eventHandler.fns, function(fn){
- fn.call(element, event);
+ if (!eventHandler) {
+ if (type == 'mouseenter' || type == 'mouseleave') {
+ var mouseenter = bind.mouseenter = createEventHandler(element);
+ var mouseleave = bind.mouseleave = createEventHandler(element);
+ var counter = 0;
+
+
+ bindFn(element, 'mouseover', function(event) {
+ counter++;
+ if (counter == 1) {
+ event.type = 'mouseenter';
+ mouseenter(event);
+ }
});
-
- // Remove monkey-patched methods (IE),
- // as they would cause memory leaks in IE8.
- // It shouldn't affect normal browsers, as their native methods are defined on prototype.
- delete event.preventDefault
- delete event.stopPropagation
- delete event.isDefaultPrevented
- };
- eventHandler.fns = [];
- addEventListenerFn(element, type, eventHandler);
+ bindFn(element, 'mouseout', function(event) {
+ counter --;
+ if (counter == 0) {
+ event.type = 'mouseleave';
+ mouseleave(event);
+ }
+ });
+ eventHandler = bind[type];
+ } else {
+ eventHandler = bind[type] = createEventHandler(element);
+ addEventListenerFn(element, type, eventHandler);
+ }
}
eventHandler.fns.push(fn);
});
diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js
index 8b49502f..358b8c4a 100644
--- a/test/jqLiteSpec.js
+++ b/test/jqLiteSpec.js
@@ -603,6 +603,50 @@ describe('jqLite', function() {
browserTrigger(a, 'click');
});
+
+ describe('mouseenter-mouseleave', function() {
+ var root, parent, sibling, child, log;
+
+ beforeEach(function() {
+ log = '';
+ root = jqLite('<div>root<p>parent<span>child</span></p><ul></ul></div>');
+ parent = root.find('p');
+ sibling = root.find('ul');
+ child = parent.find('span');
+
+ parent.bind('mouseenter', function() { log += 'parentEnter;'; });
+ parent.bind('mouseleave', function() { log += 'parentLeave;'; });
+ parent.mouseover = function(event) { parent.data('bind').mouseover(event || {}); };
+ parent.mouseout = function(event) { parent.data('bind').mouseout(event || {}); };
+
+ child.bind('mouseenter', function() { log += 'childEnter;'; });
+ child.bind('mouseleave', function() { log += 'childLeave;'; });
+ child.mouseover = function(event) { child.data('bind').mouseover(event || {}); };
+ child.mouseout = function(event) { child.data('bind').mouseout(event || {}); };
+ });
+
+ afterEach(function() {
+ dealoc(root);
+ });
+
+ it('should fire mouseenter when coming from outside the browser window', function() {
+ if (window.jQuery) return;
+ parent.mouseover();
+ expect(log).toEqual('parentEnter;');
+
+ child.mouseover();
+ expect(log).toEqual('parentEnter;childEnter;');
+ child.mouseover();
+ expect(log).toEqual('parentEnter;childEnter;');
+
+ child.mouseout();
+ expect(log).toEqual('parentEnter;childEnter;');
+ child.mouseout();
+ expect(log).toEqual('parentEnter;childEnter;childLeave;');
+ parent.mouseout();
+ expect(log).toEqual('parentEnter;childEnter;childLeave;parentLeave;');
+ });
+ });
});