diff --git a/broccoli/amd-compat-entrypoints/ember.debug.js b/broccoli/amd-compat-entrypoints/ember.debug.js index a58df23e3ac..d72d9063e8b 100644 --- a/broccoli/amd-compat-entrypoints/ember.debug.js +++ b/broccoli/amd-compat-entrypoints/ember.debug.js @@ -56,12 +56,6 @@ d('@ember/-internals/runtime/index', emberinternalsRuntimeIndex); import * as emberinternalsRuntimeLibExtRsvp from '@ember/-internals/runtime/lib/ext/rsvp'; d('@ember/-internals/runtime/lib/ext/rsvp', emberinternalsRuntimeLibExtRsvp); -import * as emberinternalsRuntimeLibMixinsActionHandler from '@ember/-internals/runtime/lib/mixins/action_handler'; -d( - '@ember/-internals/runtime/lib/mixins/action_handler', - emberinternalsRuntimeLibMixinsActionHandler -); - import * as emberinternalsRuntimeLibMixinsContainerProxy from '@ember/-internals/runtime/lib/mixins/container_proxy'; d( '@ember/-internals/runtime/lib/mixins/container_proxy', @@ -74,12 +68,6 @@ d( emberinternalsRuntimeLibMixinsRegistryProxy ); -import * as emberinternalsRuntimeLibMixinsTargetActionSupport from '@ember/-internals/runtime/lib/mixins/target_action_support'; -d( - '@ember/-internals/runtime/lib/mixins/target_action_support', - emberinternalsRuntimeLibMixinsTargetActionSupport -); - import * as emberinternalsStringIndex from '@ember/-internals/string/index'; d('@ember/-internals/string/index', emberinternalsStringIndex); @@ -104,9 +92,6 @@ d( import * as emberinternalsViewsLibComponentLookup from '@ember/-internals/views/lib/component_lookup'; d('@ember/-internals/views/lib/component_lookup', emberinternalsViewsLibComponentLookup); -import * as emberinternalsViewsLibMixinsActionSupport from '@ember/-internals/views/lib/mixins/action_support'; -d('@ember/-internals/views/lib/mixins/action_support', emberinternalsViewsLibMixinsActionSupport); - import * as emberinternalsViewsLibSystemActionManager from '@ember/-internals/views/lib/system/action_manager'; d('@ember/-internals/views/lib/system/action_manager', emberinternalsViewsLibSystemActionManager); diff --git a/package.json b/package.json index 8c1bb1a3748..545a356f204 100644 --- a/package.json +++ b/package.json @@ -203,10 +203,8 @@ "@ember/-internals/routing/index.js": "ember-source/@ember/-internals/routing/index.js", "@ember/-internals/runtime/index.js": "ember-source/@ember/-internals/runtime/index.js", "@ember/-internals/runtime/lib/ext/rsvp.js": "ember-source/@ember/-internals/runtime/lib/ext/rsvp.js", - "@ember/-internals/runtime/lib/mixins/action_handler.js": "ember-source/@ember/-internals/runtime/lib/mixins/action_handler.js", "@ember/-internals/runtime/lib/mixins/container_proxy.js": "ember-source/@ember/-internals/runtime/lib/mixins/container_proxy.js", "@ember/-internals/runtime/lib/mixins/registry_proxy.js": "ember-source/@ember/-internals/runtime/lib/mixins/registry_proxy.js", - "@ember/-internals/runtime/lib/mixins/target_action_support.js": "ember-source/@ember/-internals/runtime/lib/mixins/target_action_support.js", "@ember/-internals/string/index.js": "ember-source/@ember/-internals/string/index.js", "@ember/-internals/utility-types/index.js": "ember-source/@ember/-internals/utility-types/index.js", "@ember/-internals/utils/index.js": "ember-source/@ember/-internals/utils/index.js", @@ -214,7 +212,6 @@ "@ember/-internals/views/lib/compat/attrs.js": "ember-source/@ember/-internals/views/lib/compat/attrs.js", "@ember/-internals/views/lib/compat/fallback-view-registry.js": "ember-source/@ember/-internals/views/lib/compat/fallback-view-registry.js", "@ember/-internals/views/lib/component_lookup.js": "ember-source/@ember/-internals/views/lib/component_lookup.js", - "@ember/-internals/views/lib/mixins/action_support.js": "ember-source/@ember/-internals/views/lib/mixins/action_support.js", "@ember/-internals/views/lib/system/action_manager.js": "ember-source/@ember/-internals/views/lib/system/action_manager.js", "@ember/-internals/views/lib/system/event_dispatcher.js": "ember-source/@ember/-internals/views/lib/system/event_dispatcher.js", "@ember/-internals/views/lib/system/utils.js": "ember-source/@ember/-internals/views/lib/system/utils.js", diff --git a/packages/@ember/-internals/glimmer/lib/component-managers/curly.ts b/packages/@ember/-internals/glimmer/lib/component-managers/curly.ts index 0b0da6ec97d..1f4edaf029d 100644 --- a/packages/@ember/-internals/glimmer/lib/component-managers/curly.ts +++ b/packages/@ember/-internals/glimmer/lib/component-managers/curly.ts @@ -239,7 +239,7 @@ export default class CurlyComponentManager /* * This hook is responsible for actually instantiating the component instance. * It also is where we perform additional bookkeeping to support legacy - * features like exposed by view mixins like ChildViewSupport, ActionSupport, + * features like exposed by view mixins like ChildViewSupport, * etc. */ create( diff --git a/packages/@ember/-internals/glimmer/lib/component.ts b/packages/@ember/-internals/glimmer/lib/component.ts index 5531d9c5e2f..86b1e748071 100644 --- a/packages/@ember/-internals/glimmer/lib/component.ts +++ b/packages/@ember/-internals/glimmer/lib/component.ts @@ -7,10 +7,8 @@ import { } from '@ember/-internals/metal'; import type { PropertyDidChange } from '@ember/-internals/metal/lib/property_events'; import { getOwner } from '@ember/-internals/owner'; -import { TargetActionSupport } from '@ember/-internals/runtime'; import type { ViewStates } from '@ember/-internals/views'; import { - ActionSupport, addChildView, CoreView, EventDispatcher, @@ -789,22 +787,14 @@ declare const SIGNATURE: unique symbol; @class Component @extends Ember.CoreView - @uses Ember.TargetActionSupport - @uses Ember.ActionSupport @public */ // This type param is used in the class, so must appear here. // eslint-disable-next-line @typescript-eslint/no-unused-vars -interface Component - extends CoreView, - TargetActionSupport, - ActionSupport, - ComponentMethods {} +interface Component extends CoreView, ComponentMethods {} class Component extends CoreView.extend( - TargetActionSupport, - ActionSupport, { // These need to be overridable via extend/create but should still // have a default. Defining them here is the best way to achieve that. diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/target-action-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/target-action-test.js deleted file mode 100644 index 628beffa8f8..00000000000 --- a/packages/@ember/-internals/glimmer/tests/integration/components/target-action-test.js +++ /dev/null @@ -1,194 +0,0 @@ -import { moduleFor, RenderingTestCase, runTask } from 'internal-test-helpers'; - -import { action, set } from '@ember/object'; -import Mixin from '@ember/object/mixin'; -import Controller from '@ember/controller'; -import EmberObject from '@ember/object'; - -import { Component } from '../../utils/helpers'; - -moduleFor( - 'Components test: send', - class extends RenderingTestCase { - ['@test sending to undefined actions triggers an error'](assert) { - assert.expect(2); - - let component; - - this.registerComponent('foo-bar', { - ComponentClass: class extends Component { - init() { - super.init(); - component = this; - } - - @action - foo(message) { - assert.equal('bar', message); - } - }, - }); - - this.render('{{foo-bar}}'); - - runTask(() => component.send('foo', 'bar')); - - expectAssertion(() => { - return component.send('baz', 'bar'); - }, /had no action handler for: baz/); - } - - ['@test `send` will call send from a target if it is defined']() { - let component; - let target = { - send: (message, payload) => { - this.assert.equal('foo', message); - this.assert.equal('baz', payload); - }, - }; - - this.registerComponent('foo-bar', { - ComponentClass: class extends Component { - init() { - super.init(...arguments); - component = this; - } - target = target; - }, - }); - - this.render('{{foo-bar}}'); - - runTask(() => component.send('foo', 'baz')); - } - - ['@test a handled action can be bubbled to the target for continued processing']() { - this.assert.expect(2); - - let component; - - this.registerComponent('foo-bar', { - ComponentClass: Component.extend({ - init() { - this._super(...arguments); - component = this; - }, - actions: { - poke: () => { - this.assert.ok(true, 'component action called'); - return true; - }, - }, - target: Controller.extend({ - actions: { - poke: () => { - this.assert.ok(true, 'action bubbled to controller'); - }, - }, - }).create(), - }), - }); - - this.render('{{foo-bar poke="poke"}}'); - - runTask(() => component.send('poke')); - } - - ["@test action can be handled by a superclass' actions object"](assert) { - this.assert.expect(4); - - let component; - - let SuperComponent = class extends Component { - @action - foo() { - assert.ok(true, 'foo'); - } - - @action - bar(msg) { - assert.equal(msg, 'HELLO'); - } - }; - - let BarViewMixin = Mixin.create({ - actions: { - bar(msg) { - assert.equal(msg, 'HELLO'); - this._super(msg); - }, - }, - }); - - this.registerComponent('x-index', { - ComponentClass: class extends SuperComponent.extend(BarViewMixin) { - init() { - super.init(...arguments); - component = this; - } - - @action - baz() { - assert.ok(true, 'baz'); - } - }, - }); - - this.render('{{x-index}}'); - - runTask(() => { - component.send('foo'); - component.send('bar', 'HELLO'); - component.send('baz'); - }); - } - - ['@test actions cannot be provided at create time'](assert) { - this.registerComponent('foo-bar', class extends Component {}); - let ComponentFactory = this.owner.factoryFor('component:foo-bar'); - - expectAssertion(() => { - ComponentFactory.create({ - actions: { - foo() { - assert.ok(true, 'foo'); - }, - }, - }); - }, /`actions` must be provided at extend time, not at create time/); - // but should be OK on an object that doesn't mix in Ember.ActionHandler - EmberObject.create({ - actions: ['foo'], - }); - } - - ['@test asserts if called on a destroyed component']() { - let component; - - this.registerComponent('rip-alley', { - ComponentClass: class extends Component { - init() { - super.init(...arguments); - component = this; - } - - toString() { - return 'component:rip-alley'; - } - }, - }); - - this.render('{{#if this.shouldRender}}{{rip-alley}}{{/if}}', { - shouldRender: true, - }); - - runTask(() => { - set(this.context, 'shouldRender', false); - }); - - expectAssertion(() => { - component.send('trigger-me-dead'); - }, "Attempted to call .send() with the action 'trigger-me-dead' on the destroyed object 'component:rip-alley'."); - } - } -); diff --git a/packages/@ember/-internals/runtime/index.ts b/packages/@ember/-internals/runtime/index.ts index 5ebfca3fa2a..c60cf8c9ccc 100644 --- a/packages/@ember/-internals/runtime/index.ts +++ b/packages/@ember/-internals/runtime/index.ts @@ -1,7 +1,5 @@ export { default as RegistryProxyMixin } from './lib/mixins/registry_proxy'; export { default as ContainerProxyMixin } from './lib/mixins/container_proxy'; -export { default as ActionHandler } from './lib/mixins/action_handler'; export { default as MutableEnumerable } from '@ember/enumerable/mutable'; -export { default as TargetActionSupport } from './lib/mixins/target_action_support'; export { default as RSVP, onerrorDefault } from './lib/ext/rsvp'; // just for side effect of extending Ember.RSVP diff --git a/packages/@ember/-internals/runtime/lib/mixins/action_handler.ts b/packages/@ember/-internals/runtime/lib/mixins/action_handler.ts deleted file mode 100644 index 29c13f32c7c..00000000000 --- a/packages/@ember/-internals/runtime/lib/mixins/action_handler.ts +++ /dev/null @@ -1,227 +0,0 @@ -/** -@module ember -*/ - -import Mixin from '@ember/object/mixin'; -import { get } from '@ember/-internals/metal'; -import { assert } from '@ember/debug'; - -/** - `Ember.ActionHandler` is available on some familiar classes including - `Route`, `Component`, and `Controller`. - (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, - and `Route` and available to the above classes through - inheritance.) - - @class ActionHandler - @namespace Ember - @private -*/ -interface ActionHandler { - actions?: Record unknown>; - send(actionName: string, ...args: unknown[]): void; -} -const ActionHandler = Mixin.create({ - mergedProperties: ['actions'], - - /** - The collection of functions, keyed by name, available on this - `ActionHandler` as action targets. - - These functions will be invoked when a matching `{{action}}` is triggered - from within a template and the application's current route is this route. - - Actions can also be invoked from other parts of your application - via `ActionHandler#send`. - - The `actions` hash will inherit action handlers from - the `actions` hash defined on extended parent classes - or mixins rather than just replace the entire hash, e.g.: - - ```app/mixins/can-display-banner.js - import Mixin from '@ember/object/mixin'; - - export default Mixin.create({ - actions: { - displayBanner(msg) { - // ... - } - } - }); - ``` - - ```app/routes/welcome.js - import Route from '@ember/routing/route'; - import CanDisplayBanner from '../mixins/can-display-banner'; - - export default Route.extend(CanDisplayBanner, { - actions: { - playMusic() { - // ... - } - } - }); - - // `WelcomeRoute`, when active, will be able to respond - // to both actions, since the actions hash is merged rather - // then replaced when extending mixins / parent classes. - this.send('displayBanner'); - this.send('playMusic'); - ``` - - Within a Controller, Route or Component's action handler, - the value of the `this` context is the Controller, Route or - Component object: - - ```app/routes/song.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - myAction() { - this.controllerFor("song"); - this.transitionTo("other.route"); - ... - } - } - }); - ``` - - It is also possible to call `this._super(...arguments)` from within an - action handler if it overrides a handler defined on a parent - class or mixin: - - Take for example the following routes: - - ```app/mixins/debug-route.js - import Mixin from '@ember/object/mixin'; - - export default Mixin.create({ - actions: { - debugRouteInformation() { - console.debug("It's a-me, console.debug!"); - } - } - }); - ``` - - ```app/routes/annoying-debug.js - import Route from '@ember/routing/route'; - import DebugRoute from '../mixins/debug-route'; - - export default Route.extend(DebugRoute, { - actions: { - debugRouteInformation() { - // also call the debugRouteInformation of mixed in DebugRoute - this._super(...arguments); - - // show additional annoyance - window.alert(...); - } - } - }); - ``` - - ## Bubbling - - By default, an action will stop bubbling once a handler defined - on the `actions` hash handles it. To continue bubbling the action, - you must return `true` from the handler: - - ```app/router.js - Router.map(function() { - this.route("album", function() { - this.route("song"); - }); - }); - ``` - - ```app/routes/album.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - startPlaying: function() { - } - } - }); - ``` - - ```app/routes/album-song.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - startPlaying() { - // ... - - if (actionShouldAlsoBeTriggeredOnParentRoute) { - return true; - } - } - } - }); - ``` - - @property actions - @type Object - @default null - @public - */ - - /** - Triggers a named action on the `ActionHandler`. Any parameters - supplied after the `actionName` string will be passed as arguments - to the action target function. - - If the `ActionHandler` has its `target` property set, actions may - bubble to the `target`. Bubbling happens when an `actionName` can - not be found in the `ActionHandler`'s `actions` hash or if the - action target function returns `true`. - - Example - - ```app/routes/welcome.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - playTheme() { - this.send('playMusic', 'theme.mp3'); - }, - playMusic(track) { - // ... - } - } - }); - ``` - - @method send - @param {String} actionName The action to trigger - @param {*} context a context to send with the action - @public - */ - send(actionName: string, ...args: any[]) { - assert( - `Attempted to call .send() with the action '${actionName}' on the destroyed object '${this}'.`, - !this.isDestroying && !this.isDestroyed - ); - if (this.actions && this.actions[actionName]) { - let shouldBubble = this.actions[actionName].apply(this, args) === true; - if (!shouldBubble) { - return; - } - } - - let target = get(this, 'target'); - if (target) { - assert( - `The \`target\` for ${this} (${target}) does not have a \`send\` method`, - typeof target.send === 'function' - ); - target.send(...arguments); - } - }, -}); - -export default ActionHandler; diff --git a/packages/@ember/-internals/runtime/lib/mixins/target_action_support.ts b/packages/@ember/-internals/runtime/lib/mixins/target_action_support.ts deleted file mode 100644 index e4448ab7392..00000000000 --- a/packages/@ember/-internals/runtime/lib/mixins/target_action_support.ts +++ /dev/null @@ -1,176 +0,0 @@ -/** -@module ember -*/ - -import { context } from '@ember/-internals/environment'; -import { get, computed } from '@ember/-internals/metal'; -import Mixin from '@ember/object/mixin'; -import { assert } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; - -/** -`Ember.TargetActionSupport` is a mixin that can be included in a class -to add a `triggerAction` method with semantics similar to the Handlebars -`{{action}}` helper. In normal Ember usage, the `{{action}}` helper is -usually the best choice. This mixin is most often useful when you are -doing more complex event handling in Components. - -@class TargetActionSupport -@namespace Ember -@extends Mixin -@private -*/ -interface TargetActionSupport { - target: unknown; - action: string | null; - actionContext: unknown; - actionContextObject: unknown; - triggerAction(opts?: object): unknown; - - /** @internal */ - _target?: unknown; -} -const TargetActionSupport = Mixin.create({ - target: null, - action: null, - actionContext: null, - - actionContextObject: computed('actionContext', function () { - let actionContext = get(this, 'actionContext'); - - if (typeof actionContext === 'string') { - let value = get(this, actionContext); - if (value === undefined) { - value = get(context.lookup, actionContext); - } - return value; - } else { - return actionContext; - } - }), - - /** - Send an `action` with an `actionContext` to a `target`. The action, actionContext - and target will be retrieved from properties of the object. For example: - - ```javascript - import { alias } from '@ember/object/computed'; - - App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { - target: alias('controller'), - action: 'save', - actionContext: alias('context'), - click() { - this.triggerAction(); // Sends the `save` action, along with the current context - // to the current controller - } - }); - ``` - - The `target`, `action`, and `actionContext` can be provided as properties of - an optional object argument to `triggerAction` as well. - - ```javascript - App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { - click() { - this.triggerAction({ - action: 'save', - target: this.get('controller'), - actionContext: this.get('context') - }); // Sends the `save` action, along with the current context - // to the current controller - } - }); - ``` - - The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. - But `target` and `action` must be specified either as properties or with the argument - to `triggerAction`, or a combination: - - ```javascript - import { alias } from '@ember/object/computed'; - - App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { - target: alias('controller'), - click() { - this.triggerAction({ - action: 'save' - }); // Sends the `save` action, along with a reference to `this`, - // to the current controller - } - }); - ``` - - @method triggerAction - @param opts {Object} (optional, with the optional keys action, target and/or actionContext) - @return {Boolean} true if the action was sent successfully and did not return false - @private - */ - triggerAction(opts: { action?: string; target?: unknown; actionContext?: unknown } = {}) { - let { action, target, actionContext } = opts; - action = action || get(this, 'action'); - target = target || getTarget(this); - - if (actionContext === undefined) { - actionContext = get(this, 'actionContextObject') || this; - } - - let context = Array.isArray(actionContext) ? actionContext : [actionContext]; - - if (target && action) { - let ret; - - if (isSendable(target)) { - ret = target.send(action, ...context); - } else { - assert( - `The action '${action}' did not exist on ${target}`, - typeof (target as any)[action] === 'function' - ); - ret = (target as any)[action](...context); - } - - if (ret !== false) { - return true; - } - } - - return false; - }, -}); - -interface Sendable { - send(action: string, ...context: unknown[]): unknown; -} - -function isSendable(obj: unknown): obj is Sendable { - return obj != null && typeof obj === 'object' && typeof (obj as Sendable).send === 'function'; -} - -function getTarget(instance: TargetActionSupport) { - let target = get(instance, 'target'); - if (target) { - if (typeof target === 'string') { - let value = get(instance, target); - if (value === undefined) { - value = get(context.lookup, target); - } - - return value; - } else { - return target; - } - } - - if (instance._target) { - return instance._target; - } - - return null; -} - -if (DEBUG) { - Object.seal(TargetActionSupport); -} - -export default TargetActionSupport; diff --git a/packages/@ember/-internals/runtime/tests/mixins/target_action_support_test.js b/packages/@ember/-internals/runtime/tests/mixins/target_action_support_test.js deleted file mode 100644 index be9eb69ea7b..00000000000 --- a/packages/@ember/-internals/runtime/tests/mixins/target_action_support_test.js +++ /dev/null @@ -1,211 +0,0 @@ -import { context } from '@ember/-internals/environment'; -import EmberObject from '@ember/object'; -import TargetActionSupport from '../../lib/mixins/target_action_support'; -import { moduleFor, AbstractTestCase } from 'internal-test-helpers'; - -let originalLookup = context.lookup; -let lookup; - -moduleFor( - 'TargetActionSupport', - class extends AbstractTestCase { - beforeEach() { - context.lookup = lookup = {}; - } - - afterEach() { - context.lookup = originalLookup; - } - - ['@test it should return false if no target or action are specified'](assert) { - assert.expect(1); - - let obj = EmberObject.extend(TargetActionSupport).create(); - - assert.ok(false === obj.triggerAction(), 'no target or action was specified'); - } - - ['@test it should support actions specified as strings'](assert) { - assert.expect(2); - - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent() { - assert.ok(true, 'anEvent method was called'); - }, - }), - - action: 'anEvent', - }); - - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); - } - - ['@test it should invoke the send() method on objects that implement it'](assert) { - assert.expect(3); - - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - send(evt, context) { - assert.equal(evt, 'anEvent', 'send() method was invoked with correct event name'); - assert.equal(context, obj, 'send() method was invoked with correct context'); - }, - }), - - action: 'anEvent', - }); - - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); - } - - ['@test it should find targets specified using a property path'](assert) { - assert.expect(2); - - let Test = {}; - lookup.Test = Test; - - Test.targetObj = EmberObject.create({ - anEvent() { - assert.ok(true, 'anEvent method was called on global object'); - }, - }); - - let myObj = EmberObject.extend(TargetActionSupport).create({ - target: 'Test.targetObj', - action: 'anEvent', - }); - - assert.ok(true === myObj.triggerAction(), 'a valid target and action were specified'); - } - - ['@test it should use an actionContext object specified as a property on the object'](assert) { - assert.expect(2); - let obj = EmberObject.extend(TargetActionSupport).create({ - action: 'anEvent', - actionContext: {}, - target: EmberObject.create({ - anEvent(ctx) { - assert.ok( - obj.actionContext === ctx, - 'anEvent method was called with the expected context' - ); - }, - }), - }); - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); - } - - ['@test it should find an actionContext specified as a property path'](assert) { - assert.expect(2); - - let Test = {}; - lookup.Test = Test; - Test.aContext = {}; - - let obj = EmberObject.extend(TargetActionSupport).create({ - action: 'anEvent', - actionContext: 'Test.aContext', - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(Test.aContext === ctx, 'anEvent method was called with the expected context'); - }, - }), - }); - - assert.ok(true === obj.triggerAction(), 'a valid target and action were specified'); - } - - ['@test it should use the target specified in the argument'](assert) { - assert.expect(2); - let targetObj = EmberObject.create({ - anEvent() { - assert.ok(true, 'anEvent method was called'); - }, - }); - let obj = EmberObject.extend(TargetActionSupport).create({ - action: 'anEvent', - }); - - assert.ok( - true === obj.triggerAction({ target: targetObj }), - 'a valid target and action were specified' - ); - } - - ['@test it should use the action specified in the argument'](assert) { - assert.expect(2); - - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent() { - assert.ok(true, 'anEvent method was called'); - }, - }), - }); - assert.ok( - true === obj.triggerAction({ action: 'anEvent' }), - 'a valid target and action were specified' - ); - } - - ['@test it should use the actionContext specified in the argument'](assert) { - assert.expect(2); - let context = {}; - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(context === ctx, 'anEvent method was called with the expected context'); - }, - }), - action: 'anEvent', - }); - - assert.ok( - true === obj.triggerAction({ actionContext: context }), - 'a valid target and action were specified' - ); - } - - ['@test it should allow multiple arguments from actionContext'](assert) { - assert.expect(3); - let param1 = 'someParam'; - let param2 = 'someOtherParam'; - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent(first, second) { - assert.ok( - first === param1, - 'anEvent method was called with the expected first argument' - ); - assert.ok( - second === param2, - 'anEvent method was called with the expected second argument' - ); - }, - }), - action: 'anEvent', - }); - - assert.ok( - true === obj.triggerAction({ actionContext: [param1, param2] }), - 'a valid target and action were specified' - ); - } - - ['@test it should use a null value specified in the actionContext argument'](assert) { - assert.expect(2); - let obj = EmberObject.extend(TargetActionSupport).create({ - target: EmberObject.create({ - anEvent(ctx) { - assert.ok(null === ctx, 'anEvent method was called with the expected context (null)'); - }, - }), - action: 'anEvent', - }); - assert.ok( - true === obj.triggerAction({ actionContext: null }), - 'a valid target and action were specified' - ); - } - } -); diff --git a/packages/@ember/-internals/views/index.ts b/packages/@ember/-internals/views/index.ts index 71a23252628..35e90736704 100644 --- a/packages/@ember/-internals/views/index.ts +++ b/packages/@ember/-internals/views/index.ts @@ -18,7 +18,6 @@ export { export { default as EventDispatcher } from './lib/system/event_dispatcher'; export { default as ComponentLookup } from './lib/component_lookup'; export { default as CoreView } from './lib/views/core_view'; -export { default as ActionSupport } from './lib/mixins/action_support'; export { MUTABLE_CELL } from './lib/compat/attrs'; export { default as ActionManager } from './lib/system/action_manager'; export { default as ViewStates } from './lib/views/states'; diff --git a/packages/@ember/-internals/views/lib/mixins/action_support.ts b/packages/@ember/-internals/views/lib/mixins/action_support.ts deleted file mode 100644 index f7d79862587..00000000000 --- a/packages/@ember/-internals/views/lib/mixins/action_support.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - @module ember -*/ -import { get } from '@ember/-internals/metal'; -import Mixin from '@ember/object/mixin'; -import { assert, inspect } from '@ember/debug'; - -/** - @class ActionSupport - @namespace Ember - @private -*/ -interface ActionSupport { - send(actionName: string, ...args: unknown[]): void; -} -const ActionSupport = Mixin.create({ - send(actionName: string, ...args: unknown[]) { - assert( - `Attempted to call .send() with the action '${actionName}' on the destroyed object '${this}'.`, - !this.isDestroying && !this.isDestroyed - ); - - let action = this.actions && this.actions[actionName]; - - if (action) { - let shouldBubble = action.apply(this, args) === true; - if (!shouldBubble) { - return; - } - } - - let target = get(this, 'target'); - if (target) { - assert( - `The \`target\` for ${this} (${target}) does not have a \`send\` method`, - typeof target.send === 'function' - ); - target.send(...arguments); - } else { - assert(`${inspect(this)} had no action handler for: ${actionName}`, action); - } - }, -}); - -export default ActionSupport; diff --git a/packages/@ember/-internals/views/lib/views/core_view.ts b/packages/@ember/-internals/views/lib/views/core_view.ts index 671bb20b2ce..899101871a9 100644 --- a/packages/@ember/-internals/views/lib/views/core_view.ts +++ b/packages/@ember/-internals/views/lib/views/core_view.ts @@ -1,6 +1,5 @@ import type { Renderer, View } from '@ember/-internals/glimmer/lib/renderer'; import { inject } from '@ember/-internals/metal'; -import { ActionHandler } from '@ember/-internals/runtime'; import { FrameworkObject } from '@ember/object/-internals'; import type { ViewState } from './states'; import states from './states'; @@ -17,12 +16,12 @@ import states from './states'; @namespace Ember @extends EmberObject @deprecated Use `Component` instead. - @uses Ember.ActionHandler @private */ -interface CoreView extends ActionHandler, View {} -class CoreView extends FrameworkObject.extend(ActionHandler) { +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +interface CoreView extends View {} +class CoreView extends FrameworkObject { isView = true; declare _states: typeof states; diff --git a/packages/@ember/controller/index.ts b/packages/@ember/controller/index.ts index 711b6d634cd..38575db7073 100644 --- a/packages/@ember/controller/index.ts +++ b/packages/@ember/controller/index.ts @@ -5,7 +5,6 @@ import { inject as metalInject } from '@ember/-internals/metal'; import type { DecoratorPropertyDescriptor, ElementDescriptor } from '@ember/-internals/metal'; import Mixin from '@ember/object/mixin'; import type { RouteArgs } from '@ember/routing/-internals'; -import { ActionHandler } from '@ember/-internals/runtime'; import { symbol } from '@ember/-internals/utils'; import type { Transition } from 'router_js'; @@ -24,10 +23,9 @@ const MODEL = symbol('MODEL'); /** @class ControllerMixin @namespace Ember - @uses Ember.ActionHandler @private */ -interface ControllerMixin extends ActionHandler { +interface ControllerMixin { /** @internal */ _qpDelegate: unknown | null; @@ -230,7 +228,10 @@ interface ControllerMixin extends ActionHandler { */ replaceRoute(...args: RouteArgs): Transition; } -const ControllerMixin = Mixin.create(ActionHandler, { +const ControllerMixin = Mixin.create({ + // Support the action hash which is still used internally + mergedProperties: ['actions'], + /* ducktype as a controller */ isController: true, diff --git a/packages/@ember/controller/tests/controller_test.js b/packages/@ember/controller/tests/controller_test.js index 62778cec084..e7d4a6f0b51 100644 --- a/packages/@ember/controller/tests/controller_test.js +++ b/packages/@ember/controller/tests/controller_test.js @@ -1,8 +1,6 @@ import Controller, { inject as injectController } from '@ember/controller'; import Service, { service } from '@ember/service'; import EmberObject, { get } from '@ember/object'; -import Mixin from '@ember/object/mixin'; -import { setOwner } from '@ember/-internals/owner'; import { runDestroy, buildOwner } from 'internal-test-helpers'; import { moduleFor, ApplicationTestCase, AbstractTestCase, runTask } from 'internal-test-helpers'; import { action } from '@ember/object'; @@ -69,113 +67,6 @@ moduleFor( } ); -moduleFor( - 'Controller event handling', - class extends AbstractTestCase { - ['@test Action can be handled by a function on actions object'](assert) { - assert.expect(1); - let TestController = Controller.extend({ - actions: { - poke() { - assert.ok(true, 'poked'); - }, - }, - }); - let controller = TestController.create(); - controller.send('poke'); - } - - ['@test A handled action can be bubbled to the target for continued processing'](assert) { - assert.expect(2); - let owner = buildOwner(); - - let TestController = Controller.extend({ - actions: { - poke() { - assert.ok(true, 'poked 1'); - return true; - }, - }, - }); - - owner.register('controller:index', TestController); - - let controller = TestController.create({ - target: Controller.extend({ - actions: { - poke() { - assert.ok(true, 'poked 2'); - }, - }, - }).create(), - }); - - setOwner(controller, owner); - - controller.send('poke'); - - runDestroy(owner); - } - - ["@test Action can be handled by a superclass' actions object"](assert) { - assert.expect(4); - - let SuperController = Controller.extend({ - actions: { - foo() { - assert.ok(true, 'foo'); - }, - bar(msg) { - assert.equal(msg, 'HELLO'); - }, - }, - }); - - let BarControllerMixin = Mixin.create({ - actions: { - bar(msg) { - assert.equal(msg, 'HELLO'); - this._super(msg); - }, - }, - }); - - let IndexController = SuperController.extend(BarControllerMixin, { - actions: { - baz() { - assert.ok(true, 'baz'); - }, - }, - }); - - let controller = IndexController.create({}); - controller.send('foo'); - controller.send('bar', 'HELLO'); - controller.send('baz'); - } - - ['@test .send asserts if called on a destroyed controller']() { - let owner = buildOwner(); - - owner.register( - 'controller:application', - class extends Controller { - toString() { - return 'controller:rip-alley'; - } - } - ); - - let controller = owner.lookup('controller:application'); - runDestroy(owner); - - expectAssertion(() => { - controller.send('trigger-me-dead'); - }, "Attempted to call .send() with the action 'trigger-me-dead' on the destroyed object 'controller:rip-alley'."); - } - } -); - moduleFor( 'Controller deprecations -> Controller Content -> Model Alias', class extends AbstractTestCase { diff --git a/packages/@ember/object/core.ts b/packages/@ember/object/core.ts index 106169e3ef8..e3b88c02819 100644 --- a/packages/@ember/object/core.ts +++ b/packages/@ember/object/core.ts @@ -18,7 +18,6 @@ import { hasUnknownProperty, } from '@ember/-internals/metal'; import Mixin, { applyMixin } from '@ember/object/mixin'; -import { ActionHandler } from '@ember/-internals/runtime'; import makeArray from '@ember/array/make'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -105,11 +104,6 @@ function initialize(obj: CoreObject, properties?: unknown) { 'EmberObject.create no longer supports defining methods that call _super.', !(typeof value === 'function' && value.toString().indexOf('._super') !== -1) ); - assert( - '`actions` must be provided at extend time, not at create time, ' + - 'when Ember.ActionHandler is used (i.e. views, controllers & routes).', - !(keyName === 'actions' && ActionHandler.detect(obj)) - ); let possibleDesc = descriptorForProperty(obj, keyName, m); let isDescriptor = possibleDesc !== undefined; diff --git a/packages/@ember/routing/route.ts b/packages/@ember/routing/route.ts index d3ba373508f..eda2b06991b 100644 --- a/packages/@ember/routing/route.ts +++ b/packages/@ember/routing/route.ts @@ -10,7 +10,6 @@ import { getOwner } from '@ember/-internals/owner'; import type { default as BucketCache } from './lib/cache'; import EmberObject, { computed, get, set, getProperties, setProperties } from '@ember/object'; import { A as emberA } from '@ember/array'; -import { ActionHandler } from '@ember/-internals/runtime'; import { typeOf } from '@ember/utils'; import { lookupDescriptor } from '@ember/-internals/utils'; import type { AnyFn } from '@ember/-internals/utility-types'; @@ -72,11 +71,10 @@ const RENDER_STATE = Symbol('render-state'); @class Route @extends EmberObject - @uses ActionHandler @since 1.0.0 @public */ -interface Route extends IRoute, ActionHandler { +interface Route extends IRoute { /** The `willTransition` action is fired at the beginning of any attempted transition with a `Transition` object as the sole @@ -250,7 +248,7 @@ interface Route extends IRoute, ActionHandler { error?(error: Error, transition: Transition): boolean | void; } -class Route extends EmberObject.extend(ActionHandler) implements IRoute { +class Route extends EmberObject implements IRoute { static isRouteFactory = true; // These properties will end up appearing in the public interface because we diff --git a/packages/ember/barrel.ts b/packages/ember/barrel.ts index fb685374322..bde1c6bee1c 100644 --- a/packages/ember/barrel.ts +++ b/packages/ember/barrel.ts @@ -44,12 +44,7 @@ import { sendEvent as emberSendEvent, } from '@ember/object/events'; -import { - RegistryProxyMixin, - ContainerProxyMixin, - RSVP as _RSVP, - ActionHandler as InternalActionHandler, -} from '@ember/-internals/runtime'; +import { RegistryProxyMixin, ContainerProxyMixin, RSVP as _RSVP } from '@ember/-internals/runtime'; import { componentCapabilities, modifierCapabilities, @@ -180,8 +175,6 @@ namespace Ember { // ****@ember/-internals/runtime**** export const _ContainerProxyMixin = ContainerProxyMixin; export const _RegistryProxyMixin = RegistryProxyMixin; - export const ActionHandler = InternalActionHandler; - export type ActionHandler = InternalActionHandler; // ****@ember/-internals/view**** export const ComponentLookup = views.ComponentLookup; diff --git a/packages/ember/tests/reexports_test.js b/packages/ember/tests/reexports_test.js index a293af7aa95..4248766c8fa 100644 --- a/packages/ember/tests/reexports_test.js +++ b/packages/ember/tests/reexports_test.js @@ -333,7 +333,6 @@ let allExports = [ ['_Input', '@ember/-internals/glimmer', 'Input', test56], ['_RegistryProxyMixin', '@ember/-internals/runtime', 'RegistryProxyMixin', test57], ['_ContainerProxyMixin', '@ember/-internals/runtime', 'ContainerProxyMixin', test57], - ['ActionHandler', '@ember/-internals/runtime', null, test57], ['MutableEnumerable', '@ember/-internals/runtime', null, test57], ['controllerFor', '@ember/-internals/routing', null, test58], ['generateControllerFactory', '@ember/-internals/routing', null, test58], diff --git a/packages/ember/tests/routing/query_params_test.js b/packages/ember/tests/routing/query_params_test.js index d9f33febc3d..fb5d50e8dce 100644 --- a/packages/ember/tests/routing/query_params_test.js +++ b/packages/ember/tests/routing/query_params_test.js @@ -749,21 +749,15 @@ moduleFor( ); this.setSingleQPController('application', 'foo', 1, { + router: service(), + increment: action(function () { this.incrementProperty('foo'); - this.send('refreshRoute'); + this.router.refresh(); }), }); - this.add( - 'route:application', - class extends Route { - @action - refreshRoute() { - this.refresh(); - } - } - ); + this.add('route:application', class extends Route {}); await this.visitAndAssert('/'); assert.equal(getTextOf(document.getElementById('test-value')), '1'); diff --git a/packages/ember/tests/routing/router_service_test/non_application_test_test.js b/packages/ember/tests/routing/router_service_test/non_application_test_test.js index 077bd4b8a2e..3849bc2eac1 100644 --- a/packages/ember/tests/routing/router_service_test/non_application_test_test.js +++ b/packages/ember/tests/routing/router_service_test/non_application_test_test.js @@ -110,7 +110,7 @@ moduleFor( this.render('{{foo-bar}}'); run(function () { - componentInstance.send('transitionToSister'); + componentInstance.transitionToSister(); }); assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); diff --git a/packages/ember/tests/routing/router_service_test/transitionTo_test.js b/packages/ember/tests/routing/router_service_test/transitionTo_test.js index 10c1a9a1e55..2405af054e0 100644 --- a/packages/ember/tests/routing/router_service_test/transitionTo_test.js +++ b/packages/ember/tests/routing/router_service_test/transitionTo_test.js @@ -109,8 +109,7 @@ moduleFor( super.init(); componentInstance = this; } - @action - transitionToSister() { + @action transitionToSister() { get(this, 'routerService').transitionTo('parent.sister'); } }, @@ -119,7 +118,7 @@ moduleFor( return this.visit('/').then(() => { run(function () { - componentInstance.send('transitionToSister'); + componentInstance.transitionToSister(); }); assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); @@ -151,7 +150,7 @@ moduleFor( return this.visit('/').then(() => { run(function () { - componentInstance.send('transitionToSister'); + componentInstance.transitionToSister(); }); assert.equal(this.routerService.get('currentRouteName'), 'parent.sister'); @@ -186,7 +185,7 @@ moduleFor( await this.visit('/'); run(function () { - componentInstance.send('transitionToDynamic'); + componentInstance.transitionToDynamic(); }); assert.equal(this.routerService.get('currentRouteName'), 'dynamic'); @@ -231,7 +230,7 @@ moduleFor( await this.visit('/'); run(function () { - componentInstance.send('transitionToDynamic'); + componentInstance.transitionToDynamic(); }); assert.equal(this.routerService.get('currentRouteName'), 'dynamic'); diff --git a/tests/docs/expected.js b/tests/docs/expected.js index a004e98b951..e6ec306bf62 100644 --- a/tests/docs/expected.js +++ b/tests/docs/expected.js @@ -54,7 +54,6 @@ module.exports = { 'abort', 'acceptsModelName', 'action', - 'actions', 'activate', 'adapter', 'addListener', @@ -497,7 +496,6 @@ module.exports = { 'transitionTo', 'transitionToRoute', 'trigger', - 'triggerAction', 'trySet', 'typeOf', 'typeWatchers',