diff --git a/packages/@ember/-internals/glimmer/lib/component.ts b/packages/@ember/-internals/glimmer/lib/component.ts index c2c3db2d38c..035e2162486 100644 --- a/packages/@ember/-internals/glimmer/lib/component.ts +++ b/packages/@ember/-internals/glimmer/lib/component.ts @@ -11,7 +11,7 @@ import { ViewMixin, ViewStateSupport, } from '@ember/-internals/views'; -import { assert } from '@ember/debug'; +import { assert, deprecate } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import { DirtyableTag } from '@glimmer/reference'; import { normalizeProperty, SVG_NAMESPACE } from '@glimmer/runtime'; @@ -642,11 +642,8 @@ export const BOUNDS = symbol('BOUNDS'); * `contextMenu` * `click` * `doubleClick` - * `mouseMove` * `focusIn` * `focusOut` - * `mouseEnter` - * `mouseLeave` Form events: @@ -749,6 +746,34 @@ const Component = CoreView.extend( !eventNames.length ); } + + deprecate( + `Using \`mouseEnter\` event handler methods in components has been deprecated.`, + this.mouseEnter === undefined, + { + id: 'ember-views.event-dispatcher.mouseenter-leave-move', + until: '4.0.0', + url: 'https://emberjs.com/deprecations/v3.x#toc_component-mouseenter-leave-move', + } + ); + deprecate( + `Using \`mouseLeave\` event handler methods in components has been deprecated.`, + this.mouseLeave === undefined, + { + id: 'ember-views.event-dispatcher.mouseenter-leave-move', + until: '4.0.0', + url: 'https://emberjs.com/deprecations/v3.x#toc_component-mouseenter-leave-move', + } + ); + deprecate( + `Using \`mouseMove\` event handler methods in components has been deprecated.`, + this.mouseMove === undefined, + { + id: 'ember-views.event-dispatcher.mouseenter-leave-move', + until: '4.0.0', + url: 'https://emberjs.com/deprecations/v3.x#toc_component-mouseenter-leave-move', + } + ); }, rerender() { diff --git a/packages/@ember/-internals/glimmer/lib/modifiers/action.ts b/packages/@ember/-internals/glimmer/lib/modifiers/action.ts index 2cab05c658a..ef956ee4800 100644 --- a/packages/@ember/-internals/glimmer/lib/modifiers/action.ts +++ b/packages/@ember/-internals/glimmer/lib/modifiers/action.ts @@ -1,6 +1,6 @@ import { uuid } from '@ember/-internals/utils'; import { ActionManager, isSimpleClick } from '@ember/-internals/views'; -import { assert } from '@ember/debug'; +import { assert, deprecate } from '@ember/debug'; import { flaggedInstrument } from '@ember/instrumentation'; import { join } from '@ember/runloop'; import { Opaque, Simple } from '@glimmer/interfaces'; @@ -230,7 +230,7 @@ export default class ActionModifierManager implements ModifierManager`, }); - this.render(`{{x-foo id="outer"}}`); + expectDeprecation( + () => this.render(`{{x-foo id="outer"}}`), + /Using `mouse(Enter|Leave)` event handler methods in components has been deprecated./ + ); let parent = this.element; let outer = this.$('#outer')[0]; @@ -230,7 +233,7 @@ moduleFor( assert.strictEqual(receivedLeaveEvents[0].target, outer); } - ['@test delegated event listeners work for mouseEnter on SVG elements'](assert) { + ['@test [DEPRECATED] delegated event listeners work for mouseEnter on SVG elements'](assert) { let receivedEnterEvents = []; let receivedLeaveEvents = []; @@ -247,7 +250,10 @@ moduleFor( template: ``, }); - this.render(`{{x-foo id="outer"}}`); + expectDeprecation( + () => this.render(`{{x-foo id="outer"}}`), + /Using `mouse(Enter|Leave)` event handler methods in components has been deprecated./ + ); let parent = this.element; let outer = this.$('#outer')[0]; @@ -286,7 +292,9 @@ moduleFor( assert.strictEqual(receivedLeaveEvents[0].target, outer); } - ['@test delegated event listeners work for mouseEnter/Leave with skipped events'](assert) { + ['@test [DEPRECATED] delegated event listeners work for mouseEnter/Leave with skipped events']( + assert + ) { let receivedEnterEvents = []; let receivedLeaveEvents = []; @@ -302,7 +310,10 @@ moduleFor( template: `
`, }); - this.render(`{{x-foo id="outer"}}`); + expectDeprecation( + () => this.render(`{{x-foo id="outer"}}`), + /Using `mouse(Enter|Leave)` event handler methods in components has been deprecated./ + ); let parent = this.element; let outer = this.$('#outer')[0]; @@ -327,7 +338,7 @@ moduleFor( assert.strictEqual(receivedLeaveEvents[0].target, inner); } - ['@test delegated event listeners work for mouseEnter/Leave with skipped events and subcomponent']( + ['@test [DEPRECATED] delegated event listeners work for mouseEnter/Leave with skipped events and subcomponent']( assert ) { let receivedEnterEvents = []; @@ -350,7 +361,10 @@ moduleFor( template: ``, }); - this.render(`{{#x-outer id="outer"}}{{x-inner id="inner"}}{{/x-outer}}`); + expectDeprecation( + () => this.render(`{{#x-outer id="outer"}}{{x-inner id="inner"}}{{/x-outer}}`), + /Using `mouse(Enter|Leave)` event handler methods in components has been deprecated./ + ); let parent = this.element; let outer = this.$('#outer')[0]; @@ -375,6 +389,28 @@ moduleFor( assert.equal(receivedLeaveEvents.length, 1, 'mouseleave event was triggered'); assert.strictEqual(receivedLeaveEvents[0].target, inner); } + + ['@test [DEPRECATED] supports mouseMove events'](assert) { + let receivedEvent; + + this.registerComponent('x-foo', { + ComponentClass: Component.extend({ + mouseMove(event) { + receivedEvent = event; + }, + }), + template: `
`, + }); + + expectDeprecation( + 'Using `mouseMove` event handler methods in components has been deprecated.' + ); + + this.render(`{{x-foo}}`); + + runTask(() => this.$('#inner').trigger('mousemove')); + assert.ok(receivedEvent, 'mousemove event was triggered'); + } } ); diff --git a/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js b/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js index 50bad97f7da..74eedad04d2 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js @@ -1663,5 +1663,130 @@ moduleFor( "Element with action handler has properly updated it's conditional class" ); } + + ['@test [DEPRECATED] it should support mouseEnter events']() { + let showCalled = false; + + let ExampleComponent = Component.extend({ + actions: { + show() { + showCalled = true; + }, + }, + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '
', + }); + + expectDeprecation( + () => this.render('{{example-component id="outer"}}'), + 'Using the `{{action}}` modifier with `mouseEnter` events has been deprecated.' + ); + + let parent = this.element; + let outer = this.$('#outer')[0]; + let inner = this.$('#inner')[0]; + + runTask(() => { + this.$(outer).trigger('mouseenter', { canBubble: false, relatedTarget: parent }); + this.$(inner).trigger('mouseover', { relatedTarget: parent }); + this.$(parent).trigger('mouseout', { relatedTarget: inner }); + }); + + this.assert.ok(showCalled, 'show action was called on mouseEnter'); + } + + ['@test [DEPRECATED] it should support mouseLeave events']() { + let showCalled = false; + + let ExampleComponent = Component.extend({ + actions: { + show() { + showCalled = true; + }, + }, + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '
', + }); + + expectDeprecation( + () => this.render('{{example-component id="outer"}}'), + 'Using the `{{action}}` modifier with `mouseLeave` events has been deprecated.' + ); + + let parent = this.element; + let outer = this.$('#outer')[0]; + let inner = this.$('#inner')[0]; + + runTask(() => { + this.$(outer).trigger('mouseleave', { canBubble: false, relatedTarget: parent }); + this.$(inner).trigger('mouseout', { relatedTarget: parent }); + this.$(parent).trigger('mouseover', { relatedTarget: inner }); + }); + + this.assert.ok(showCalled, 'show action was called on mouseLeave'); + } + + ['@test [DEPRECATED] it should support mouseMove events']() { + let showCalled = false; + + let ExampleComponent = Component.extend({ + actions: { + show() { + showCalled = true; + }, + }, + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '
', + }); + + expectDeprecation( + () => this.render('{{example-component id="outer"}}'), + 'Using the `{{action}}` modifier with `mouseMove` events has been deprecated.' + ); + + runTask(() => { + this.$('#inner').trigger('mousemove'); + }); + + this.assert.ok(showCalled, 'show action was called on mouseMove'); + } + + ['@test [DEPRECATED] it should support bound mouseMove events']() { + let showCalled = false; + + let ExampleComponent = Component.extend({ + eventType: 'mouseMove', + actions: { + show() { + showCalled = true; + }, + }, + }); + + this.registerComponent('example-component', { + ComponentClass: ExampleComponent, + template: '
', + }); + + expectDeprecation( + () => this.render('{{example-component id="outer"}}'), + 'Using the `{{action}}` modifier with `mouseMove` events has been deprecated.' + ); + + runTask(() => { + this.$('#inner').trigger('mousemove'); + }); + + this.assert.ok(showCalled, 'show action was called on mouseMove'); + } } ); diff --git a/packages/@ember/-internals/views/lib/system/event_dispatcher.js b/packages/@ember/-internals/views/lib/system/event_dispatcher.js index f000a24c162..23418e6bd59 100644 --- a/packages/@ember/-internals/views/lib/system/event_dispatcher.js +++ b/packages/@ember/-internals/views/lib/system/event_dispatcher.js @@ -8,7 +8,7 @@ import jQuery, { jQueryDisabled } from './jquery'; import ActionManager from './action_manager'; import addJQueryEventDeprecation from './jquery_event_deprecation'; import { contains } from './utils'; -import { JQUERY_INTEGRATION } from '@ember/deprecated-features'; +import { JQUERY_INTEGRATION, MOUSE_ENTER_LEAVE_MOVE_EVENTS } from '@ember/deprecated-features'; /** @module ember @@ -67,35 +67,41 @@ export default EmberObject.extend({ @type Object @private */ - events: { - touchstart: 'touchStart', - touchmove: 'touchMove', - touchend: 'touchEnd', - touchcancel: 'touchCancel', - keydown: 'keyDown', - keyup: 'keyUp', - keypress: 'keyPress', - mousedown: 'mouseDown', - mouseup: 'mouseUp', - contextmenu: 'contextMenu', - click: 'click', - dblclick: 'doubleClick', - mousemove: 'mouseMove', - focusin: 'focusIn', - focusout: 'focusOut', - mouseenter: 'mouseEnter', - mouseleave: 'mouseLeave', - submit: 'submit', - input: 'input', - change: 'change', - dragstart: 'dragStart', - drag: 'drag', - dragenter: 'dragEnter', - dragleave: 'dragLeave', - dragover: 'dragOver', - drop: 'drop', - dragend: 'dragEnd', - }, + events: assign( + { + touchstart: 'touchStart', + touchmove: 'touchMove', + touchend: 'touchEnd', + touchcancel: 'touchCancel', + keydown: 'keyDown', + keyup: 'keyUp', + keypress: 'keyPress', + mousedown: 'mouseDown', + mouseup: 'mouseUp', + contextmenu: 'contextMenu', + click: 'click', + dblclick: 'doubleClick', + focusin: 'focusIn', + focusout: 'focusOut', + submit: 'submit', + input: 'input', + change: 'change', + dragstart: 'dragStart', + drag: 'drag', + dragenter: 'dragEnter', + dragleave: 'dragLeave', + dragover: 'dragOver', + drop: 'drop', + dragend: 'dragEnd', + }, + MOUSE_ENTER_LEAVE_MOVE_EVENTS + ? { + mouseenter: 'mouseEnter', + mouseleave: 'mouseLeave', + mousemove: 'mouseMove', + } + : {} + ), /** The root DOM element to which event listeners should be attached. Event @@ -300,7 +306,7 @@ export default EmberObject.extend({ // 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 (EVENT_MAP[event] !== undefined) { + if (MOUSE_ENTER_LEAVE_MOVE_EVENTS && EVENT_MAP[event] !== undefined) { let mappedEventType = EVENT_MAP[event]; let origEventType = event; diff --git a/packages/@ember/deprecated-features/index.ts b/packages/@ember/deprecated-features/index.ts index bf488ee0bf2..724ffb311f3 100644 --- a/packages/@ember/deprecated-features/index.ts +++ b/packages/@ember/deprecated-features/index.ts @@ -13,3 +13,4 @@ export const JQUERY_INTEGRATION = !!'3.9.0'; export const ALIAS_METHOD = !!'3.9.0'; export const APP_CTRL_ROUTER_PROPS = !!'3.10.0-beta.1'; export const FUNCTION_PROTOTYPE_EXTENSIONS = !!'3.11.0-beta.1'; +export const MOUSE_ENTER_LEAVE_MOVE_EVENTS = !!'3.13.0-beta.1';