From c1f34e8eeb5105767f6cbf4727b8c5664be2a261 Mon Sep 17 00:00:00 2001 From: Kuzminov Aleksandr Sergeevich Date: Tue, 2 Dec 2014 12:17:46 +0300 Subject: [PATCH] fix(jqLite): ensure mouseenter works with svg elements on IE Closes #10259 Closes #10276 --- src/jqLite.js | 10 +++++- test/jqLiteSpec.js | 86 +++++++++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/jqLite.js b/src/jqLite.js index c899ac186ee4..80680ac55469 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -241,6 +241,14 @@ function jqLiteParseHTML(html, context) { return []; } + +// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259. +var jqLiteContains = Node.prototype.contains || function(arg) { + // jshint bitwise: false + return !!(this.compareDocumentPosition(arg) & 16); + // jshint bitwise: true +}; + ///////////////////////////////////////////// function JQLite(element) { if (element instanceof JQLite) { @@ -826,7 +834,7 @@ forEach({ var 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 && !target.contains(related))) { + if (!related || (related !== target && !jqLiteContains.call(target, related))) { handle(event, type); } }); diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 233e298f63f7..0fccd1e67c78 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1193,21 +1193,45 @@ describe('jqLite', function() { }); describe('mouseenter-mouseleave', function() { - var root, parent, sibling, child, log; + var root, parent, child, log; - beforeEach(function() { + function setup(html, parentNode, childNode) { log = ''; - root = jqLite('
root

parentchild

'); - parent = root.find('p'); - sibling = root.find('ul'); - child = parent.find('span'); + root = jqLite(html); + parent = root.find(parentNode); + child = parent.find(childNode); parent.on('mouseenter', function() { log += 'parentEnter;'; }); parent.on('mouseleave', function() { log += 'parentLeave;'; }); child.on('mouseenter', function() { log += 'childEnter;'; }); child.on('mouseleave', function() { log += 'childLeave;'; }); - }); + } + + function browserMoveTrigger(from, to) { + var fireEvent = function(type, element, relatedTarget) { + var evnt; + evnt = document.createEvent('MouseEvents'); + + var 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]); + } afterEach(function() { dealoc(root); @@ -1215,30 +1239,8 @@ describe('jqLite', function() { it('should fire mouseenter when coming from outside the browser window', function() { if (window.jQuery) return; - var browserMoveTrigger = function(from, to) { - var fireEvent = function(type, element, relatedTarget) { - var evnt; - evnt = document.createEvent('MouseEvents'); - - var 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]); - }; + + setup('
root

parentchild

', 'p', 'span'); browserMoveTrigger(root, parent); expect(log).toEqual('parentEnter;'); @@ -1253,6 +1255,28 @@ describe('jqLite', function() { expect(log).toEqual('parentEnter;childEnter;childLeave;parentLeave;'); }); + + it('should fire the mousenter on SVG elements', function() { + if (window.jQuery) return; + + setup( + '
' + + '' + + ' ' + + '' + + '
', + 'svg', 'path'); + + browserMoveTrigger(parent, child); + expect(log).toEqual('childEnter;'); + }); }); // Only run this test for jqLite and not normal jQuery