From c8133d9a627954b012d766388fd2a711d1891b1c Mon Sep 17 00:00:00 2001 From: Artem Ruts Date: Fri, 28 Oct 2016 15:43:51 -0400 Subject: [PATCH 1/2] When checking if node A contains node B, will also check if A and B are valid DOM nodes. --- plugins/tungsten-event-mouseenter/index.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/tungsten-event-mouseenter/index.js b/plugins/tungsten-event-mouseenter/index.js index faa9d557..ecb54432 100644 --- a/plugins/tungsten-event-mouseenter/index.js +++ b/plugins/tungsten-event-mouseenter/index.js @@ -1,8 +1,22 @@ +/* eslint-env browser */ + /** * Module to handle the shimming in delegated mouseenter events */ 'use strict'; + +/** + * Check if passed object is a valid DOM Node + * @param {Object} node object to be validated + * @return {Boolean} whether object is a DOM node + */ +function isNode(node) { + return typeof Node === 'object' ? node instanceof Node : + node && typeof node === 'object' && typeof node.nodeType === 'number' && + typeof node.nodeName === 'string'; +} + /** * Fallback contains check from http://stackoverflow.com/a/6131052 * @param {Element} container Container element @@ -10,6 +24,10 @@ * @return {Boolean} Whether container contains maybe */ function contains(container, maybe) { + if (!isNode(container) || !isNode(maybe)) { + return false; + } + // 16 is for a nodeType constant: window.Node.DOCUMENT_POSITION_CONTAINED_BY, // but the window.Node object is not available in IE8 return container.contains ? container.contains(maybe) : From fff88296bdc313ce4a10daf259456a4410062c4f Mon Sep 17 00:00:00 2001 From: Artem Ruts Date: Sat, 29 Oct 2016 18:02:47 -0400 Subject: [PATCH 2/2] Adds tests for contains -> isNode check. --- plugins/tungsten-event-intent/index.js | 2 + plugins/tungsten-event-mouseenter/index.js | 1 - .../tungsten-event-mouseenter/index_spec.js | 38 ++++++++++++++++--- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/plugins/tungsten-event-intent/index.js b/plugins/tungsten-event-intent/index.js index be82afcf..1d834dbc 100644 --- a/plugins/tungsten-event-intent/index.js +++ b/plugins/tungsten-event-intent/index.js @@ -1,3 +1,5 @@ +/* eslint-env browser */ + /** * Module to handle "intent" delay on events */ diff --git a/plugins/tungsten-event-mouseenter/index.js b/plugins/tungsten-event-mouseenter/index.js index ecb54432..3e703dbb 100644 --- a/plugins/tungsten-event-mouseenter/index.js +++ b/plugins/tungsten-event-mouseenter/index.js @@ -5,7 +5,6 @@ */ 'use strict'; - /** * Check if passed object is a valid DOM Node * @param {Object} node object to be validated diff --git a/test/plugins/tungsten-event-mouseenter/index_spec.js b/test/plugins/tungsten-event-mouseenter/index_spec.js index 2d492c35..813a06ee 100644 --- a/test/plugins/tungsten-event-mouseenter/index_spec.js +++ b/test/plugins/tungsten-event-mouseenter/index_spec.js @@ -1,5 +1,5 @@ 'use strict'; -var mouseenterleaveBind = require('../../../plugins/tungsten-event-mouseenter'); +var mouseEnterLeaveBind = require('../../../plugins/tungsten-event-mouseenter'); describe('mouseenter_and_mouseleave_events', function() { var elem, otherElem, handler, obj; beforeEach(function() { @@ -23,14 +23,28 @@ describe('mouseenter_and_mouseleave_events', function() { }); }; spyOn(obj, 'bindEventFn').and.callThrough(); - mouseenterleaveBind(elem, 'mouseenter', '.js-foo', handler, {}, obj.bindEventFn); + mouseEnterLeaveBind(elem, 'mouseenter', '.js-foo', handler, {}, obj.bindEventFn); jasmineExpect(obj.bindEventFn).toHaveBeenCalledWith(elem, 'mouseover', '.js-foo', jasmine.any(Function), {}); }); it('should not call bindVirtualEvent when event is not mouseenter event', function() { var spy = jasmine.createSpy('spy'); - mouseenterleaveBind(elem, 'notmouseenter', '.js-foo', handler, {}, spy); + mouseEnterLeaveBind(elem, 'notmouseenter', '.js-foo', handler, {}, spy); jasmineExpect(spy).not.toHaveBeenCalled(); }); + it('should not call handler function when currentTarget is not a DOM node', function() { + obj.bindEventFn = function(el, eventName, selector, method) { + method({ + currentTarget: {}, + target: elem, + originalEvent: { + relatedTarget: otherElem + } + }); + }; + handler = jasmine.createSpy('handler'); + mouseEnterLeaveBind(elem, 'mouseenter', '.js-foo', handler, {}, obj.bindEventFn); + jasmineExpect(handler).not.toHaveBeenCalled(); + }); }); @@ -46,14 +60,28 @@ describe('mouseenter_and_mouseleave_events', function() { }); }; spyOn(obj, 'bindEventFn').and.callThrough(); - mouseenterleaveBind(elem, 'mouseleave', '.js-foo', handler, {}, obj.bindEventFn); + mouseEnterLeaveBind(elem, 'mouseleave', '.js-foo', handler, {}, obj.bindEventFn); jasmineExpect(obj.bindEventFn).toHaveBeenCalledWith(elem, 'mouseout', '.js-foo', jasmine.any(Function), {}); }); it('should not call bindVirtualEvent when event is not mouseleave event', function() { var spy = jasmine.createSpy('spy'); - mouseenterleaveBind(elem, 'notmouseleave', '.js-foo', handler, {}, spy); + mouseEnterLeaveBind(elem, 'notmouseleave', '.js-foo', handler, {}, spy); jasmineExpect(spy).not.toHaveBeenCalled(); }); + it('should not call handler function when currentTarget is not a DOM node', function() { + obj.bindEventFn = function(el, eventName, selector, method) { + method({ + currentTarget: {}, + target: elem, + originalEvent: { + relatedTarget: otherElem + } + }); + }; + handler = jasmine.createSpy('handler'); + mouseEnterLeaveBind(elem, 'mouseleave', '.js-foo', handler, {}, obj.bindEventFn); + jasmineExpect(handler).not.toHaveBeenCalled(); + }); }); });