From c4aaab2d6066fe627de1c7488b8a9b53f2712eba Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Mon, 10 Dec 2018 16:46:59 +0200 Subject: [PATCH 1/2] Prevent stack overflow for geteventlisteners hook --- libs/core/src/lib/renderer/geteventlisteners.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/core/src/lib/renderer/geteventlisteners.ts b/libs/core/src/lib/renderer/geteventlisteners.ts index 9527f51d..8287d1f3 100644 --- a/libs/core/src/lib/renderer/geteventlisteners.ts +++ b/libs/core/src/lib/renderer/geteventlisteners.ts @@ -9,6 +9,10 @@ */ export function initHooks() { // save the original methods before overwriting them + if (Element.prototype['_addEventListener'] && Element.prototype['_removeEventListener']) { + return; + } + Element.prototype['_addEventListener'] = Element.prototype.addEventListener; Element.prototype['_removeEventListener'] = Element.prototype.removeEventListener; From 039c0b2bede909f398e553b1bcfd1b3c5c092354 Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Tue, 11 Dec 2018 19:22:14 +0200 Subject: [PATCH 2/2] Fix geteventlisteners import to work with HMR as well --- .../src/lib/renderer/geteventlisteners.ts | 120 +++++++++--------- libs/core/src/lib/renderer/renderer.ts | 5 +- 2 files changed, 58 insertions(+), 67 deletions(-) diff --git a/libs/core/src/lib/renderer/geteventlisteners.ts b/libs/core/src/lib/renderer/geteventlisteners.ts index 8287d1f3..c7907a68 100644 --- a/libs/core/src/lib/renderer/geteventlisteners.ts +++ b/libs/core/src/lib/renderer/geteventlisteners.ts @@ -1,81 +1,76 @@ -// Taken and modified from https://github.com/colxi/getEventListeners to be compiled into ES5, allowing running in older browsers - /** * Monkey-patches `Element`'s `addEventListener` & `removeEventListener` and adds `getEventListeners`. * This later allows the renderer to emit any event handlers attached to React-wrapped components as Angular Outputs: -```html - -``` - */ -export function initHooks() { - // save the original methods before overwriting them - if (Element.prototype['_addEventListener'] && Element.prototype['_removeEventListener']) { - return; - } + * ```html + * + * ``` + * + * @note Taken and modified from https://github.com/colxi/getEventListeners to be compiled into ES5, allowing running in older browsers + **/ - Element.prototype['_addEventListener'] = Element.prototype.addEventListener; - Element.prototype['_removeEventListener'] = Element.prototype.removeEventListener; +Element.prototype['_addEventListener'] = Element.prototype.addEventListener; +Element.prototype['_removeEventListener'] = Element.prototype.removeEventListener; - Element.prototype.addEventListener = function( - type: K, - listener: (this: Element, ev: ElementEventMap[K]) => any, - options?: boolean | AddEventListenerOptions - ): void { - if (options === undefined) options = false; +Element.prototype.addEventListener = function( + type: K, + listener: (this: Element, ev: ElementEventMap[K]) => any, + options?: boolean | AddEventListenerOptions +): void { + if (options === undefined) options = false; - // declare listener - this._addEventListener(type, listener, options); + // declare listener + this._addEventListener(type, listener, options); - if (!this.eventListenerList) this.eventListenerList = {}; - if (!this.eventListenerList[type]) this.eventListenerList[type] = []; + if (!this.eventListenerList) this.eventListenerList = {}; + if (!this.eventListenerList[type]) this.eventListenerList[type] = []; - // add listener to event tracking list - this.eventListenerList[type].push({ - type: type, - listener: listener, - useCapture: options, - }); - }; + // add listener to event tracking list + this.eventListenerList[type].push({ + type: type, + listener: listener, + useCapture: options, + }); +}; - Element.prototype.removeEventListener = function( - type: K, - listener: (this: Element, ev: ElementEventMap[K]) => any, - options?: boolean | EventListenerOptions - ): void { - if (options === undefined) options = false; +Element.prototype.removeEventListener = function( + type: K, + listener: (this: Element, ev: ElementEventMap[K]) => any, + options?: boolean | EventListenerOptions +): void { + if (options === undefined) options = false; - // remove listener - this._removeEventListener(type, listener, options); + // remove listener + this._removeEventListener(type, listener, options); - if (!this.eventListenerList) this.eventListenerList = {}; - if (!this.eventListenerList[type]) this.eventListenerList[type] = []; + if (!this.eventListenerList) this.eventListenerList = {}; + if (!this.eventListenerList[type]) this.eventListenerList[type] = []; - // Find the event in the list, If a listener is registered twice, one - // with capture and one without, remove each one separately. Removal of - // a capturing listener does not affect a non-capturing version of the - // same listener, and vice versa. - for (let i = 0; i < this.eventListenerList[type].length; i++) { - if ( - this.eventListenerList[type][i].listener === listener && - this.eventListenerList[type][i].useCapture === options - ) { - this.eventListenerList[type].splice(i, 1); - break; - } + // Find the event in the list, If a listener is registered twice, one + // with capture and one without, remove each one separately. Removal of + // a capturing listener does not affect a non-capturing version of the + // same listener, and vice versa. + for (let i = 0; i < this.eventListenerList[type].length; i++) { + if ( + this.eventListenerList[type][i].listener === listener && + this.eventListenerList[type][i].useCapture === options + ) { + this.eventListenerList[type].splice(i, 1); + break; } - // if no more events of the removed event type are left,remove the group - if (this.eventListenerList[type].length == 0) delete this.eventListenerList[type]; - }; + } + // if no more events of the removed event type are left,remove the group + if (this.eventListenerList[type].length == 0) delete this.eventListenerList[type]; +}; - Element.prototype.getEventListeners = function(type?: K) { - if (!this.eventListenerList) this.eventListenerList = {}; +Element.prototype.getEventListeners = function(type?: K) { + if (!this.eventListenerList) this.eventListenerList = {}; - // return requested listeners type or all them - if (type === undefined) return this.eventListenerList; - return this.eventListenerList[type]; - }; + // return requested listeners type or all them + if (type === undefined) return this.eventListenerList; + return this.eventListenerList[type]; +}; - /* +/* Element.prototype.clearEventListeners = function(a){ if(!this.eventListenerList) this.eventListenerList = {}; @@ -92,4 +87,3 @@ export function initHooks() { } }; */ -} diff --git a/libs/core/src/lib/renderer/renderer.ts b/libs/core/src/lib/renderer/renderer.ts index da19ee90..8a9ec38f 100644 --- a/libs/core/src/lib/renderer/renderer.ts +++ b/libs/core/src/lib/renderer/renderer.ts @@ -8,7 +8,7 @@ import { Disguise } from './components/Disguise'; import { ReactContent } from './react-content'; import { isReactNode, ReactNode } from './react-node'; import { registerElement } from './registry'; -import { initHooks as initGetEventListeners } from './geteventlisteners'; +import './geteventlisteners'; const DEBUG = false; @@ -84,9 +84,6 @@ export class ReactRenderer implements Renderer2 { }; constructor(public readonly rootRenderer: AngularReactRendererFactory) { - // Attach hooks to event handlers so we can intercept and re-emit any event handlers passed to React-wrapper components - initGetEventListeners(); - // These two elements are essential for the whole experience to be smooth for the user - register them from the get-go. registerElement('ReactContent', () => ReactContent); registerElement('Disguise', () => Disguise);