From dea3ab23dde83bd321550cb075bdf6dfdb6ca7bd Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Tue, 17 May 2022 19:01:31 +0200 Subject: [PATCH 1/2] Fix interoperability issue regarding Event properties - make possible to re-set read-only event properties - use hydrateObj() to set delegateTarget property Fixes #36207 --- js/src/dom/event-handler.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index 87f936b41d44..d2b452b7b261 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -89,7 +89,7 @@ function getElementEvents(element) { function bootstrapHandler(element, fn) { return function handler(event) { - event.delegateTarget = element + hydrateObj(event, { delegateTarget: element }) if (handler.oneOff) { EventHandler.off(element, event.type, fn) @@ -109,7 +109,7 @@ function bootstrapDelegationHandler(element, selector, fn) { continue } - event.delegateTarget = target + hydrateObj(event, { delegateTarget: target }) if (handler.oneOff) { EventHandler.off(element, event.type, selector, fn) @@ -303,6 +303,7 @@ const EventHandler = { function hydrateObj(obj, meta) { for (const [key, value] of Object.entries(meta || {})) { Object.defineProperty(obj, key, { + configurable: true, get() { return value } From faf45192beeef45fd0e49ac82e96b51f6ba2559e Mon Sep 17 00:00:00 2001 From: GeoSot Date: Sat, 11 Jun 2022 12:36:32 +0300 Subject: [PATCH 2/2] Add tests, and refactor the change --- js/src/dom/event-handler.js | 16 +++++++---- js/tests/unit/dom/event-handler.spec.js | 37 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index d2b452b7b261..0aa628c66dbd 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -302,12 +302,16 @@ const EventHandler = { function hydrateObj(obj, meta) { for (const [key, value] of Object.entries(meta || {})) { - Object.defineProperty(obj, key, { - configurable: true, - get() { - return value - } - }) + try { + obj[key] = value + } catch { + Object.defineProperty(obj, key, { + configurable: true, + get() { + return value + } + }) + } } return obj diff --git a/js/tests/unit/dom/event-handler.spec.js b/js/tests/unit/dom/event-handler.spec.js index 14037929bca9..19d0235e6cbf 100644 --- a/js/tests/unit/dom/event-handler.spec.js +++ b/js/tests/unit/dom/event-handler.spec.js @@ -441,4 +441,41 @@ describe('EventHandler', () => { expect(i).toEqual(5) }) }) + + describe('general functionality', () => { + it('should hydrate properties, and make them configurable', () => { + return new Promise(resolve => { + fixtureEl.innerHTML = [ + '
', + '
', + '
', + '
' + ].join('') + + const div1 = fixtureEl.querySelector('#div1') + const div2 = fixtureEl.querySelector('#div2') + const div3 = fixtureEl.querySelector('#div3') + + EventHandler.on(div1, 'click', event => { + event.originalTarget = div3 + + expect(event.currentTarget).toBe(div2) + + Object.defineProperty(event, 'currentTarget', { + configurable: true, + get() { + return div1 + } + }) + + expect(event.currentTarget).toBe(div1) + resolve() + }) + + expect(() => { + EventHandler.trigger(div1, 'click', { delegateTarget: div2, originalTarget: null, currentTarget: div2 }) + }).not.toThrowError(TypeError) + }) + }) + }) })