diff options
| -rw-r--r-- | src/jqLite.js | 112 | ||||
| -rw-r--r-- | test/jqLiteSpec.js | 44 | 
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;'); +      }); +    });    }); | 
