From 4863cbc12bc9fceccd5bfce1ace5cb95fea90c0e Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 6 Aug 2014 14:09:32 +0100 Subject: [PATCH 1/3] fix(jqLite): allow `triggerHandler()` to accept custom event In some scenarios you want to be able to specify properties on the event that is passed to the event handler. JQuery does this by overloading the first parameter (`eventName`). If it is an object with a `type` property then we assume that it must be a custom event. In this case the custom event must provide the `type` property which is the name of the event to be triggered. `triggerHandler` will continue to provide dummy default functions for `preventDefault()`, `isDefaultPrevented()` and `stopPropagation()` but you may override these with your own versions in your custom object if you wish. Closes #8469 --- src/jqLite.js | 22 ++++++++++++++-------- test/jqLiteSpec.js | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/jqLite.js b/src/jqLite.js index 0db4c25103f4..03b01bce9212 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -948,13 +948,8 @@ forEach({ clone: jqLiteClone, triggerHandler: function(element, eventName, eventData) { - // Copy event handlers in case event handlers array is modified during execution. - var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName], - eventFnsCopy = shallowCopy(eventFns || []); - eventData = eventData || []; - - var event = [{ + var event = { preventDefault: function() { this.defaultPrevented = true; }, @@ -962,10 +957,21 @@ forEach({ return this.defaultPrevented === true; }, stopPropagation: noop - }]; + }; + + if ( eventName.type ) { + extend(event, eventName); + eventName = event.type; + } + + var handlerArgs = [event].concat(eventData || []); + + // Copy event handlers in case event handlers array is modified during execution. + var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName], + eventFnsCopy = shallowCopy(eventFns || []); forEach(eventFnsCopy, function(fn) { - fn.apply(element, event.concat(eventData)); + fn.apply(element, handlerArgs); }); } }, function(fn, name){ diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 38ec858f03e7..3f63cce2d098 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1765,6 +1765,22 @@ describe('jqLite', function() { expect(clickOnceSpy).toHaveBeenCalledOnce(); expect(clickSpy.callCount).toBe(2); }); + + it("should accept a custom event instead of eventName", function() { + var element = jqLite('poke'), + pokeSpy = jasmine.createSpy('poke'), + customEvent = { + type: 'click', + someProp: 'someValue' + }, + actualEvent; + + element.on('click', pokeSpy); + element.triggerHandler(customEvent); + actualEvent = pokeSpy.mostRecentCall.args[0]; + expect(actualEvent.preventDefault).toBeDefined(); + expect(actualEvent.someProp).toEqual('someValue'); + }); }); From e12bc120f34a2312f173e78c69a467ad80320884 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 8 Aug 2014 13:59:16 +0100 Subject: [PATCH 2/3] fix(jqLite): allow `triggerHandler()` to accept custom event In some scenarios you want to be able to specify properties on the event that is passed to the event handler. JQuery does this by overloading the first parameter (`eventName`). If it is an object with a `type` property then we assume that it must be a custom event. In this case the custom event must provide the `type` property which is the name of the event to be triggered. `triggerHandler` will continue to provide dummy default functions for `preventDefault()`, `isDefaultPrevented()` and `stopPropagation()` but you may override these with your own versions in your custom object if you wish. Closes #8469 --- src/jqLite.js | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/jqLite.js b/src/jqLite.js index 03b01bce9212..3c491699b49c 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -947,32 +947,37 @@ forEach({ clone: jqLiteClone, - triggerHandler: function(element, eventName, eventData) { - - var event = { - preventDefault: function() { - this.defaultPrevented = true; - }, - isDefaultPrevented: function() { - return this.defaultPrevented === true; - }, - stopPropagation: noop - }; + triggerHandler: function(element, event, eventData) { - if ( eventName.type ) { - extend(event, eventName); - eventName = event.type; - } + var dummyEvent, eventFnsCopy, handlerArgs; + var eventName = event.type || event; + var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName]; - var handlerArgs = [event].concat(eventData || []); + if (eventFns) { - // Copy event handlers in case event handlers array is modified during execution. - var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName], - eventFnsCopy = shallowCopy(eventFns || []); + // Create a dummy event to pass to the handlers + dummyEvent = { + preventDefault: function() { this.defaultPrevented = true; }, + isDefaultPrevented: function() { return this.defaultPrevented === true; }, + stopPropagation: noop, + type: eventName, + target: element + }; - forEach(eventFnsCopy, function(fn) { - fn.apply(element, handlerArgs); - }); + // If a custom event was provided then extend our dummy event with it + if (event.type) { + dummyEvent = extend(dummyEvent, event); + } + + // Copy event handlers in case event handlers array is modified during execution. + eventFnsCopy = shallowCopy(eventFns); + handlerArgs = eventData ? [dummyEvent].concat(eventData) : [dummyEvent]; + + forEach(eventFnsCopy, function(fn) { + fn.apply(element, handlerArgs); + }); + + } } }, function(fn, name){ /** From 8eb20e80f3bb91aec17d84d5f4f06ff14672114c Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Fri, 8 Aug 2014 14:10:03 +0100 Subject: [PATCH 3/3] fix(jqLite): allow `triggerHandler()` to accept custom event In some scenarios you want to be able to specify properties on the event that is passed to the event handler. JQuery does this by overloading the first parameter (`eventName`). If it is an object with a `type` property then we assume that it must be a custom event. In this case the custom event must provide the `type` property which is the name of the event to be triggered. `triggerHandler` will continue to provide dummy default functions for `preventDefault()`, `isDefaultPrevented()` and `stopPropagation()` but you may override these with your own versions in your custom object if you wish. Closes #8469 --- src/jqLite.js | 4 ++-- test/jqLiteSpec.js | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/jqLite.js b/src/jqLite.js index 3c491699b49c..42ad8dea44db 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -947,7 +947,7 @@ forEach({ clone: jqLiteClone, - triggerHandler: function(element, event, eventData) { + triggerHandler: function(element, event, extraParameters) { var dummyEvent, eventFnsCopy, handlerArgs; var eventName = event.type || event; @@ -971,7 +971,7 @@ forEach({ // Copy event handlers in case event handlers array is modified during execution. eventFnsCopy = shallowCopy(eventFns); - handlerArgs = eventData ? [dummyEvent].concat(eventData) : [dummyEvent]; + handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent]; forEach(eventFnsCopy, function(fn) { fn.apply(element, handlerArgs); diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 3f63cce2d098..aeba79f654ae 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1718,9 +1718,11 @@ describe('jqLite', function() { element.triggerHandler('click'); event = pokeSpy.mostRecentCall.args[0]; expect(event.preventDefault).toBeDefined(); + expect(event.target).toEqual(element[0]); + expect(event.type).toEqual('click'); }); - it('should pass data as an additional argument', function() { + it('should pass extra parameters as an additional argument', function() { var element = jqLite('poke'), pokeSpy = jasmine.createSpy('poke'), data; @@ -1780,6 +1782,8 @@ describe('jqLite', function() { actualEvent = pokeSpy.mostRecentCall.args[0]; expect(actualEvent.preventDefault).toBeDefined(); expect(actualEvent.someProp).toEqual('someValue'); + expect(actualEvent.target).toEqual(element[0]); + expect(actualEvent.type).toEqual('click'); }); });