diff options
| -rw-r--r-- | src/jqLite.js | 48 | ||||
| -rw-r--r-- | test/jqLiteSpec.js | 49 | 
2 files changed, 71 insertions, 26 deletions
| diff --git a/src/jqLite.js b/src/jqLite.js index cf63c5df..0abae3d7 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -607,23 +607,43 @@ forEach({        if (!eventFns) {          if (type == 'mouseenter' || type == 'mouseleave') { -          var counter = 0; +          var contains = document.body.contains || document.body.compareDocumentPosition ? +          function( a, b ) { +            var adown = a.nodeType === 9 ? a.documentElement : a, +            bup = b && b.parentNode; +            return a === bup || !!( bup && bup.nodeType === 1 && ( +              adown.contains ? +              adown.contains( bup ) : +              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 +              )); +            } : +            function( a, b ) { +              if ( b ) { +                while ( (b = b.parentNode) ) { +                  if ( b === a ) { +                    return true; +                  } +                } +              } +              return false; +            };	 -          events.mouseenter = []; -          events.mouseleave = []; +          events[type] = []; +		 +		  // Refer to jQuery's implementation of mouseenter & mouseleave +          // Read about mouseenter and mouseleave: +          // http://www.quirksmode.org/js/events_mouse.html#link8 +          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}           +          bindFn(element, eventmap[type], function(event) { +            var ret, target = this, related = event.relatedTarget; +            // For mousenter/leave call the handler if related is outside the target. +            // NB: No relatedTarget if the mouse left/entered the browser window +            if ( !related || (related !== target && !contains(target, related)) ){ +              handle(event, type); +            }	 -          bindFn(element, 'mouseover', function(event) { -            counter++; -            if (counter == 1) { -              handle(event, 'mouseenter'); -            } -          }); -          bindFn(element, 'mouseout', function(event) { -            counter --; -            if (counter == 0) { -              handle(event, 'mouseleave'); -            }            }); +          } else {            addEventListenerFn(element, type, handle);            events[type] = []; diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index b1fa6b05..089ae78c 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -775,13 +775,9 @@ describe('jqLite', function() {          parent.bind('mouseenter', function() { log += 'parentEnter;'; });          parent.bind('mouseleave', function() { log += 'parentLeave;'; }); -        parent.mouseover = function() { browserTrigger(parent, 'mouseover'); }; -        parent.mouseout = function() { browserTrigger(parent, 'mouseout'); };          child.bind('mouseenter', function() { log += 'childEnter;'; });          child.bind('mouseleave', function() { log += 'childLeave;'; }); -        child.mouseover = function() { browserTrigger(child, 'mouseover'); }; -        child.mouseout = function() { browserTrigger(child, 'mouseout'); };        });        afterEach(function() { @@ -790,20 +786,49 @@ describe('jqLite', function() {        it('should fire mouseenter when coming from outside the browser window', function() {          if (window.jQuery) return; -        parent.mouseover(); +        var browserMoveTrigger = function(from, to){ +          var fireEvent = function(type, element, relatedTarget){ +            var msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1]); +            if (msie < 9){ +              var evnt = document.createEventObject(); +              evnt.srcElement = element; +              evnt.relatedTarget = relatedTarget;		 +              element.fireEvent('on' + type, evnt); +              return; +            }; +            var evnt = document.createEvent('MouseEvents'), +            originalPreventDefault = evnt.preventDefault, +            appWindow = window, +            fakeProcessDefault = true, +            finalProcessDefault; + +            evnt.preventDefault = function() { +              fakeProcessDefault = false; +              return originalPreventDefault.apply(evnt, arguments); +            }; + +            var x = 0, y = 0; +            evnt.initMouseEvent(type, true, true, window, 0, x, y, x, y, false, false, +            false, false, 0, relatedTarget); + +            element.dispatchEvent(evnt); +          }; +          fireEvent('mouseout', from[0], to[0]); +          fireEvent('mouseover', to[0], from[0]); +        }; + +        browserMoveTrigger(root, parent);          expect(log).toEqual('parentEnter;'); -        child.mouseover(); -        expect(log).toEqual('parentEnter;childEnter;'); -        child.mouseover(); +        browserMoveTrigger(parent, child);          expect(log).toEqual('parentEnter;childEnter;'); -        child.mouseout(); -        expect(log).toEqual('parentEnter;childEnter;'); -        child.mouseout(); +        browserMoveTrigger(child, parent);          expect(log).toEqual('parentEnter;childEnter;childLeave;'); -        parent.mouseout(); + +        browserMoveTrigger(parent, root);          expect(log).toEqual('parentEnter;childEnter;childLeave;parentLeave;'); +        });      });    }); | 
