From f7e8e324eb21c8c528b15a6ec9096a9206e47684 Mon Sep 17 00:00:00 2001 From: Sebastien Roch Date: Mon, 18 Mar 2019 10:01:09 +0100 Subject: [PATCH 1/3] fix(ElementEvents): ElementEvents.defaultListenerOptions allows to set default options when subscribing to events ElementEvents.subscribe will set capture to true be default if not explicitely passed in argument. This is not the standard behavior of the native addEventListener() and confuses developers. This new options let you define the default behavior. Fixes issue #657 --- src/element-events.js | 12 +++++++++-- test/element-events.spec.js | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/element-events.js b/src/element-events.js index f1071a48..43f60af6 100644 --- a/src/element-events.js +++ b/src/element-events.js @@ -13,6 +13,8 @@ interface EventHandler { * @param element */ export class ElementEvents { + static defaultListenerOptions: boolean | AddEventListenerOptions = { capture: true }; + constructor(element: EventTarget) { this.element = element; this.subscriptions = {}; @@ -51,8 +53,11 @@ export class ElementEvents { * Adds and Event Listener on the context element. * @return Returns the eventHandler containing a dispose method */ - subscribe(eventName: string, handler: Function, captureOrOptions?: boolean = true): EventHandler { + subscribe(eventName: string, handler: Function, captureOrOptions?: boolean | AddEventListenerOptions): EventHandler { if (typeof handler === 'function') { + if (typeof captureOrOptions === 'undefined') { + captureOrOptions = ElementEvents.defaultListenerOptions; + } const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, false); return eventHandler; } @@ -64,8 +69,11 @@ export class ElementEvents { * Adds an Event Listener on the context element, that will be disposed on the first trigger. * @return Returns the eventHandler containing a dispose method */ - subscribeOnce(eventName: string, handler: Function, captureOrOptions?: boolean = true): EventHandler { + subscribeOnce(eventName: string, handler: Function, captureOrOptions?: boolean | AddEventListenerOptions): EventHandler { if (typeof handler === 'function') { + if (typeof captureOrOptions === 'undefined') { + captureOrOptions = ElementEvents.defaultListenerOptions; + } const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, true); return eventHandler; } diff --git a/test/element-events.spec.js b/test/element-events.spec.js index 223cbb2f..b60c2f27 100644 --- a/test/element-events.spec.js +++ b/test/element-events.spec.js @@ -53,6 +53,48 @@ describe('ElementEvents', () => { expect(callCount).toBe(1); }); + it("should subscribe and take ElementEvent default listener options into account", () => { + let isCapture; + + // we need to track event on a parent of the input, let's take body + const bodyElementEvents = new ElementEvents(document.body); + ElementEvents.defaultListenerOptions = { capture: false }; + let eventHandler = bodyElementEvents.subscribe('input', event => { + isCapture = event.eventPhase === Event.CAPTURING_PHASE; + }); + + // input has to be attached for the event to bubble up + document.body.appendChild(input); + input.dispatchEvent(new CustomEvent('input', {bubbles: true})); + expect(isCapture).toBe(false); + eventHandler.dispose(); + + + // set capture back to true and check if it's being used + ElementEvents.defaultListenerOptions = { capture: true }; + eventHandler = bodyElementEvents.subscribe('input', event => { + isCapture = event.eventPhase === Event.CAPTURING_PHASE; + }); + + input.dispatchEvent(new CustomEvent('input', {bubbles: true})); + expect(isCapture).toBe(true); + eventHandler.dispose(); + }); + + it("should subscribe and ignore ElementEvent default listener options when argument captureOrOptions is passed", () => { + let isCapture; + + const bodyElementEvents = new ElementEvents(document.body); + ElementEvents.defaultListenerOptions = { capture: false }; + bodyElementEvents.subscribe('input', event => { + isCapture = event.eventPhase === Event.CAPTURING_PHASE; + }, true); + + document.body.appendChild(input); + input.dispatchEvent(new CustomEvent('input', {bubbles: true})); + expect(isCapture).toBe(true); + }); + it('should dispose single event', () => { let value; let callCount = 0; From d68a806e16728d7d7f8f9b4d827b0ce2bd27e881 Mon Sep 17 00:00:00 2001 From: Sebastien Roch Date: Mon, 18 Mar 2019 10:35:48 +0100 Subject: [PATCH 2/3] set defautListenerOptions to boolean true for IE --- src/element-events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/element-events.js b/src/element-events.js index 43f60af6..c0d41d51 100644 --- a/src/element-events.js +++ b/src/element-events.js @@ -13,7 +13,7 @@ interface EventHandler { * @param element */ export class ElementEvents { - static defaultListenerOptions: boolean | AddEventListenerOptions = { capture: true }; + static defaultListenerOptions: boolean | AddEventListenerOptions = true; constructor(element: EventTarget) { this.element = element; From 10a97f945ae8f540e95ba15be2267afa45e5e182 Mon Sep 17 00:00:00 2001 From: Sebastien Roch Date: Mon, 18 Mar 2019 10:53:32 +0100 Subject: [PATCH 3/3] Only check argument against undefined --- src/element-events.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/element-events.js b/src/element-events.js index c0d41d51..1842bc7d 100644 --- a/src/element-events.js +++ b/src/element-events.js @@ -55,7 +55,7 @@ export class ElementEvents { */ subscribe(eventName: string, handler: Function, captureOrOptions?: boolean | AddEventListenerOptions): EventHandler { if (typeof handler === 'function') { - if (typeof captureOrOptions === 'undefined') { + if (captureOrOptions === undefined) { captureOrOptions = ElementEvents.defaultListenerOptions; } const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, false); @@ -71,7 +71,7 @@ export class ElementEvents { */ subscribeOnce(eventName: string, handler: Function, captureOrOptions?: boolean | AddEventListenerOptions): EventHandler { if (typeof handler === 'function') { - if (typeof captureOrOptions === 'undefined') { + if (captureOrOptions === undefined) { captureOrOptions = ElementEvents.defaultListenerOptions; } const eventHandler = new EventHandlerImpl(this, eventName, handler, captureOrOptions, true);