diff --git a/js/src/dom/eventHandler.js b/js/src/dom/eventHandler.js index a69ab61368..b72684f819 100644 --- a/js/src/dom/eventHandler.js +++ b/js/src/dom/eventHandler.js @@ -16,6 +16,8 @@ const workingDefaultPrevented = (() => { return e.defaultPrevented })() +let defaultPreventedPreservedOnDispatch = true + // CustomEvent polyfill for IE (see: https://mzl.la/2v76Zvn) if (typeof window.CustomEvent !== 'function') { window.CustomEvent = (event, params) => { @@ -46,6 +48,20 @@ if (typeof window.CustomEvent !== 'function') { } window.CustomEvent.prototype = window.Event.prototype +} else { + // MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached + defaultPreventedPreservedOnDispatch = (() => { + const e = new CustomEvent('Bootstrap', { + cancelable: true + }) + + const element = document.createElement('div') + element.addEventListener('Bootstrap', () => null) + + e.preventDefault() + element.dispatchEvent(e) + return e.defaultPrevented + })() } // Event constructor shim @@ -276,7 +292,7 @@ const EventHandler = { if (isNative) { evt = document.createEvent('HTMLEvents') - evt.initEvent(typeEvent, true, true) + evt.initEvent(typeEvent, bubbles, true) } else { evt = new CustomEvent(event, { bubbles, @@ -291,6 +307,12 @@ const EventHandler = { if (defaultPrevented) { evt.preventDefault() + + if (!defaultPreventedPreservedOnDispatch) { + Object.defineProperty(evt, 'defaultPrevented', { + get: () => true + }) + } } if (nativeDispatch) { diff --git a/js/tests/unit/dom/eventHandler.js b/js/tests/unit/dom/eventHandler.js index 49cc89c65f..0730e38468 100644 --- a/js/tests/unit/dom/eventHandler.js +++ b/js/tests/unit/dom/eventHandler.js @@ -59,6 +59,24 @@ $(function () { EventHandler.trigger(element, 'foobar.namespace') }) + QUnit.test('should mirror preventDefault for native events', function (assert) { + assert.expect(2) + + var element = document.createElement('div') + document.body.appendChild(element) + + $(element).on('click', function (event) { + event.preventDefault() + assert.ok(true, 'first listener called') + }) + element.addEventListener('click', function (event) { + assert.ok(event.defaultPrevented, 'defaultPrevented is true in second listener') + }) + + EventHandler.trigger(element, 'click') + document.body.removeChild(element) + }) + QUnit.test('on should add event listener', function (assert) { assert.expect(1)