diff --git a/.eslintrc.js b/.eslintrc.js index 1afb795562b..0864a4f08c4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -81,6 +81,7 @@ module.exports = { Set: true, Symbol: true, WeakMap: true, + Event: true, }, rules: { diff --git a/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts b/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts index c81f4b23565..1ae1ca26a74 100644 --- a/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts +++ b/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts @@ -3,7 +3,6 @@ import { TargetActionSupport } from '@ember/-internals/runtime'; import { TextSupport } from '@ember/-internals/views'; import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { assert } from '@ember/debug'; -import { JQUERY_INTEGRATION } from '@ember/deprecated-features'; import { action } from '@ember/object'; import { isConstRef, isUpdatableRef, Reference, updateRef, valueForRef } from '@glimmer/reference'; import Component from '../component'; @@ -14,7 +13,6 @@ import InternalComponent, { handleDeprecatedAttributeArguments, handleDeprecatedEventArguments, InternalComponentConstructor, - jQueryEventShim, } from './internal'; const UNINITIALIZED: unknown = Object.freeze({}); @@ -243,8 +241,4 @@ export function handleDeprecatedFeatures( }); } } - - if (JQUERY_INTEGRATION) { - jQueryEventShim(target); - } } diff --git a/packages/@ember/-internals/glimmer/lib/components/internal.ts b/packages/@ember/-internals/glimmer/lib/components/internal.ts index 81528e7cc2b..f3ac67a5c57 100644 --- a/packages/@ember/-internals/glimmer/lib/components/internal.ts +++ b/packages/@ember/-internals/glimmer/lib/components/internal.ts @@ -1,9 +1,7 @@ import { Owner, setOwner } from '@ember/-internals/owner'; import { guidFor } from '@ember/-internals/utils'; -import { jQuery, jQueryDisabled } from '@ember/-internals/views'; import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { assert, deprecate } from '@ember/debug'; -import { JQUERY_INTEGRATION } from '@ember/deprecated-features'; import { CapturedArguments, Destroyable, @@ -552,25 +550,3 @@ if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { }); }; } - -export function jQueryEventShim(target: DeprecatingInternalComponentConstructor): void { - if (JQUERY_INTEGRATION) { - let { prototype } = target; - - let superListenerFor = prototype['listenerFor']; - - Object.defineProperty(prototype, 'listenerFor', { - configurable: true, - enumerable: false, - value: function listenerFor(this: InternalComponent, name: string): EventListener { - let listener = superListenerFor.call(this, name); - - if (jQuery && !jQueryDisabled) { - return (event: Event) => listener(new jQuery.Event(event)); - } else { - return listener; - } - }, - }); - } -} diff --git a/packages/@ember/-internals/glimmer/lib/components/link-to.ts b/packages/@ember/-internals/glimmer/lib/components/link-to.ts index 3bb0b105281..a823da4b978 100644 --- a/packages/@ember/-internals/glimmer/lib/components/link-to.ts +++ b/packages/@ember/-internals/glimmer/lib/components/link-to.ts @@ -5,7 +5,6 @@ import { TargetActionSupport } from '@ember/-internals/runtime'; import { isSimpleClick } from '@ember/-internals/views'; import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { assert, debugFreeze, deprecate, warn } from '@ember/debug'; -import { JQUERY_INTEGRATION } from '@ember/deprecated-features'; import { EngineInstance, getEngineParent } from '@ember/engine'; import { flaggedInstrument } from '@ember/instrumentation'; import { action } from '@ember/object'; @@ -22,7 +21,6 @@ import InternalComponent, { handleDeprecatedArguments, handleDeprecatedAttributeArguments, handleDeprecatedEventArguments, - jQueryEventShim, opaquify, } from './internal'; @@ -710,8 +708,4 @@ if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { } } -if (JQUERY_INTEGRATION) { - jQueryEventShim(LinkTo); -} - export default opaquify(LinkTo, LinkToTemplate); diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/input-angle-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/input-angle-test.js index 4657de9ddd9..3a7693f42b2 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/input-angle-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/input-angle-test.js @@ -1,10 +1,10 @@ -import { RenderingTestCase, moduleFor, runDestroy, runTask } from 'internal-test-helpers'; +import { moduleFor, RenderingTestCase, runDestroy, runTask } from 'internal-test-helpers'; import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { action } from '@ember/object'; import { Checkbox, TextArea, TextField } from '@ember/-internals/glimmer'; import { set } from '@ember/-internals/metal'; import { TargetActionSupport } from '@ember/-internals/runtime'; -import { getElementView, jQueryDisabled, jQuery, TextSupport } from '@ember/-internals/views'; +import { getElementView, TextSupport } from '@ember/-internals/views'; import { Component } from '../../utils/helpers'; @@ -563,11 +563,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -589,11 +585,7 @@ moduleFor( foo(value, event) { triggered++; assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -663,11 +655,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -686,11 +674,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -710,11 +694,7 @@ moduleFor( foo(value, event) { triggered++; assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -740,11 +720,7 @@ moduleFor( foo(value, event) { triggered++; assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/input-curly-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/input-curly-test.js index 589649eecd4..93dd57ed485 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/input-curly-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/input-curly-test.js @@ -3,7 +3,6 @@ import { RenderingTestCase, moduleFor, runDestroy, runTask } from 'internal-test import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { action } from '@ember/object'; import { set } from '@ember/-internals/metal'; -import { jQueryDisabled, jQuery } from '@ember/-internals/views'; import { Component } from '../../utils/helpers'; @@ -394,11 +393,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -420,11 +415,7 @@ moduleFor( foo(value, event) { triggered++; assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -494,11 +485,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -517,11 +504,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -541,11 +524,7 @@ moduleFor( foo(value, event) { triggered++; assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); @@ -566,11 +545,7 @@ moduleFor( actions: { foo(value, event) { assert.ok(true, 'action was triggered'); - if (jQueryDisabled) { - assert.notOk(event.originalEvent, 'event is not a jQuery.Event'); - } else { - assert.ok(event instanceof jQuery.Event, 'jQuery event was passed'); - } + assert.ok(event instanceof Event, 'Native event was passed'); }, }, }); diff --git a/packages/@ember/-internals/glimmer/tests/integration/event-dispatcher-test.js b/packages/@ember/-internals/glimmer/tests/integration/event-dispatcher-test.js index 127b8fd4384..e893ecc8a8a 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/event-dispatcher-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/event-dispatcher-test.js @@ -1,14 +1,12 @@ -import { RenderingTestCase, moduleFor, runTask } from 'internal-test-helpers'; +import { moduleFor, RenderingTestCase, runTask } from 'internal-test-helpers'; import { Component } from '../utils/helpers'; import { _getCurrentRunLoop } from '@ember/runloop'; import { - subscribe as instrumentationSubscribe, reset as instrumentationReset, + subscribe as instrumentationSubscribe, } from '@ember/instrumentation'; import { EMBER_IMPROVED_INSTRUMENTATION } from '@ember/canary-features'; -import { jQueryDisabled, jQuery } from '@ember/-internals/views'; -import { DEBUG } from '@glimmer/env'; let canDataTransfer = Boolean(document.createEvent('HTMLEvents').dataTransfer); @@ -273,6 +271,29 @@ moduleFor( this.$('#is-done').trigger('click'); } + ['@test native event on text node does not throw on hasAttribute [ISSUE #16730]'](assert) { + this.registerComponent('x-foo', { + ComponentClass: Component.extend({ + actions: { + someAction() {}, + }, + }), + template: `test`, + }); + + this.render(`{{x-foo id="outer"}}`); + + let node = this.$('#inner')[0].childNodes[0]; + + runTask(() => { + let event = document.createEvent('HTMLEvents'); + event.initEvent('mousemove', true, true); + node.dispatchEvent(event); + }); + + assert.ok(true); + } + ['@test [DEPRECATED] delegated event listeners work for mouseEnter/Leave'](assert) { let receivedEnterEvents = []; let receivedLeaveEvents = []; @@ -669,181 +690,3 @@ if (canDataTransfer) { } ); } - -if (jQueryDisabled) { - moduleFor( - 'EventDispatcher#native-events', - class extends RenderingTestCase { - ['@test native events are passed when jQuery is not present'](assert) { - let receivedEvent; - - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - click(event) { - receivedEvent = event; - }, - }), - template: ``, - }); - - this.render(`{{x-foo}}`); - - runTask(() => this.$('#foo').click()); - assert.ok(receivedEvent, 'click event was triggered'); - assert.notOk(receivedEvent.originalEvent, 'event is not a jQuery.Event'); - } - - ['@test native event on text node does not throw on hasAttribute [ISSUE #16730]'](assert) { - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - actions: { - someAction() {}, - }, - }), - template: `test`, - }); - - this.render(`{{x-foo id="outer"}}`); - - let node = this.$('#inner')[0].childNodes[0]; - - runTask(() => { - let event = document.createEvent('HTMLEvents'); - event.initEvent('mousemove', true, true); - node.dispatchEvent(event); - }); - - assert.ok(true); - } - } - ); -} else { - moduleFor( - 'EventDispatcher#jquery-events', - class extends RenderingTestCase { - beforeEach() { - this.jqueryIntegration = window.EmberENV._JQUERY_INTEGRATION; - } - - afterEach() { - window.EmberENV._JQUERY_INTEGRATION = this.jqueryIntegration; - } - - ['@test jQuery events are passed when jQuery is present'](assert) { - let receivedEvent; - - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - click(event) { - receivedEvent = event; - }, - }), - template: ``, - }); - - this.render(`{{x-foo}}`); - - runTask(() => this.$('#foo').click()); - assert.ok(receivedEvent, 'click event was triggered'); - assert.ok(receivedEvent instanceof jQuery.Event, 'event is a jQuery.Event'); - } - - ['@test accessing jQuery.Event#originalEvent is deprecated'](assert) { - let receivedEvent; - - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - click(event) { - receivedEvent = event; - }, - }), - template: ``, - }); - - this.render(`{{x-foo}}`); - - runTask(() => this.$('#foo').click()); - expectDeprecation(() => { - let { originalEvent } = receivedEvent; - assert.ok(originalEvent, 'jQuery event has originalEvent property'); - assert.equal(originalEvent.type, 'click', 'properties of originalEvent are available'); - }, 'Accessing jQuery.Event specific properties is deprecated. Either use the ember-jquery-legacy addon to normalize events to native events, or explicitly opt into jQuery integration using @ember/optional-features.'); - } - - ['@test other jQuery.Event properties do not trigger deprecation'](assert) { - let receivedEvent; - - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - click(event) { - receivedEvent = event; - }, - }), - template: ``, - }); - - this.render(`{{x-foo}}`); - - runTask(() => this.$('#foo').click()); - expectNoDeprecation(() => { - receivedEvent.stopPropagation(); - receivedEvent.stopImmediatePropagation(); - receivedEvent.preventDefault(); - assert.ok(receivedEvent.bubbles, 'properties of jQuery event are available'); - assert.equal(receivedEvent.type, 'click', 'properties of jQuery event are available'); - }); - } - - ['@test accessing jQuery.Event#originalEvent does not trigger deprecations when jquery integration is explicitly enabled']( - assert - ) { - let receivedEvent; - window.EmberENV._JQUERY_INTEGRATION = true; - - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - click(event) { - receivedEvent = event; - }, - }), - template: ``, - }); - - this.render(`{{x-foo}}`); - - runTask(() => this.$('#foo').click()); - expectNoDeprecation(() => { - let { originalEvent } = receivedEvent; - assert.ok(originalEvent, 'jQuery event has originalEvent property'); - assert.equal(originalEvent.type, 'click', 'properties of originalEvent are available'); - }); - } - - [`@${ - DEBUG ? 'test' : 'skip' - } accessing jQuery.Event#__originalEvent does not trigger deprecations to support ember-jquery-legacy`]( - assert - ) { - let receivedEvent; - - this.registerComponent('x-foo', { - ComponentClass: Component.extend({ - click(event) { - receivedEvent = event; - }, - }), - template: ``, - }); - - this.render(`{{x-foo}}`); - - runTask(() => this.$('#foo').click()); - expectNoDeprecation(() => { - let { __originalEvent: originalEvent } = receivedEvent; - assert.ok(originalEvent, 'jQuery event has __originalEvent property'); - assert.equal(originalEvent.type, 'click', 'properties of __originalEvent are available'); - }); - } - } - ); -} diff --git a/packages/@ember/-internals/views/lib/system/event_dispatcher.js b/packages/@ember/-internals/views/lib/system/event_dispatcher.js index 4cb32af5112..94c6509aae2 100644 --- a/packages/@ember/-internals/views/lib/system/event_dispatcher.js +++ b/packages/@ember/-internals/views/lib/system/event_dispatcher.js @@ -3,11 +3,9 @@ import { assert } from '@ember/debug'; import { get, set } from '@ember/-internals/metal'; import { Object as EmberObject } from '@ember/-internals/runtime'; import { getElementView } from '@ember/-internals/views'; -import { jQuery, jQueryDisabled } from './jquery'; import ActionManager from './action_manager'; -import addJQueryEventDeprecation from './jquery_event_deprecation'; import { contains } from './utils'; -import { JQUERY_INTEGRATION, MOUSE_ENTER_LEAVE_MOVE_EVENTS } from '@ember/deprecated-features'; +import { MOUSE_ENTER_LEAVE_MOVE_EVENTS } from '@ember/deprecated-features'; /** @module ember @@ -163,75 +161,47 @@ export default EmberObject.extend({ let rootElementSelector = get(this, 'rootElement'); let rootElement; - if (!JQUERY_INTEGRATION || jQueryDisabled) { - if (typeof rootElementSelector !== 'string') { - rootElement = rootElementSelector; - } else { - rootElement = document.querySelector(rootElementSelector); - } - - assert( - `You cannot use the same root element (${ - get(this, 'rootElement') || rootElement.tagName - }) multiple times in an Ember.Application`, - !rootElement.classList.contains(ROOT_ELEMENT_CLASS) - ); - assert( - 'You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', - (() => { - let target = rootElement.parentNode; - do { - if (target.classList.contains(ROOT_ELEMENT_CLASS)) { - return false; - } - - target = target.parentNode; - } while (target && target.nodeType === 1); - - return true; - })() - ); - assert( - 'You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', - !rootElement.querySelector(ROOT_ELEMENT_SELECTOR) - ); - - rootElement.classList.add(ROOT_ELEMENT_CLASS); - - assert( - `Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${ - get(this, 'rootElement') || rootElement.tagName - }). Make sure you set rootElement to the body or an element in the body.`, - rootElement.classList.contains(ROOT_ELEMENT_CLASS) - ); + if (typeof rootElementSelector !== 'string') { + rootElement = rootElementSelector; } else { - rootElement = jQuery(rootElementSelector); - assert( - `You cannot use the same root element (${ - rootElement.selector || rootElement[0].tagName - }) multiple times in an Ember.Application`, - !rootElement.is(ROOT_ELEMENT_SELECTOR) - ); - assert( - 'You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', - !rootElement.closest(ROOT_ELEMENT_SELECTOR).length - ); - assert( - 'You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', - !rootElement.find(ROOT_ELEMENT_SELECTOR).length - ); - - rootElement.addClass(ROOT_ELEMENT_CLASS); - - if (!rootElement.is(ROOT_ELEMENT_SELECTOR)) { - throw new TypeError( - `Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${ - rootElement.selector || rootElement[0].tagName - }). Make sure you set rootElement to the body or an element in the body.` - ); - } + rootElement = document.querySelector(rootElementSelector); } + assert( + `You cannot use the same root element (${ + get(this, 'rootElement') || rootElement.tagName + }) multiple times in an Ember.Application`, + !rootElement.classList.contains(ROOT_ELEMENT_CLASS) + ); + assert( + 'You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', + (() => { + let target = rootElement.parentNode; + do { + if (target.classList.contains(ROOT_ELEMENT_CLASS)) { + return false; + } + + target = target.parentNode; + } while (target && target.nodeType === 1); + + return true; + })() + ); + assert( + 'You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', + !rootElement.querySelector(ROOT_ELEMENT_SELECTOR) + ); + + rootElement.classList.add(ROOT_ELEMENT_CLASS); + + assert( + `Unable to add '${ROOT_ELEMENT_CLASS}' class to root element (${ + get(this, 'rootElement') || rootElement.tagName + }). Make sure you set rootElement to the body or an element in the body.`, + rootElement.classList.contains(ROOT_ELEMENT_CLASS) + ); + // save off the final sanitized root element (for usage in setupHandler) this._sanitizedRootElement = rootElement; @@ -290,185 +260,144 @@ export default EmberObject.extend({ return; // nothing to do } - if (!JQUERY_INTEGRATION || jQueryDisabled) { - let viewHandler = (target, event) => { - let view = getElementView(target); - let result = true; + let viewHandler = (target, event) => { + let view = getElementView(target); + let result = true; - if (view) { - result = view.handleEvent(eventName, event); - } + if (view) { + result = view.handleEvent(eventName, event); + } - return result; - }; + return result; + }; - let actionHandler = (target, event) => { - let actionId = target.getAttribute('data-ember-action'); - let actions = ActionManager.registeredActions[actionId]; + let actionHandler = (target, event) => { + let actionId = target.getAttribute('data-ember-action'); + let actions = ActionManager.registeredActions[actionId]; - // In Glimmer2 this attribute is set to an empty string and an additional - // attribute it set for each action on a given element. In this case, the - // attributes need to be read so that a proper set of action handlers can - // be coalesced. - if (actionId === '') { - let attributes = target.attributes; - let attributeCount = attributes.length; + // In Glimmer2 this attribute is set to an empty string and an additional + // attribute it set for each action on a given element. In this case, the + // attributes need to be read so that a proper set of action handlers can + // be coalesced. + if (actionId === '') { + let attributes = target.attributes; + let attributeCount = attributes.length; - actions = []; + actions = []; - for (let i = 0; i < attributeCount; i++) { - let attr = attributes.item(i); - let attrName = attr.name; + for (let i = 0; i < attributeCount; i++) { + let attr = attributes.item(i); + let attrName = attr.name; - if (attrName.indexOf('data-ember-action-') === 0) { - actions = actions.concat(ActionManager.registeredActions[attr.value]); - } + if (attrName.indexOf('data-ember-action-') === 0) { + actions = actions.concat(ActionManager.registeredActions[attr.value]); } } + } - // We have to check for actions here since in some cases, jQuery will trigger - // an event on `removeChild` (i.e. focusout) after we've already torn down the - // action handlers for the view. - if (!actions) { - return; - } + // We have to check for actions here since in some cases, jQuery will trigger + // an event on `removeChild` (i.e. focusout) after we've already torn down the + // action handlers for the view. + if (!actions) { + return; + } - let result = true; - for (let index = 0; index < actions.length; index++) { - let action = actions[index]; + let result = true; + for (let index = 0; index < actions.length; index++) { + let action = actions[index]; - if (action && action.eventName === eventName) { - // return false if any of the action handlers returns false - result = action.handler(event) && result; - } + if (action && action.eventName === eventName) { + // return false if any of the action handlers returns false + result = action.handler(event) && result; } - return result; - }; - - // Special handling of events that don't bubble (event delegation does not work). - // Mimics the way this is handled in jQuery, - // see https://github.com/jquery/jquery/blob/899c56f6ada26821e8af12d9f35fa039100e838e/src/event.js#L666-L700 - if (MOUSE_ENTER_LEAVE_MOVE_EVENTS && EVENT_MAP[event] !== undefined) { - let mappedEventType = EVENT_MAP[event]; - let origEventType = event; - - let createFakeEvent = (eventType, event) => { - let fakeEvent = document.createEvent('MouseEvent'); - fakeEvent.initMouseEvent( - eventType, - false, - false, - event.view, - event.detail, - event.screenX, - event.screenY, - event.clientX, - event.clientY, - event.ctrlKey, - event.altKey, - event.shiftKey, - event.metaKey, - event.button, - event.relatedTarget - ); - - // fake event.target as we don't dispatch the event - Object.defineProperty(fakeEvent, 'target', { value: event.target, enumerable: true }); - - return fakeEvent; - }; - - let handleMappedEvent = (this._eventHandlers[mappedEventType] = (event) => { - let target = event.target; - let related = event.relatedTarget; - - while ( - target && - target.nodeType === 1 && - (related === null || (related !== target && !contains(target, related))) - ) { - // mouseEnter/Leave don't bubble, so there is no logic to prevent it as with other events - if (getElementView(target)) { - viewHandler(target, createFakeEvent(origEventType, event)); - } else if (target.hasAttribute('data-ember-action')) { - actionHandler(target, createFakeEvent(origEventType, event)); - } + } + return result; + }; + + // Special handling of events that don't bubble (event delegation does not work). + // Mimics the way this is handled in jQuery, + // see https://github.com/jquery/jquery/blob/899c56f6ada26821e8af12d9f35fa039100e838e/src/event.js#L666-L700 + if (MOUSE_ENTER_LEAVE_MOVE_EVENTS && EVENT_MAP[event] !== undefined) { + let mappedEventType = EVENT_MAP[event]; + let origEventType = event; + + let createFakeEvent = (eventType, event) => { + let fakeEvent = document.createEvent('MouseEvent'); + fakeEvent.initMouseEvent( + eventType, + false, + false, + event.view, + event.detail, + event.screenX, + event.screenY, + event.clientX, + event.clientY, + event.ctrlKey, + event.altKey, + event.shiftKey, + event.metaKey, + event.button, + event.relatedTarget + ); - // separate mouseEnter/Leave events are dispatched for each listening element - // until the element (related) has been reached that the pointing device exited from/to - target = target.parentNode; - } - }); - - rootElement.addEventListener(mappedEventType, handleMappedEvent); - } else { - let handleEvent = (this._eventHandlers[event] = (event) => { - let target = event.target; - - do { - if (getElementView(target)) { - if (viewHandler(target, event) === false) { - event.preventDefault(); - event.stopPropagation(); - break; - } else if (event.cancelBubble === true) { - break; - } - } else if ( - typeof target.hasAttribute === 'function' && - target.hasAttribute('data-ember-action') - ) { - if (actionHandler(target, event) === false) { - break; - } - } + // fake event.target as we don't dispatch the event + Object.defineProperty(fakeEvent, 'target', { value: event.target, enumerable: true }); - target = target.parentNode; - } while (target && target.nodeType === 1); - }); + return fakeEvent; + }; - rootElement.addEventListener(event, handleEvent); - } - } else { - rootElement.on(`${event}.ember`, '.ember-view', function (evt) { - let view = getElementView(this); - let result = true; + let handleMappedEvent = (this._eventHandlers[mappedEventType] = (event) => { + let target = event.target; + let related = event.relatedTarget; + + while ( + target && + target.nodeType === 1 && + (related === null || (related !== target && !contains(target, related))) + ) { + // mouseEnter/Leave don't bubble, so there is no logic to prevent it as with other events + if (getElementView(target)) { + viewHandler(target, createFakeEvent(origEventType, event)); + } else if (target.hasAttribute('data-ember-action')) { + actionHandler(target, createFakeEvent(origEventType, event)); + } - if (view) { - result = view.handleEvent(eventName, addJQueryEventDeprecation(evt)); + // separate mouseEnter/Leave events are dispatched for each listening element + // until the element (related) has been reached that the pointing device exited from/to + target = target.parentNode; } - - return result; }); - rootElement.on(`${event}.ember`, '[data-ember-action]', (evt) => { - let attributes = evt.currentTarget.attributes; - let handledActions = []; - - evt = addJQueryEventDeprecation(evt); - - for (let i = 0; i < attributes.length; i++) { - let attr = attributes.item(i); - let attrName = attr.name; - - if (attrName.lastIndexOf('data-ember-action-', 0) !== -1) { - let action = ActionManager.registeredActions[attr.value]; - - // We have to check for action here since in some cases, jQuery will trigger - // an event on `removeChild` (i.e. focusout) after we've already torn down the - // action handlers for the view. - if (action && action.eventName === eventName && handledActions.indexOf(action) === -1) { - action.handler(evt); - // Action handlers can mutate state which in turn creates new attributes on the element. - // This effect could cause the `data-ember-action` attribute to shift down and be invoked twice. - // To avoid this, we keep track of which actions have been handled. - handledActions.push(action); + rootElement.addEventListener(mappedEventType, handleMappedEvent); + } else { + let handleEvent = (this._eventHandlers[event] = (event) => { + let target = event.target; + + do { + if (getElementView(target)) { + if (viewHandler(target, event) === false) { + event.preventDefault(); + event.stopPropagation(); + break; + } else if (event.cancelBubble === true) { + break; + } + } else if ( + typeof target.hasAttribute === 'function' && + target.hasAttribute('data-ember-action') + ) { + if (actionHandler(target, event) === false) { + break; } } - } + + target = target.parentNode; + } while (target && target.nodeType === 1); }); - } + rootElement.addEventListener(event, handleEvent); + } this.lazyEvents.delete(event); }, @@ -489,12 +418,8 @@ export default EmberObject.extend({ return; } - if (!JQUERY_INTEGRATION || jQueryDisabled) { - for (let event in this._eventHandlers) { - rootElement.removeEventListener(event, this._eventHandlers[event]); - } - } else { - jQuery(rootElementSelector).off('.ember', '**'); + for (let event in this._eventHandlers) { + rootElement.removeEventListener(event, this._eventHandlers[event]); } rootElement.classList.remove(ROOT_ELEMENT_CLASS); diff --git a/packages/@ember/-internals/views/lib/system/jquery_event_deprecation.js b/packages/@ember/-internals/views/lib/system/jquery_event_deprecation.js deleted file mode 100644 index 8d401e2f976..00000000000 --- a/packages/@ember/-internals/views/lib/system/jquery_event_deprecation.js +++ /dev/null @@ -1,64 +0,0 @@ -/* global Proxy */ -import { deprecate } from '@ember/debug'; -import { global } from '@ember/-internals/environment'; -import { DEBUG } from '@glimmer/env'; -import { JQUERY_INTEGRATION } from '@ember/deprecated-features'; - -export default function addJQueryEventDeprecation(jqEvent) { - if (DEBUG && JQUERY_INTEGRATION) { - let boundFunctions = new Map(); - - // wrap the jQuery event in a Proxy to add the deprecation message for originalEvent, according to RFC#294 - // we need a native Proxy here, so we can make sure that the internal use of originalEvent in jQuery itself does - // not trigger a deprecation - return new Proxy(jqEvent, { - get(target, name) { - switch (name) { - case 'originalEvent': - deprecate( - 'Accessing jQuery.Event specific properties is deprecated. Either use the ember-jquery-legacy addon to normalize events to native events, or explicitly opt into jQuery integration using @ember/optional-features.', - ((EmberENV) => { - // this deprecation is intentionally checking `global.EmberENV` so - // that we can ensure we _only_ deprecate in the case where jQuery - // integration is enabled implicitly (e.g. "defaulted" to enabled) - // as opposed to when the user explicitly opts in to using jQuery - if (typeof EmberENV !== 'object' || EmberENV === null) return false; - - return EmberENV._JQUERY_INTEGRATION === true; - })(global.EmberENV), - { - id: 'ember-views.event-dispatcher.jquery-event', - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_jquery-event', - for: 'ember-source', - since: { - enabled: '3.9.0', - }, - } - ); - return target[name]; - - // provide an escape hatch for ember-jquery-legacy to access originalEvent without a deprecation - case '__originalEvent': - return target.originalEvent; - - default: - if (typeof target[name] === 'function') { - // cache functions for reuse - if (!boundFunctions.has(name)) { - // for jQuery.Event methods call them with `target` as the `this` context, so they will access - // `originalEvent` from the original jQuery event, not our proxy, thus not trigger the deprecation - boundFunctions.set(name, target[name].bind(target)); - } - - return boundFunctions.get(name); - } - // same for jQuery's getter functions for simple properties - return target[name]; - } - }, - }); - } - - return jqEvent; -}