diff --git a/packages/@ember/-internals/glimmer/index.ts b/packages/@ember/-internals/glimmer/index.ts index aa6c9e2c96f..c4f5cc31ae3 100644 --- a/packages/@ember/-internals/glimmer/index.ts +++ b/packages/@ember/-internals/glimmer/index.ts @@ -295,11 +295,8 @@ export { templateFactory as template, templateCacheCounters } from '@glimmer/opcode-compiler'; export { default as RootTemplate } from './lib/templates/root'; -export { default as Checkbox } from './lib/components/checkbox'; -export { default as TextField } from './lib/components/text-field'; -export { default as TextArea } from './lib/components/-textarea'; -export { default as LinkComponent } from './lib/components/-link-to'; export { default as Input } from './lib/components/input'; +export { default as LinkTo } from './lib/components/link-to'; export { default as Textarea } from './lib/components/textarea'; export { default as Component } from './lib/component'; export { default as Helper, helper } from './lib/helper'; diff --git a/packages/@ember/-internals/glimmer/lib/component.ts b/packages/@ember/-internals/glimmer/lib/component.ts index e856100fa9d..4ecd78b2d42 100644 --- a/packages/@ember/-internals/glimmer/lib/component.ts +++ b/packages/@ember/-internals/glimmer/lib/component.ts @@ -1,6 +1,6 @@ import { get, PROPERTY_DID_CHANGE } from '@ember/-internals/metal'; import { getOwner } from '@ember/-internals/owner'; -import { CoreObject, TargetActionSupport } from '@ember/-internals/runtime'; +import { TargetActionSupport } from '@ember/-internals/runtime'; import { ActionSupport, ChildViewsSupport, @@ -11,8 +11,7 @@ import { ViewMixin, ViewStateSupport, } from '@ember/-internals/views'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; -import { assert, deprecate } from '@ember/debug'; +import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import { Environment } from '@glimmer/interfaces'; import { setInternalComponentManager } from '@glimmer/manager'; @@ -1061,71 +1060,4 @@ Component.reopenClass({ setInternalComponentManager(CURLY_COMPONENT_MANAGER, Component); -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - Object.defineProperty(Component, '_wasReopened', { - configurable: true, - enumerable: false, - writable: true, - value: false, - }); - - Object.defineProperty(Component, 'reopen', { - configurable: true, - enumerable: false, - writable: true, - value: function reopen(this: typeof Component, ...args: unknown[]): unknown { - if (this === Component) { - deprecate( - 'Reopening the Ember.Component super class itself is deprecated. ' + - 'Consider alternatives such as installing event listeners on ' + - 'the document or add the customizations to specific subclasses.', - false, - { - id: 'ember.component.reopen', - for: 'ember-source', - since: { - enabled: '4.0.0', - }, - url: 'https://deprecations.emberjs.com/v4.x#toc_ember-component-reopen', - until: '5.0.0', - } - ); - - Component._wasReopened = true; - } - - return CoreObject.reopen.call(this, ...args); - }, - }); - - Object.defineProperty(Component, 'reopenClass', { - configurable: true, - enumerable: false, - writable: true, - value: function reopenClass(this: typeof Component, ...args: unknown[]): unknown { - if (this === Component) { - deprecate( - 'Reopening the Ember.Component super class itself is deprecated. ' + - 'Consider alternatives such as installing event listeners on ' + - 'the document or add the customizations to specific subclasses.', - false, - { - id: 'ember.component.reopen', - for: 'ember-source', - url: 'https://deprecations.emberjs.com/v4.x#toc_ember-component-reopen', - since: { - enabled: '4.0.0', - }, - until: '5.0.0', - } - ); - - Component._wasReopened = true; - } - - return CoreObject.reopenClass.call(this, ...args); - }, - }); -} - export default Component; diff --git a/packages/@ember/-internals/glimmer/lib/components/-link-to.ts b/packages/@ember/-internals/glimmer/lib/components/-link-to.ts deleted file mode 100644 index edd973cae1b..00000000000 --- a/packages/@ember/-internals/glimmer/lib/components/-link-to.ts +++ /dev/null @@ -1,1082 +0,0 @@ -/** -@module ember -*/ - -import { alias, computed } from '@ember/-internals/metal'; -import { getOwner } from '@ember/-internals/owner'; -import RouterState from '@ember/-internals/routing/lib/system/router_state'; -import { CoreObject } from '@ember/-internals/runtime'; -import { isSimpleClick } from '@ember/-internals/views'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; -import { assert, deprecate, runInDebug, warn } from '@ember/debug'; -import { EngineInstance, getEngineParent } from '@ember/engine'; -import { flaggedInstrument } from '@ember/instrumentation'; -import { service } from '@ember/service'; -import { DEBUG } from '@glimmer/env'; -import EmberComponent from '../component'; -import { HAS_BLOCK } from '../component-managers/curly'; -import layout from '../templates/-link-to'; - -/** - The `LinkTo` component renders a link to the supplied `routeName` passing an optionally - supplied model to the route as its `model` context of the route. The block for `LinkTo` - becomes the contents of the rendered element: - - ```handlebars - - Great Hamster Photos - - ``` - - This will result in: - - ```html - - Great Hamster Photos - - ``` - - ### Disabling the `LinkTo` component - - The `LinkTo` component can be disabled by using the `disabled` argument. A disabled link - doesn't result in a transition when activated, and adds the `disabled` class to the `` - element. - - (The class name to apply to the element can be overridden by using the `disabledClass` - argument) - - ```handlebars - - Great Hamster Photos - - ``` - - ### Handling `href` - - `` will use your application's Router to fill the element's `href` property with a URL - that matches the path to the supplied `routeName`. - - ### Handling current route - - The `LinkTo` component will apply a CSS class name of 'active' when the application's current - route matches the supplied routeName. For example, if the application's current route is - 'photoGallery.recent', then the following invocation of `LinkTo`: - - ```handlebars - - Great Hamster Photos - - ``` - - will result in - - ```html - - Great Hamster Photos - - ``` - - The CSS class used for active classes can be customized by passing an `activeClass` argument: - - ```handlebars - - Great Hamster Photos - - ``` - - ```html - - Great Hamster Photos - - ``` - - ### Keeping a link active for other routes - - If you need a link to be 'active' even when it doesn't match the current route, you can use the - `current-when` argument. - - ```handlebars - - Photo Gallery - - ``` - - This may be helpful for keeping links active for: - - * non-nested routes that are logically related - * some secondary menu approaches - * 'top navigation' with 'sub navigation' scenarios - - A link will be active if `current-when` is `true` or the current - route is the route this link would transition to. - - To match multiple routes 'space-separate' the routes: - - ```handlebars - - Art Gallery - - ``` - - ### Supplying a model - - An optional `model` argument can be used for routes whose - paths contain dynamic segments. This argument will become - the model context of the linked route: - - ```javascript - Router.map(function() { - this.route("photoGallery", {path: "hamster-photos/:photo_id"}); - }); - ``` - - ```handlebars - - {{aPhoto.title}} - - ``` - - ```html - - Tomster - - ``` - - ### Supplying multiple models - - For deep-linking to route paths that contain multiple - dynamic segments, the `models` argument can be used. - - As the router transitions through the route path, each - supplied model argument will become the context for the - route with the dynamic segments: - - ```javascript - Router.map(function() { - this.route("photoGallery", { path: "hamster-photos/:photo_id" }, function() { - this.route("comment", {path: "comments/:comment_id"}); - }); - }); - ``` - - This argument will become the model context of the linked route: - - ```handlebars - - {{comment.body}} - - ``` - - ```html - - A+++ would snuggle again. - - ``` - - ### Supplying an explicit dynamic segment value - - If you don't have a model object available to pass to `LinkTo`, - an optional string or integer argument can be passed for routes whose - paths contain dynamic segments. This argument will become the value - of the dynamic segment: - - ```javascript - Router.map(function() { - this.route("photoGallery", { path: "hamster-photos/:photo_id" }); - }); - ``` - - ```handlebars - - {{this.aPhoto.title}} - - ``` - - ```html - - Tomster - - ``` - - When transitioning into the linked route, the `model` hook will - be triggered with parameters including this passed identifier. - - ### Supplying a `tagName` - - By default `` renders an `` element. This can be overridden for a single use of - `` by supplying a `tagName` argument: - - ```handlebars - - Great Hamster Photos - - ``` - - This produces: - - ```html -
  • - Great Hamster Photos -
  • - ``` - - In general, this is not recommended. - - ### Supplying query parameters - - If you need to add optional key-value pairs that appear to the right of the ? in a URL, - you can use the `query` argument. - - ```handlebars - - Great Hamster Photos - - ``` - - This will result in: - - ```html -
    - Great Hamster Photos - - ``` - - @for Ember.Templates.components - @method LinkTo - @see {LinkComponent} - @public -*/ - -/** - @module @ember/routing -*/ - -/** - See [Ember.Templates.components.LinkTo](/ember/release/classes/Ember.Templates.components/methods/input?anchor=LinkTo). - - @for Ember.Templates.helpers - @method link-to - @see {Ember.Templates.components.LinkTo} - @public -**/ - -/** - `LinkComponent` is the internal component invoked with `` or `{{link-to}}`. - - @class LinkComponent - @extends Component - @see {Ember.Templates.components.LinkTo} - @public -**/ - -const UNDEFINED = Object.freeze({ - toString() { - return 'UNDEFINED'; - }, -}); - -const EMPTY_QUERY_PARAMS = Object.freeze({}); - -const LinkComponent = EmberComponent.extend({ - layout, - - tagName: 'a', - - /** - @property route - @public - */ - route: UNDEFINED, - - /** - @property model - @public - */ - model: UNDEFINED, - - /** - @property models - @public - */ - models: UNDEFINED, - - /** - @property query - @public - */ - query: UNDEFINED, - - /** - Used to determine when this `LinkComponent` is active. - - @property current-when - @public - */ - 'current-when': null, - - /** - Sets the `title` attribute of the `LinkComponent`'s HTML element. - - @property title - @default null - @public - **/ - title: null, - - /** - Sets the `rel` attribute of the `LinkComponent`'s HTML element. - - @property rel - @default null - @public - **/ - rel: null, - - /** - Sets the `tabindex` attribute of the `LinkComponent`'s HTML element. - - @property tabindex - @default null - @public - **/ - tabindex: null, - - /** - Sets the `target` attribute of the `LinkComponent`'s HTML element. - - @since 1.8.0 - @property target - @default null - @public - **/ - target: null, - - /** - The CSS class to apply to `LinkComponent`'s element when its `active` - property is `true`. - - @property activeClass - @type String - @default active - @public - **/ - activeClass: 'active', - - /** - The CSS class to apply to `LinkComponent`'s element when its `loading` - property is `true`. - - @property loadingClass - @type String - @default loading - @public - **/ - loadingClass: 'loading', - - /** - The CSS class to apply to a `LinkComponent`'s element when its `disabled` - property is `true`. - - @property disabledClass - @type String - @default disabled - @public - **/ - disabledClass: 'disabled', - - /** - Determines whether the `LinkComponent` will trigger routing via - the `replaceWith` routing strategy. - - @property replace - @type Boolean - @default false - @public - **/ - replace: false, - - /** - Determines whether the `LinkComponent` will prevent the default - browser action by calling preventDefault() to avoid reloading - the browser page. - - If you need to trigger a full browser reload pass `@preventDefault={{false}}`: - - ```handlebars - - {{this.aPhotoId.title}} - - ``` - - @property preventDefault - @type Boolean - @default true - @private - **/ - preventDefault: true, - - /** - By default this component will forward `href`, `title`, `rel`, `tabindex`, and `target` - arguments to attributes on the component's element. When invoked with `{{link-to}}`, you can - only customize these attributes. When invoked with ``, you can just use HTML - attributes directly. - - @property attributeBindings - @type Array | String - @default ['title', 'rel', 'tabindex', 'target'] - @public - */ - attributeBindings: ['href', 'title', 'rel', 'tabindex', 'target'], - - /** - By default this component will set classes on its element when any of the following arguments - are truthy: - - * active - * loading - * disabled - - When these arguments are truthy, a class with the same name will be set on the element. When - falsy, the associated class will not be on the element. - - @property classNameBindings - @type Array - @default ['active', 'loading', 'disabled', 'ember-transitioning-in', 'ember-transitioning-out'] - @public - */ - classNameBindings: ['active', 'loading', 'disabled', 'transitioningIn', 'transitioningOut'], - - /** - By default this component responds to the `click` event. When the component element is an - `` element, activating the link in another way, such as using the keyboard, triggers the - click event. - - @property eventName - @type String - @default click - @private - */ - eventName: 'click', - - // this is doc'ed here so it shows up in the events - // section of the API documentation, which is where - // people will likely go looking for it. - /** - Triggers the `LinkComponent`'s routing behavior. If - `eventName` is changed to a value other than `click` - the routing behavior will trigger on that custom event - instead. - - @event click - @private - */ - - /** - An overridable method called when `LinkComponent` objects are instantiated. - - Example: - - ```app/components/my-link.js - import LinkComponent from '@ember/routing/link-component'; - - export default LinkComponent.extend({ - init() { - this._super(...arguments); - console.log('Event is ' + this.get('eventName')); - } - }); - ``` - - NOTE: If you do override `init` for a framework class like `Component`, - be sure to call `this._super(...arguments)` in your - `init` declaration! If you don't, Ember may not have an opportunity to - do important setup work, and you'll see strange behavior in your - application. - - @method init - @private - */ - init() { - this._super(...arguments); - - this.assertLinkToOrigin(); - - // Map desired event name to invoke function - let { eventName } = this; - this.on(eventName, this, this._invoke); - }, - - _routing: service('-routing'), - _currentRoute: alias('_routing.currentRouteName'), - _currentRouterState: alias('_routing.currentState'), - _targetRouterState: alias('_routing.targetState'), - - _isEngine: computed(function (this: any) { - return getEngineParent(getOwner(this) as EngineInstance) !== undefined; - }), - - _engineMountPoint: computed(function (this: any) { - return (getOwner(this) as EngineInstance).mountPoint; - }), - - _route: computed('route', '_currentRouterState', function computeLinkToComponentRoute(this: any) { - let { route } = this; - - return route === UNDEFINED ? this._currentRoute : this._namespaceRoute(route); - }), - - _models: computed('model', 'models', function computeLinkToComponentModels(this: any) { - let { model, models } = this; - - assert( - 'You cannot provide both the `@model` and `@models` arguments to the component.', - model === UNDEFINED || models === UNDEFINED - ); - - if (model !== UNDEFINED) { - return [model]; - } else if (models !== UNDEFINED) { - assert('The `@models` argument must be an array.', Array.isArray(models)); - return models; - } else { - return []; - } - }), - - _query: computed('query', function computeLinkToComponentQuery(this: any) { - let { query } = this; - - if (query === UNDEFINED) { - return EMPTY_QUERY_PARAMS; - } else { - return Object.assign({}, query); - } - }), - - /** - Accessed as a classname binding to apply the component's `disabledClass` - CSS `class` to the element when the link is disabled. - - When `true`, interactions with the element will not trigger route changes. - @property disabled - @private - */ - disabled: computed({ - get(_key: string): boolean { - // always returns false for `get` because (due to the `set` just below) - // the cached return value from the set will prevent this getter from _ever_ - // being called after a set has occurred - return false; - }, - - set(this: any, _key: string, value: any): boolean { - this._isDisabled = value; - - return value ? this.disabledClass : false; - }, - }), - - /** - Accessed as a classname binding to apply the component's `activeClass` - CSS `class` to the element when the link is active. - - This component is considered active when its `currentWhen` property is `true` - or the application's current route is the route this component would trigger - transitions into. - - The `currentWhen` property can match against multiple routes by separating - route names using the ` ` (space) character. - - @property active - @private - */ - active: computed('activeClass', '_active', function computeLinkToComponentActiveClass(this: any) { - return this._active ? this.activeClass : false; - }), - - _active: computed( - '_currentRouterState', - '_route', - '_models', - '_query', - 'loading', - 'current-when', - function computeLinkToComponentActive(this: any) { - let { _currentRouterState: state } = this; - - if (state) { - return this._isActive(state); - } else { - return false; - } - } - ), - - willBeActive: computed( - '_currentRouterState', - '_targetRouterState', - '_route', - '_models', - '_query', - 'loading', - 'current-when', - function computeLinkToComponentWillBeActive(this: any) { - let { _currentRouterState: current, _targetRouterState: target } = this; - - if (current === target) { - return; - } - - return this._isActive(target); - } - ), - - /** - * Method to assert that LinkTo is not used inside of a routeless engine. This method is - * overridden in ember-engines link-to-external component to just be a noop, since the - * link-to-external component extends the link-to component. - * - * @method assertLinkToOrigin - * @private - */ - assertLinkToOrigin() { - assert( - 'You attempted to use the component within a routeless engine, this is not supported. ' + - 'If you are using the ember-engines addon, use the component instead. ' + - 'See https://ember-engines.com/docs/links for more info.', - !this._isEngine || this._engineMountPoint !== undefined - ); - }, - - _isActive(routerState: RouterState): boolean { - if (this.loading) { - return false; - } - - let currentWhen = this['current-when']; - - if (typeof currentWhen === 'boolean') { - return currentWhen; - } - - let { _models: models, _routing: routing } = this; - - if (typeof currentWhen === 'string') { - return currentWhen - .split(' ') - .some((route) => - routing.isActiveForRoute(models, undefined, this._namespaceRoute(route), routerState) - ); - } else { - return routing.isActiveForRoute(models, this._query, this._route, routerState); - } - }, - - transitioningIn: computed( - '_active', - 'willBeActive', - function computeLinkToComponentTransitioningIn(this: any) { - if (this.willBeActive === true && !this._active) { - return 'ember-transitioning-in'; - } else { - return false; - } - } - ), - - transitioningOut: computed( - '_active', - 'willBeActive', - function computeLinkToComponentTransitioningOut(this: any) { - if (this.willBeActive === false && this._active) { - return 'ember-transitioning-out'; - } else { - return false; - } - } - ), - - _namespaceRoute(route: string): string { - let { _engineMountPoint: mountPoint } = this; - - if (mountPoint === undefined) { - return route; - } else if (route === 'application') { - return mountPoint; - } else { - return `${mountPoint}.${route}`; - } - }, - - /** - Event handler that invokes the link, activating the associated route. - - @method _invoke - @param {Event} event - @private - */ - _invoke(this: any, event: Event): boolean { - if (!isSimpleClick(event)) { - return true; - } - - let { bubbles, preventDefault } = this; - let target = this.element.target; - let isSelf = !target || target === '_self'; - - if (preventDefault !== false && isSelf) { - event.preventDefault(); - } - - if (bubbles === false) { - event.stopPropagation(); - } - - if (this._isDisabled) { - return false; - } - - if (this.loading) { - // tslint:disable-next-line:max-line-length - warn( - 'This link is in an inactive loading state because at least one of its models ' + - 'currently has a null/undefined value, or the provided route name is invalid.', - false, - { - id: 'ember-glimmer.link-to.inactive-loading-state', - } - ); - return false; - } - - if (!isSelf) { - return false; - } - - let { _route: routeName, _models: models, _query: queryParams, replace: shouldReplace } = this; - - let payload = { - queryParams, - routeName, - }; - - flaggedInstrument( - 'interaction.link-to', - payload, - this._generateTransition(payload, routeName, models, queryParams, shouldReplace) - ); - return false; - }, - - _generateTransition( - payload: any, - qualifiedRouteName: string, - models: any[], - queryParams: any[], - shouldReplace: boolean - ) { - let { _routing: routing } = this; - - return () => { - payload.transition = routing.transitionTo( - qualifiedRouteName, - models, - queryParams, - shouldReplace - ); - }; - }, - - /** - Sets the element's `href` attribute to the url for - the `LinkComponent`'s targeted route. - - If the `LinkComponent`'s `tagName` is changed to a value other - than `a`, this property will be ignored. - - @property href - @private - */ - href: computed( - '_currentRouterState', - '_route', - '_models', - '_query', - 'tagName', - 'loading', - 'loadingHref', - function computeLinkToComponentHref(this: any) { - if (this.tagName !== 'a') { - return; - } - - if (this.loading) { - return this.loadingHref; - } - - let { _route: route, _models: models, _query: query, _routing: routing } = this; - - if (DEBUG) { - /* - * Unfortunately, to get decent error messages, we need to do this. - * In some future state we should be able to use a "feature flag" - * which allows us to strip this without needing to call it twice. - * - * if (isDebugBuild()) { - * // Do the useful debug thing, probably including try/catch. - * } else { - * // Do the performant thing. - * } - */ - try { - return routing.generateURL(route, models, query); - } catch (e) { - // tslint:disable-next-line:max-line-length - e.message = `While generating link to route "${this.route}": ${e.message}`; - throw e; - } - } else { - return routing.generateURL(route, models, query); - } - } - ), - - loading: computed( - '_route', - '_modelsAreLoaded', - 'loadingClass', - function computeLinkToComponentLoading(this: any) { - let { _route: route, _modelsAreLoaded: loaded } = this; - - if (!loaded || route === null || route === undefined) { - return this.loadingClass; - } - } - ), - - _modelsAreLoaded: computed('_models', function computeLinkToComponentModelsAreLoaded(this: any) { - let { _models: models } = this; - - for (let i = 0; i < models.length; i++) { - let model = models[i]; - if (model === null || model === undefined) { - return false; - } - } - - return true; - }), - - /** - The default href value to use while a link-to is loading. - Only applies when tagName is 'a' - - @property loadingHref - @type String - @default # - @private - */ - loadingHref: '#', - - didReceiveAttrs() { - let { disabledWhen } = this; - - if (disabledWhen !== undefined) { - this.set('disabled', disabledWhen); - } - - let { params } = this; - - if (!params || params.length === 0) { - assert( - 'You must provide at least one of the `@route`, `@model`, `@models` or `@query` argument to ``.', - !( - this.route === UNDEFINED && - this.model === UNDEFINED && - this.models === UNDEFINED && - this.query === UNDEFINED - ) - ); - - let { _models: models } = this; - if (models.length > 0) { - let lastModel = models[models.length - 1]; - - if (typeof lastModel === 'object' && lastModel !== null && lastModel.isQueryParams) { - this.query = lastModel.values; - models.pop(); - } - } - - return; - } - - let hasBlock = this[HAS_BLOCK]; - - params = params.slice(); - - // Process the positional arguments, in order. - // 1. Inline link title comes first, if present. - if (!hasBlock) { - this.set('linkTitle', params.shift()); - } - - // 2. The last argument is possibly the `query` object. - let queryParams = params[params.length - 1]; - - if (queryParams && queryParams.isQueryParams) { - this.set('query', params.pop().values); - } else { - this.set('query', UNDEFINED); - } - - // 3. If there is a `route`, it is now at index 0. - if (params.length === 0) { - this.set('route', UNDEFINED); - } else { - this.set('route', params.shift()); - } - - // 4. Any remaining indices (if any) are `models`. - this.set('model', UNDEFINED); - this.set('models', params); - - runInDebug(() => { - params = this.params.slice(); - - let equivalentNamedArgs = []; - let hasQueryParams = false; - - // Process the positional arguments, in order. - // 1. Inline link title comes first, if present. - if (!hasBlock) { - params.shift(); - } - - // 2. The last argument is possibly the `query` object. - let query = params[params.length - 1]; - - if (query && query.isQueryParams) { - params.pop(); - hasQueryParams = true; - } - - // 3. If there is a `route`, it is now at index 0. - if (params.length > 0) { - params.shift(); - equivalentNamedArgs.push('`@route`'); - } - - // 4. Any remaining params (if any) are `models`. - if (params.length === 1) { - equivalentNamedArgs.push('`@model`'); - } else if (params.length > 1) { - equivalentNamedArgs.push('`@models`'); - } - - if (hasQueryParams) { - equivalentNamedArgs.push('`@query`'); - } - - if (equivalentNamedArgs.length > 0) { - let message = 'Invoking the `` component with positional arguments is deprecated.'; - - message += `Please use the equivalent named arguments (${equivalentNamedArgs.join(', ')})`; - - if (hasQueryParams) { - message += ' along with the `hash` helper'; - } - - if (!hasBlock) { - message += " and pass a block for the link's content."; - } - - message += '.'; - - deprecate(message, false, { - id: 'ember-glimmer.link-to.positional-arguments', - until: '4.0.0', - for: 'ember-source', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-glimmer-link-to-positional-arguments', - since: { - enabled: '3.26.0-beta.1', - }, - }); - } - }); - }, -}); - -LinkComponent.toString = () => '@ember/routing/link-component'; - -LinkComponent.reopenClass({ - positionalParams: 'params', -}); - -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - Object.defineProperty(LinkComponent, '_wasReopened', { - configurable: true, - enumerable: false, - writable: true, - value: false, - }); - - Object.defineProperty(LinkComponent, 'reopen', { - configurable: true, - enumerable: false, - writable: true, - value: function reopen(this: typeof LinkComponent, ...args: unknown[]): unknown { - if (this === LinkComponent) { - deprecate( - 'Reopening Ember.LinkComponent is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - LinkComponent._wasReopened = true; - } - - return CoreObject.reopen.call(this, ...args); - }, - }); - - Object.defineProperty(LinkComponent, 'reopenClass', { - configurable: true, - enumerable: false, - writable: true, - value: function reopenClass(this: typeof LinkComponent, ...args: unknown[]): unknown { - if (this === LinkComponent) { - deprecate( - 'Reopening Ember.LinkComponent is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - LinkComponent._wasReopened = true; - } - - return CoreObject.reopenClass.call(this, ...args); - }, - }); -} - -export default LinkComponent; diff --git a/packages/@ember/-internals/glimmer/lib/components/-textarea.ts b/packages/@ember/-internals/glimmer/lib/components/-textarea.ts deleted file mode 100644 index 95aa097bc1c..00000000000 --- a/packages/@ember/-internals/glimmer/lib/components/-textarea.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** -@module @ember/component -*/ -import { CoreObject } from '@ember/-internals/runtime'; -import { TextSupport } from '@ember/-internals/views'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; -import { deprecate } from '@ember/debug'; -import Component from '../component'; -import layout from '../templates/empty'; - -/** - The internal representation used for `Textarea` invocations. - - @class TextArea - @extends Component - @see {Ember.Templates.components.Textarea} - @uses Ember.TextSupport - @public -*/ -const TextArea = Component.extend(TextSupport, { - classNames: ['ember-text-area'], - - layout, - - tagName: 'textarea', - attributeBindings: [ - 'rows', - 'cols', - 'name', - 'selectionEnd', - 'selectionStart', - 'autocomplete', - 'wrap', - 'lang', - 'dir', - 'value', - ], - rows: null, - cols: null, -}); - -TextArea.toString = () => '@ember/component/text-area'; - -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - Object.defineProperty(TextArea, '_wasReopened', { - configurable: true, - enumerable: false, - writable: true, - value: false, - }); - - Object.defineProperty(TextArea, 'reopen', { - configurable: true, - enumerable: false, - writable: true, - value: function reopen(this: typeof TextArea, ...args: unknown[]): unknown { - if (this === TextArea) { - deprecate( - 'Reopening Ember.TextArea is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - TextArea._wasReopened = true; - } - - return CoreObject.reopen.call(this, ...args); - }, - }); - - Object.defineProperty(TextArea, 'reopenClass', { - configurable: true, - enumerable: false, - writable: true, - value: function reopenClass(this: typeof TextArea, ...args: unknown[]): unknown { - if (this === TextArea) { - deprecate( - 'Reopening Ember.TextArea is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - TextArea._wasReopened = true; - } - - return CoreObject.reopenClass.call(this, ...args); - }, - }); -} - -export default TextArea; diff --git a/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts b/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts index 1ae1ca26a74..1580cbace9f 100644 --- a/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts +++ b/packages/@ember/-internals/glimmer/lib/components/abstract-input.ts @@ -1,19 +1,8 @@ import { tracked } from '@ember/-internals/metal'; -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 { action } from '@ember/object'; import { isConstRef, isUpdatableRef, Reference, updateRef, valueForRef } from '@glimmer/reference'; -import Component from '../component'; -import InternalComponent, { - DeprecatingInternalComponent, - EventListener, - handleDeprecatedArguments, - handleDeprecatedAttributeArguments, - handleDeprecatedEventArguments, - InternalComponentConstructor, -} from './internal'; +import InternalComponent, { EventListener } from './internal'; const UNINITIALIZED: unknown = Object.freeze({}); @@ -109,11 +98,7 @@ class ForkedValue implements Value { } } -export default abstract class AbstractInput - extends InternalComponent - implements DeprecatingInternalComponent { - modernized = this.shouldModernize(); - +export default abstract class AbstractInput extends InternalComponent { validateArguments(): void { assert( `The ${this.constructor} component does not take any positional arguments`, @@ -123,15 +108,6 @@ export default abstract class AbstractInput super.validateArguments(); } - protected shouldModernize(): boolean { - return ( - Boolean(EMBER_MODERNIZED_BUILT_IN_COMPONENTS) && - Component._wasReopened === false && - TextSupport._wasReopened === false && - TargetActionSupport._wasReopened === false - ); - } - private _value = valueFrom(this.args.named.value); get value(): unknown { @@ -200,45 +176,3 @@ export default abstract class AbstractInput return virtualEvents.indexOf(name) !== -1; } } - -export function handleDeprecatedFeatures( - target: InternalComponentConstructor, - attributeBindings: Array -): void { - if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - let { prototype } = target; - - let virtualEvents = { - focusin: 'focus-in', - focusout: 'focus-out', - keypress: 'key-press', - keyup: 'key-up', - keydown: 'key-down', - }; - - handleDeprecatedArguments(target); - - handleDeprecatedAttributeArguments(target, attributeBindings); - - handleDeprecatedEventArguments(target, Object.entries(virtualEvents)); - - { - let superIsVirtualEventListener = prototype['isVirtualEventListener']; - - Object.defineProperty(prototype, 'isVirtualEventListener', { - configurable: true, - enumerable: false, - value: function isVirtualEventListener( - this: AbstractInput, - name: string, - listener: Function - ): listener is VirtualEventListener { - return ( - Object.values(virtualEvents).indexOf(name) !== -1 || - superIsVirtualEventListener.call(this, name, listener) - ); - }, - }); - } - } -} diff --git a/packages/@ember/-internals/glimmer/lib/components/checkbox.ts b/packages/@ember/-internals/glimmer/lib/components/checkbox.ts deleted file mode 100644 index d9a39d50e49..00000000000 --- a/packages/@ember/-internals/glimmer/lib/components/checkbox.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { set } from '@ember/-internals/metal'; -import { FrameworkObject } from '@ember/-internals/runtime'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; -import { assert, deprecate } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; -import EmberComponent from '../component'; -import layout from '../templates/empty'; - -/** -@module @ember/component -*/ - -/** - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `checkbox`. - - See [Ember.Templates.helpers.input](/ember/release/classes/Ember.Templates.helpers/methods/input?anchor=input) for usage details. - - ## Direct manipulation of `checked` - - The `checked` attribute of an `Checkbox` object should always be set - through the Ember object or by interacting with its rendered element - representation via the mouse, keyboard, or touch. Updating the value of the - checkbox via jQuery will result in the checked value of the object and its - element losing synchronization. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. - - @class Checkbox - @extends Component - @public -*/ -const Checkbox = EmberComponent.extend({ - layout, - - /** - By default, this component will add the `ember-checkbox` class to the component's element. - - @property classNames - @type Array | String - @default ['ember-checkbox'] - @public - */ - classNames: ['ember-checkbox'], - - tagName: 'input', - - /** - By default this component will forward a number of arguments to attributes on the the - component's element: - - * indeterminate - * disabled - * tabindex - * name - * autofocus - * required - * form - - When invoked with curly braces, this is the exhaustive list of HTML attributes you can - customize (i.e. `{{input type="checkbox" disabled=true}}`). - - When invoked with angle bracket invocation, this list is irrelevant, because you can use HTML - attribute syntax to customize the element (i.e. - ``). However, `@type` and - `@checked` must be passed as named arguments, not attributes. - - @property attributeBindings - @type Array | String - @default ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name', 'autofocus', 'required', 'form'] - @public - */ - attributeBindings: [ - 'type', - 'checked', - 'indeterminate', - 'disabled', - 'tabindex', - 'name', - 'autofocus', - 'required', - 'form', - ], - - /** - Sets the `type` attribute of the `Checkbox`'s element - - @property disabled - @default false - @private - */ - type: 'checkbox', - - /** - Sets the `disabled` attribute of the `Checkbox`'s element - - @property disabled - @default false - @public - */ - disabled: false, - - /** - Corresponds to the `indeterminate` property of the `Checkbox`'s element - - @property disabled - @default false - @public - */ - indeterminate: false, - - /** - Whenever the checkbox is inserted into the DOM, perform initialization steps, which include - setting the indeterminate property if needed. - - If this method is overridden, `super` must be called. - - @method - @public - */ - didInsertElement() { - this._super(...arguments); - this.element.indeterminate = Boolean(this.indeterminate); - }, - - /** - Whenever the `change` event is fired on the checkbox, update its `checked` property to reflect - whether the checkbox is checked. - - If this method is overridden, `super` must be called. - - @method - @public - */ - change() { - set(this, 'checked', this.element.checked); - }, -}); - -if (DEBUG) { - const UNSET = {}; - - Checkbox.reopen({ - value: UNSET, - - didReceiveAttrs() { - this._super(); - - assert( - "`` is not supported; " + - "please use `` instead.", - !(this.type === 'checkbox' && this.value !== UNSET) - ); - }, - }); -} - -Checkbox.toString = () => '@ember/component/checkbox'; - -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - Object.defineProperty(Checkbox, '_wasReopened', { - configurable: true, - enumerable: false, - writable: true, - value: false, - }); - - Object.defineProperty(Checkbox, 'reopen', { - configurable: true, - enumerable: false, - writable: true, - value: function reopen(this: typeof Checkbox, ...args: unknown[]): unknown { - if (this === Checkbox) { - deprecate( - 'Reopening Ember.Checkbox is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - Checkbox._wasReopened = true; - } - - return FrameworkObject.reopen.call(this, ...args); - }, - }); - - Object.defineProperty(Checkbox, 'reopenClass', { - configurable: true, - enumerable: false, - writable: true, - value: function reopenClass(this: typeof Checkbox, ...args: unknown[]): unknown { - if (this === Checkbox) { - deprecate( - 'Reopening Ember.Checkbox is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - Checkbox._wasReopened = true; - } - - return FrameworkObject.reopenClass.call(this, ...args); - }, - }); -} - -export default Checkbox; diff --git a/packages/@ember/-internals/glimmer/lib/components/input.ts b/packages/@ember/-internals/glimmer/lib/components/input.ts index b977bc5c6a8..5961a22597d 100644 --- a/packages/@ember/-internals/glimmer/lib/components/input.ts +++ b/packages/@ember/-internals/glimmer/lib/components/input.ts @@ -2,20 +2,17 @@ @module @ember/component */ import { hasDOM } from '@ember/-internals/browser-environment'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { assert, warn } from '@ember/debug'; import { action } from '@ember/object'; import { valueForRef } from '@glimmer/reference'; import { untrack } from '@glimmer/validator'; import InputTemplate from '../templates/input'; -import AbstractInput, { handleDeprecatedFeatures, valueFrom } from './abstract-input'; -import Checkbox from './checkbox'; +import AbstractInput, { valueFrom } from './abstract-input'; import { opaquify } from './internal'; -import TextField from './text-field'; let isValidInputType: (type: string) => boolean; -if (hasDOM && EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { +if (hasDOM) { const INPUT_TYPES: Record = Object.create(null); const INPUT_ELEMENT = document.createElement('input'); @@ -264,12 +261,6 @@ class Input extends AbstractInput { this.checked = element.checked; } - protected shouldModernize(): boolean { - return ( - super.shouldModernize() && TextField._wasReopened === false && Checkbox._wasReopened === false - ); - } - protected isSupportedArgument(name: string): boolean { let supportedArguments = [ 'type', @@ -284,57 +275,4 @@ class Input extends AbstractInput { } } -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - handleDeprecatedFeatures(Input, [ - // Component - 'id', - ['id', 'elementId'], - 'class', - ['class', 'classNames'], - ['role', 'ariaRole'], - - // TextSupport - 'autocapitalize', - 'autocorrect', - 'autofocus', - 'disabled', - 'form', - 'maxlength', - 'minlength', - 'placeholder', - 'readonly', - 'required', - 'selectionDirection', - 'spellcheck', - 'tabindex', - 'title', - - // TextField - 'accept', - 'autocomplete', - 'autosave', - 'dir', - 'formaction', - 'formenctype', - 'formmethod', - 'formnovalidate', - 'formtarget', - 'height', - 'inputmode', - 'lang', - 'list', - 'max', - 'min', - 'multiple', - 'name', - 'pattern', - 'size', - 'step', - 'width', - - // Checkbox - 'indeterminate', - ]); -} - export default opaquify(Input, InputTemplate); diff --git a/packages/@ember/-internals/glimmer/lib/components/internal.ts b/packages/@ember/-internals/glimmer/lib/components/internal.ts index f3ac67a5c57..fefc60fe016 100644 --- a/packages/@ember/-internals/glimmer/lib/components/internal.ts +++ b/packages/@ember/-internals/glimmer/lib/components/internal.ts @@ -1,7 +1,6 @@ import { Owner, setOwner } from '@ember/-internals/owner'; import { guidFor } from '@ember/-internals/utils'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; -import { assert, deprecate } from '@ember/debug'; +import { assert } from '@ember/debug'; import { CapturedArguments, Destroyable, @@ -9,20 +8,13 @@ import { Environment, InternalComponentCapabilities, InternalComponentManager, - Maybe, - Option, TemplateFactory, VMArguments, WithCreateInstance, } from '@glimmer/interfaces'; -import { - setComponentTemplate, - setInternalComponentManager, - setInternalModifierManager, -} from '@glimmer/manager'; +import { setComponentTemplate, setInternalComponentManager } from '@glimmer/manager'; import { createConstRef, isConstRef, Reference, valueForRef } from '@glimmer/reference'; import { untrack } from '@glimmer/validator'; -import InternalModifier, { InternalModifierManager } from '../modifiers/internal'; function NOOP(): void {} @@ -226,327 +218,3 @@ class InternalManager } const INTERNAL_COMPONENT_MANAGER = new InternalManager(); - -// Deprecated features - -export interface DeprecatingInternalComponent extends InternalComponent { - modernized: boolean; -} - -export type DeprecatingInternalComponentConstructor = InternalComponentConstructor< - DeprecatingInternalComponent ->; - -export function handleDeprecatedArguments(target: DeprecatingInternalComponentConstructor): void { - if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - let angle = target.toString(); - let { prototype } = target; - - let superOnUnsupportedArgument = prototype['onUnsupportedArgument']; - - Object.defineProperty(prototype, 'onUnsupportedArgument', { - configurable: true, - enumerable: false, - value: function onUnsupportedArgument( - this: DeprecatingInternalComponent, - name: string - ): void { - deprecate(`Passing the \`@${name}\` argument to <${angle}> is deprecated.`, false, { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - }); - - this.modernized = false; - - superOnUnsupportedArgument.call(this, name); - }, - }); - } -} - -export function handleDeprecatedAttributeArguments( - target: DeprecatingInternalComponentConstructor, - bindings: Array -): void { - if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - let angle = target.toString(); - let curly = angle.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - let { prototype } = target; - - let descriptorFor = (target: object, property: string): Option => { - if (target) { - return ( - Object.getOwnPropertyDescriptor(target, property) || - descriptorFor(Object.getPrototypeOf(target), property) - ); - } else { - return null; - } - }; - - bindings.forEach((binding) => { - let attribute: string; - let argument: string; - - if (Array.isArray(binding)) { - [attribute, argument] = binding; - } else { - attribute = argument = binding; - } - - let superIsSupportedArgument = prototype['isSupportedArgument']; - - Object.defineProperty(prototype, 'isSupportedArgument', { - configurable: true, - enumerable: false, - value: function isSupportedArgument( - this: DeprecatingInternalComponent, - name: string - ): boolean { - return ( - (this.modernized && name === argument) || superIsSupportedArgument.call(this, name) - ); - }, - }); - - let superDescriptor = descriptorFor(prototype, attribute); - let superGetter: (this: DeprecatingInternalComponent) => unknown = () => undefined; - - if (superDescriptor) { - assert( - `[BUG] expecting ${attribute} to be a getter on <${angle}>`, - typeof superDescriptor.get === 'function' - ); - - superGetter = superDescriptor.get; - } - - Object.defineProperty(prototype, attribute, { - configurable: true, - enumerable: true, - get(this: DeprecatingInternalComponent): unknown { - if (argument in this.args.named) { - deprecate( - `Passing the \`@${argument}\` argument to <${angle}> is deprecated. ` + - `Instead, please pass the attribute directly, i.e. \`<${angle} ${attribute}={{...}} />\` ` + - `instead of \`<${angle} @${argument}={{...}} />\` or \`{{${curly} ${argument}=...}}\`.`, - false, - { - id: 'ember.built-in-components.legacy-attribute-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-attribute-arguments', - } - ); - - // The `class` attribute is concatenated/merged instead of clobbered - if (attribute === 'class' && superDescriptor) { - return `${superGetter.call(this)} ${this.named(argument)}`; - } else { - return this.named(argument); - } - } else { - return superGetter.call(this); - } - }, - }); - }); - } -} - -export let handleDeprecatedEventArguments: ( - target: DeprecatingInternalComponentConstructor, - extraEvents?: Array<[event: string, argument: string]> -) => void = NOOP; - -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - type EventsMap = Record; - - const EVENTS = new WeakMap(); - - const EMPTY_EVENTS = Object.freeze({}) as EventsMap; - - const getEventsMap = (owner: Owner): EventsMap => { - let events = EVENTS.get(owner); - - if (events === undefined) { - events = EMPTY_EVENTS; - - let eventDispatcher = owner.lookup>( - 'event_dispatcher:main' - ); - - if (eventDispatcher !== null && eventDispatcher !== undefined) { - assert('[BUG] invalid event dispatcher', typeof eventDispatcher === 'object'); - - if ( - '_finalEvents' in eventDispatcher && - eventDispatcher._finalEvents !== null && - eventDispatcher._finalEvents !== undefined - ) { - assert( - '[BUG] invalid _finalEvents on event dispatcher', - typeof eventDispatcher._finalEvents === 'object' - ); - - events = eventDispatcher._finalEvents; - } - } - - EVENTS.set(owner, events); - } - - return events; - }; - - handleDeprecatedEventArguments = (target, extraEvents = []) => { - let angle = target.toString(); - let curly = angle.toLowerCase(); - let { prototype } = target; - - let superIsSupportedArgument = prototype['isSupportedArgument']; - - Object.defineProperty(prototype, 'isSupportedArgument', { - configurable: true, - enumerable: false, - value: function isSupportedArgument( - this: DeprecatingInternalComponent, - name: string - ): boolean { - let events = [ - ...Object.values(getEventsMap(this.owner)), - 'focus-in', - 'focus-out', - 'key-press', - 'key-up', - 'key-down', - ]; - - return ( - (this.modernized && events.indexOf(name) !== -1) || - superIsSupportedArgument.call(this, name) - ); - }, - }); - - class DeprecatedEventHandlersModifier extends InternalModifier { - static toString(): string { - return 'DeprecatedEventHandlersModifier'; - } - - private listeners = new Map(); - - install(): void { - let { element, component, listenerFor, listeners } = this; - - let entries: [event: string, argument: string][] = [ - ...Object.entries(getEventsMap(this.owner)), - ...extraEvents, - ]; - - for (let [event, argument] of entries) { - let listener = listenerFor.call(component, event, argument); - - if (listener) { - listeners.set(event, listener); - element.addEventListener(event, listener); - } - } - - Object.freeze(listeners); - } - - remove(): void { - let { element, listeners } = this; - - for (let [event, listener] of Object.entries(listeners)) { - element.removeEventListener(event, listener); - } - - this.listeners = new Map(); - } - - private get component(): DeprecatingInternalComponent { - let component = this.positional(0); - - assert( - `[BUG] must pass <${angle}> component as first argument`, - component instanceof target - ); - - return component; - } - - private listenerFor( - this: DeprecatingInternalComponent, - event: string, - argument: string - ): Option { - assert(`[BUG] must be called with <${angle}> component as this`, this instanceof target); - - if (argument in this.args.named) { - deprecate( - `Passing the \`@${argument}\` argument to <${angle}> is deprecated. ` + - `This would have overwritten the internal \`${argument}\` method on ` + - `the <${angle}> component and prevented it from functioning properly. ` + - `Instead, please use the {{on}} modifier, i.e. \`<${angle} {{on "${event}" ...}} />\` ` + - `instead of \`<${angle} @${argument}={{...}} />\` or \`{{${curly} ${argument}=...}}\`.`, - !(argument in this), - { - id: 'ember.built-in-components.legacy-attribute-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-attribute-arguments', - } - ); - - deprecate( - `Passing the \`@${argument}\` argument to <${angle}> is deprecated. ` + - `Instead, please use the {{on}} modifier, i.e. \`<${angle} {{on "${event}" ...}} />\` ` + - `instead of \`<${angle} @${argument}={{...}} />\` or \`{{${curly} ${argument}=...}}\`.`, - argument in this, - { - id: 'ember.built-in-components.legacy-attribute-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-attribute-arguments', - } - ); - - return this['listenerFor'].call(this, argument); - } else { - return null; - } - } - } - - setInternalModifierManager( - new InternalModifierManager(DeprecatedEventHandlersModifier, 'deprecated-event-handlers'), - DeprecatedEventHandlersModifier - ); - - Object.defineProperty(prototype, 'handleDeprecatedEvents', { - configurable: true, - enumerable: true, - value: DeprecatedEventHandlersModifier, - }); - }; -} diff --git a/packages/@ember/-internals/glimmer/lib/components/link-to.ts b/packages/@ember/-internals/glimmer/lib/components/link-to.ts index cf3b4f5a39e..a3eeeef6586 100644 --- a/packages/@ember/-internals/glimmer/lib/components/link-to.ts +++ b/packages/@ember/-internals/glimmer/lib/components/link-to.ts @@ -1,10 +1,8 @@ import { Owner } from '@ember/-internals/owner'; import { RouterState, RoutingService } from '@ember/-internals/routing'; import { QueryParam } from '@ember/-internals/routing/lib/system/router'; -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 { assert, debugFreeze, warn } from '@ember/debug'; import { EngineInstance, getEngineParent } from '@ember/engine'; import { flaggedInstrument } from '@ember/instrumentation'; import { action } from '@ember/object'; @@ -13,16 +11,8 @@ import { DEBUG } from '@glimmer/env'; import { Maybe, Option } from '@glimmer/interfaces'; import { consumeTag, createCache, getValue, tagFor, untrack } from '@glimmer/validator'; import { Transition } from 'router_js'; -import Component from '../component'; import LinkToTemplate from '../templates/link-to'; -import LegacyLinkTo from './-link-to'; -import InternalComponent, { - DeprecatingInternalComponent, - handleDeprecatedArguments, - handleDeprecatedAttributeArguments, - handleDeprecatedEventArguments, - opaquify, -} from './internal'; +import InternalComponent, { opaquify } from './internal'; const EMPTY_ARRAY: {}[] = []; const EMPTY_QUERY_PARAMS = {}; @@ -47,13 +37,254 @@ function isQueryParams(value: unknown): value is QueryParams { return typeof value === 'object' && value !== null && value['isQueryParams'] === true; } -class LinkTo extends InternalComponent implements DeprecatingInternalComponent { +/** + The `LinkTo` component renders a link to the supplied `routeName` passing an optionally + supplied model to the route as its `model` context of the route. The block for `LinkTo` + becomes the contents of the rendered element: + + ```handlebars + + Great Hamster Photos + + ``` + + This will result in: + + ```html + + Great Hamster Photos + + ``` + + ### Disabling the `LinkTo` component + + The `LinkTo` component can be disabled by using the `disabled` argument. A disabled link + doesn't result in a transition when activated, and adds the `disabled` class to the `` + element. + + (The class name to apply to the element can be overridden by using the `disabledClass` + argument) + + ```handlebars + + Great Hamster Photos + + ``` + + ### Handling `href` + + `` will use your application's Router to fill the element's `href` property with a URL + that matches the path to the supplied `routeName`. + + ### Handling current route + + The `LinkTo` component will apply a CSS class name of 'active' when the application's current + route matches the supplied routeName. For example, if the application's current route is + 'photoGallery.recent', then the following invocation of `LinkTo`: + + ```handlebars + + Great Hamster Photos + + ``` + + will result in + + ```html + + Great Hamster Photos + + ``` + + The CSS class used for active classes can be customized by passing an `activeClass` argument: + + ```handlebars + + Great Hamster Photos + + ``` + + ```html + + Great Hamster Photos + + ``` + + ### Keeping a link active for other routes + + If you need a link to be 'active' even when it doesn't match the current route, you can use the + `current-when` argument. + + ```handlebars + + Photo Gallery + + ``` + + This may be helpful for keeping links active for: + + * non-nested routes that are logically related + * some secondary menu approaches + * 'top navigation' with 'sub navigation' scenarios + + A link will be active if `current-when` is `true` or the current + route is the route this link would transition to. + + To match multiple routes 'space-separate' the routes: + + ```handlebars + + Art Gallery + + ``` + + ### Supplying a model + + An optional `model` argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + Router.map(function() { + this.route("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + + {{aPhoto.title}} + + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + + For deep-linking to route paths that contain multiple + dynamic segments, the `models` argument can be used. + + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + Router.map(function() { + this.route("photoGallery", { path: "hamster-photos/:photo_id" }, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + + This argument will become the model context of the linked route: + + ```handlebars + + {{comment.body}} + + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + + If you don't have a model object available to pass to `LinkTo`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + Router.map(function() { + this.route("photoGallery", { path: "hamster-photos/:photo_id" }); + }); + ``` + + ```handlebars + + {{this.aPhoto.title}} + + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Supplying a `tagName` + + By default `` renders an `` element. This can be overridden for a single use of + `` by supplying a `tagName` argument: + + ```handlebars + + Great Hamster Photos + + ``` + + This produces: + + ```html +
  • + Great Hamster Photos +
  • + ``` + + In general, this is not recommended. + + ### Supplying query parameters + + If you need to add optional key-value pairs that appear to the right of the ? in a URL, + you can use the `query` argument. + + ```handlebars + + Great Hamster Photos + + ``` + + This will result in: + + ```html +
    + Great Hamster Photos + + ``` + + @for Ember.Templates.components + @method LinkTo + @see {LinkComponent} + @public +*/ + +/** + @module @ember/routing +*/ + +/** + See [Ember.Templates.components.LinkTo](/ember/release/classes/Ember.Templates.components/methods/input?anchor=LinkTo). + + @for Ember.Templates.helpers + @method link-to + @see {Ember.Templates.components.LinkTo} + @public +**/ + +class LinkTo extends InternalComponent { static toString(): string { return 'LinkTo'; } - modernized = this.shouldModernize(); - @service('-routing') private declare routing: RoutingService; validateArguments(): void { @@ -61,13 +292,12 @@ class LinkTo extends InternalComponent implements DeprecatingInternalComponent { 'You attempted to use the component within a routeless engine, this is not supported. ' + 'If you are using the ember-engines addon, use the component instead. ' + 'See https://ember-engines.com/docs/links for more info.', - !this.modernized || !this.isEngine || this.engineMountPoint !== undefined + !this.isEngine || this.engineMountPoint !== undefined ); assert( 'You must provide at least one of the `@route`, `@model`, `@models` or `@query` argument to ``.', - !this.modernized || - 'route' in this.args.named || + 'route' in this.args.named || 'model' in this.args.named || 'models' in this.args.named || 'query' in this.args.named @@ -338,15 +568,6 @@ class LinkTo extends InternalComponent implements DeprecatingInternalComponent { event.preventDefault(); } - private shouldModernize(): boolean { - return ( - Boolean(EMBER_MODERNIZED_BUILT_IN_COMPONENTS) && - Component._wasReopened === false && - TargetActionSupport._wasReopened === false && - LegacyLinkTo._wasReopened === false - ); - } - protected isSupportedArgument(name: string): boolean { let supportedArguments = [ 'route', @@ -365,413 +586,114 @@ class LinkTo extends InternalComponent implements DeprecatingInternalComponent { } } -// Deprecated features -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - let { prototype } = LinkTo; +let { prototype } = LinkTo; - let descriptorFor = (target: object, property: string): Option => { - if (target) { - return ( - Object.getOwnPropertyDescriptor(target, property) || - descriptorFor(Object.getPrototypeOf(target), property) - ); - } else { - return null; - } - }; - - handleDeprecatedArguments(LinkTo); - - handleDeprecatedAttributeArguments(LinkTo, [ - // Component - 'id', - ['id', 'elementId'], - 'class', - ['class', 'classNames'], - ['role', 'ariaRole'], - - // LinkTo - 'title', - 'rel', - 'tabindex', - 'target', - ]); - - handleDeprecatedEventArguments(LinkTo); - - // @href - { - let superOnUnsupportedArgument = prototype['onUnsupportedArgument']; - - Object.defineProperty(prototype, 'onUnsupportedArgument', { - configurable: true, - enumerable: false, - value: function onUnsupportedArgument(this: LinkTo, name: string): void { - if (name === 'href') { - assert(`Passing the \`@href\` argument to is not supported.`); - } else { - superOnUnsupportedArgument.call(this, name); - } - }, - }); - } - - // @tagName - { - let superOnUnsupportedArgument = prototype['onUnsupportedArgument']; - - Object.defineProperty(prototype, 'onUnsupportedArgument', { - configurable: true, - enumerable: false, - value: function onUnsupportedArgument(this: LinkTo, name: string): void { - if (name === 'tagName') { - let tagName = this.named('tagName'); - - deprecate( - `Passing the \`@tagName\` argument to is deprecated. Using a <${tagName}> ` + - 'element for navigation is not recommended as it creates issues with assistive ' + - 'technologies. Remove this argument to use the default element. In the rare ' + - 'cases that calls for using a different element, refactor to use the router ' + - 'service inside a custom event handler instead.', - false, - { - id: 'ember.link-to.tag-name', - for: 'ember-source', - since: {}, - until: '4.0.0', - } - ); - - this.modernized = false; - } else { - superOnUnsupportedArgument.call(this, name); - } - }, - }); - } - - // @bubbles & @preventDefault - { - let superIsSupportedArgument = prototype['isSupportedArgument']; - - Object.defineProperty(prototype, 'isSupportedArgument', { - configurable: true, - enumerable: false, - value: function isSupportedArgument(this: LinkTo, name: string): boolean { - if (this.modernized) { - if (name === 'bubbles') { - deprecate( - 'Passing the `@bubbles` argument to is deprecated. ' + - 'Use the {{on}} modifier to attach a custom event handler to ' + - 'control event propagation.', - false, - { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - } - ); - - return true; - } - - if (name === 'preventDefault') { - deprecate( - 'Passing the `@preventDefault` argument to is deprecated. ' + - '`preventDefault()` is called automatically on events that are ' + - 'handled by the component to prevent the browser from ' + - 'navigating away from the page.', - false, - { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - } - ); - - return true; - } - } - - return superIsSupportedArgument.call(this, name); - }, - }); - - Object.defineProperty(prototype, 'preventDefault', { - configurable: true, - enumerable: false, - value: function preventDefault(this: LinkTo, event: Event): void { - let shouldPreventDefault = true; - let shouldStopPropagation = false; - - if ('preventDefault' in this.args.named) { - let value = this.named('preventDefault'); - - if (isMissing(value) || value) { - deprecate( - 'Passing the `@preventDefault` argument to is deprecated. ' + - '`preventDefault()` is called automatically on events that are ' + - 'handled by the component to prevent the browser from ' + - 'navigating away from the page.', - false, - { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - } - ); - } else { - deprecate( - 'Passing the `@preventDefault` argument to is deprecated. ' + - '`preventDefault()` should always be called on events that are ' + - 'handled by the component to prevent the browser from ' + - 'navigating away from the page.', - false, - { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - } - ); - - shouldPreventDefault = false; - } - } - - if ('bubbles' in this.args.named) { - let value = this.named('bubbles'); - - if (value === false) { - deprecate( - 'Passing the `@bubbles` argument to is deprecated. ' + - 'Use the {{on}} modifier to attach a custom event handler to ' + - 'control event propagation.', - false, - { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - } - ); - - shouldStopPropagation = true; - } else { - deprecate( - 'Passing the `@bubbles` argument to is deprecated. ' + - '`stopPropagation()` is not automatically called so there is ' + - 'no need to pass this argument when you DO want the event to ' + - 'propagate normally', - false, - { - id: 'ember.built-in-components.legacy-arguments', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: - 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-legacy-arguments', - } - ); - } - } - - if (shouldPreventDefault) { - event.preventDefault(); - } - - if (shouldStopPropagation) { - event.stopPropagation(); - } - }, - }); - } - - // @disabledWhen - { - let superIsSupportedArgument = prototype['isSupportedArgument']; - - Object.defineProperty(prototype, 'isSupportedArgument', { - configurable: true, - enumerable: false, - value: function isSupportedArgument(this: LinkTo, name: string): boolean { - if (this.modernized) { - if (name === 'disabledWhen') { - deprecate( - 'Passing the `@disabledWhen` argument to is deprecated. ' + - 'Use the `@disabled` argument instead.', - false, - { - id: 'ember.link-to.disabled-when', - for: 'ember-source', - url: 'https://deprecations.emberjs.com/v4.x#toc_ember-link-to-disabled-when', - since: {}, - until: '4.0.0', - } - ); - - return true; - } - } - - return superIsSupportedArgument.call(this, name); - }, - }); - - let superDescriptor = descriptorFor(prototype, 'isDisabled'); - - assert( - `[BUG] expecting isDisabled to be a getter on `, - superDescriptor && typeof superDescriptor.get === 'function' +let descriptorFor = (target: object, property: string): Option => { + if (target) { + return ( + Object.getOwnPropertyDescriptor(target, property) || + descriptorFor(Object.getPrototypeOf(target), property) ); - - let superGetter = superDescriptor.get as (this: LinkTo) => boolean; - - Object.defineProperty(prototype, 'isDisabled', { - configurable: true, - enumerable: false, - get: function isDisabled(this: LinkTo): boolean { - if ('disabledWhen' in this.args.named) { - deprecate( - 'Passing the `@disabledWhen` argument to is deprecated. ' + - 'Use the `@disabled` argument instead.', - false, - { - id: 'ember.link-to.disabled-when', - for: 'ember-source', - url: 'https://deprecations.emberjs.com/v4.x#toc_ember-link-to-disabled-when', - since: {}, - until: '4.0.0', - } - ); - - return Boolean(this.named('disabledWhen')); - } - - return superGetter.call(this); - }, - }); + } else { + return null; } +}; + +// @href +{ + let superOnUnsupportedArgument = prototype['onUnsupportedArgument']; + + Object.defineProperty(prototype, 'onUnsupportedArgument', { + configurable: true, + enumerable: false, + value: function onUnsupportedArgument(this: LinkTo, name: string): void { + if (name === 'href') { + assert(`Passing the \`@href\` argument to is not supported.`); + } else { + superOnUnsupportedArgument.call(this, name); + } + }, + }); +} - // QP - { - let superModelsDescriptor = descriptorFor(prototype, 'models'); +// QP +{ + let superModelsDescriptor = descriptorFor(prototype, 'models'); - assert( - `[BUG] expecting models to be a getter on `, - superModelsDescriptor && typeof superModelsDescriptor.get === 'function' - ); + assert( + `[BUG] expecting models to be a getter on `, + superModelsDescriptor && typeof superModelsDescriptor.get === 'function' + ); - let superModelsGetter = superModelsDescriptor.get as (this: LinkTo) => {}[]; + let superModelsGetter = superModelsDescriptor.get as (this: LinkTo) => {}[]; - Object.defineProperty(prototype, 'models', { - configurable: true, - enumerable: false, - get: function models(this: LinkTo): {}[] { - let models = superModelsGetter.call(this); + Object.defineProperty(prototype, 'models', { + configurable: true, + enumerable: false, + get: function models(this: LinkTo): {}[] { + let models = superModelsGetter.call(this); - if (models.length > 0 && !('query' in this.args.named)) { - if (isQueryParams(models[models.length - 1])) { - models = models.slice(0, -1); - } + if (models.length > 0 && !('query' in this.args.named)) { + if (isQueryParams(models[models.length - 1])) { + models = models.slice(0, -1); } + } - return models; - }, - }); + return models; + }, + }); - let superQueryDescriptor = descriptorFor(prototype, 'query'); + let superQueryDescriptor = descriptorFor(prototype, 'query'); - assert( - `[BUG] expecting query to be a getter on `, - superQueryDescriptor && typeof superQueryDescriptor.get === 'function' - ); + assert( + `[BUG] expecting query to be a getter on `, + superQueryDescriptor && typeof superQueryDescriptor.get === 'function' + ); - let superQueryGetter = superQueryDescriptor.get as (this: LinkTo) => {}; + let superQueryGetter = superQueryDescriptor.get as (this: LinkTo) => {}; - Object.defineProperty(prototype, 'query', { - configurable: true, - enumerable: false, - get: function query(this: LinkTo): {} { - if ('query' in this.args.named) { - let qp = superQueryGetter.call(this); + Object.defineProperty(prototype, 'query', { + configurable: true, + enumerable: false, + get: function query(this: LinkTo): {} { + if ('query' in this.args.named) { + let qp = superQueryGetter.call(this); - if (isQueryParams(qp)) { - return qp.values ?? EMPTY_QUERY_PARAMS; - } else { - return qp; - } + if (isQueryParams(qp)) { + return qp.values ?? EMPTY_QUERY_PARAMS; } else { - let models = superModelsGetter.call(this); + return qp; + } + } else { + let models = superModelsGetter.call(this); - if (models.length > 0) { - let qp = models[models.length - 1]; + if (models.length > 0) { + let qp = models[models.length - 1]; - if (isQueryParams(qp) && qp.values !== null) { - return qp.values; - } + if (isQueryParams(qp) && qp.values !== null) { + return qp.values; } - - return EMPTY_QUERY_PARAMS; - } - }, - }); - } - - // Positional Arguments - { - let superValidateArguments = prototype['validateArguments']; - - Object.defineProperty(prototype, 'validateArguments', { - configurable: true, - enumerable: false, - value: function validateArguments(this: LinkTo): void { - if (this.args.positional.length !== 0 || 'params' in this.args.named) { - // Already deprecated in the legacy implementation - this.modernized = false; } - superValidateArguments.call(this); - }, - }); + return EMPTY_QUERY_PARAMS; + } + }, + }); +} - let superOnUnsupportedArgument = prototype['onUnsupportedArgument']; +// Positional Arguments +{ + let superOnUnsupportedArgument = prototype['onUnsupportedArgument']; - Object.defineProperty(prototype, 'onUnsupportedArgument', { - configurable: true, - enumerable: false, - value: function onUnsupportedArgument(this: LinkTo, name: string): void { - if (name !== 'params') { - superOnUnsupportedArgument.call(this, name); - } - }, - }); - } + Object.defineProperty(prototype, 'onUnsupportedArgument', { + configurable: true, + enumerable: false, + value: function onUnsupportedArgument(this: LinkTo, name: string): void { + if (name !== 'params') { + superOnUnsupportedArgument.call(this, name); + } + }, + }); } export default opaquify(LinkTo, LinkToTemplate); diff --git a/packages/@ember/-internals/glimmer/lib/components/text-field.ts b/packages/@ember/-internals/glimmer/lib/components/text-field.ts deleted file mode 100644 index a83a0f1c4b5..00000000000 --- a/packages/@ember/-internals/glimmer/lib/components/text-field.ts +++ /dev/null @@ -1,272 +0,0 @@ -/** -@module @ember/component -*/ -import { hasDOM } from '@ember/-internals/browser-environment'; -import { computed } from '@ember/-internals/metal'; -import { CoreObject } from '@ember/-internals/runtime'; -import { TextSupport } from '@ember/-internals/views'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; -import { deprecate } from '@ember/debug'; -import Component from '../component'; -import layout from '../templates/empty'; - -const inputTypes = hasDOM ? Object.create(null) : null; -function canSetTypeOfInput(type: string): boolean { - // if running in outside of a browser always return - // the original type - if (!hasDOM) { - return Boolean(type); - } - - if (type in inputTypes) { - return inputTypes[type]; - } - - let inputTypeTestElement = document.createElement('input'); - - try { - inputTypeTestElement.type = type; - } catch (e) { - // ignored - } - - return (inputTypes[type] = inputTypeTestElement.type === type); -} - -/** - The internal class used to create text inputs when the `Input` component is used with `type` of `text`. - - See [Ember.Templates.components.Input](/ember/release/classes/Ember.Templates.components/methods/Input?anchor=Input) for usage details. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. - - @class TextField - @extends Component - @uses Ember.TextSupport - @public -*/ -const TextField = Component.extend(TextSupport, { - layout, - - /** - By default, this component will add the `ember-text-field` class to the component's element. - - @property classNames - @type Array | String - @default ['ember-text-field'] - @public - */ - classNames: ['ember-text-field'], - tagName: 'input', - - /** - By default this component will forward a number of arguments to attributes on the the - component's element: - - * accept - * autocomplete - * autosave - * dir - * formaction - * formenctype - * formmethod - * formnovalidate - * formtarget - * height - * inputmode - * lang - * list - * type - * max - * min - * multiple - * name - * pattern - * size - * step - * value - * width - - When invoked with `{{input type="text"}}`, you can only customize these attributes. When invoked - with ``, you can just use HTML attributes directly. - - @property attributeBindings - @type Array | String - @default ['accept', 'autocomplete', 'autosave', 'dir', 'formaction', 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', 'height', 'inputmode', 'lang', 'list', 'type', 'max', 'min', 'multiple', 'name', 'pattern', 'size', 'step', 'value', 'width'] - @public - */ - attributeBindings: [ - 'accept', - 'autocomplete', - 'autosave', - 'dir', - 'formaction', - 'formenctype', - 'formmethod', - 'formnovalidate', - 'formtarget', - 'height', - 'inputmode', - 'lang', - 'list', - 'type', // needs to be before min and max. See #15675 - 'max', - 'min', - 'multiple', - 'name', - 'pattern', - 'size', - 'step', - 'value', - 'width', - ], - - /** - As the user inputs text, this property is updated to reflect the `value` property of the HTML - element. - - @property value - @type String - @default "" - @public - */ - value: '', - - /** - The `type` attribute of the input element. - - @property type - @type String - @default "text" - @public - */ - type: computed({ - get(): string { - return 'text'; - }, - - set(_key: string, value: string) { - let type = 'text'; - - if (canSetTypeOfInput(value)) { - type = value; - } - - return type; - }, - }), - - /** - The `size` of the text field in characters. - - @property size - @type String - @default null - @public - */ - size: null, - - /** - The `pattern` attribute of input element. - - @property pattern - @type String - @default null - @public - */ - pattern: null, - - /** - The `min` attribute of input element used with `type="number"` or `type="range"`. - - @property min - @type String - @default null - @since 1.4.0 - @public - */ - min: null, - - /** - The `max` attribute of input element used with `type="number"` or `type="range"`. - - @property max - @type String - @default null - @since 1.4.0 - @public - */ - max: null, -}); - -TextField.toString = () => '@ember/component/text-field'; - -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - Object.defineProperty(TextField, '_wasReopened', { - configurable: true, - enumerable: false, - writable: true, - value: false, - }); - - Object.defineProperty(TextField, 'reopen', { - configurable: true, - enumerable: false, - writable: true, - value: function reopen(this: typeof TextField, ...args: unknown[]): unknown { - if (this === TextField) { - deprecate( - 'Reopening Ember.TextField is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - TextField._wasReopened = true; - } - - return CoreObject.reopen.call(this, ...args); - }, - }); - - Object.defineProperty(TextField, 'reopenClass', { - configurable: true, - enumerable: false, - writable: true, - value: function reopenClass(this: typeof TextField, ...args: unknown[]): unknown { - if (this === TextField) { - deprecate( - 'Reopening Ember.TextField is deprecated. Consider implementing your own ' + - 'wrapper component or create a custom subclass.', - false, - { - id: 'ember.built-in-components.reopen', - for: 'ember-source', - since: { - enabled: '3.27.0', - }, - until: '4.0.0', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-built-in-components-reopen', - } - ); - - TextField._wasReopened = true; - } - - return CoreObject.reopenClass.call(this, ...args); - }, - }); -} - -export default TextField; diff --git a/packages/@ember/-internals/glimmer/lib/components/textarea.ts b/packages/@ember/-internals/glimmer/lib/components/textarea.ts index 3c38ee9332e..0a1e7d1833c 100644 --- a/packages/@ember/-internals/glimmer/lib/components/textarea.ts +++ b/packages/@ember/-internals/glimmer/lib/components/textarea.ts @@ -1,11 +1,9 @@ /** @module @ember/component */ -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import { action } from '@ember/object'; import TextareaTemplate from '../templates/textarea'; -import LegacyTextArea from './-textarea'; -import AbstractInput, { handleDeprecatedFeatures } from './abstract-input'; +import AbstractInput from './abstract-input'; import { opaquify } from './internal'; /** @@ -149,53 +147,10 @@ class Textarea extends AbstractInput { super.input(event); } - protected shouldModernize(): boolean { - return super.shouldModernize() && LegacyTextArea._wasReopened === false; - } - protected isSupportedArgument(name: string): boolean { let supportedArguments = ['type', 'value', 'enter', 'insert-newline', 'escape-press']; return supportedArguments.indexOf(name) !== -1 || super.isSupportedArgument(name); } } -// Deprecated features -if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - handleDeprecatedFeatures(Textarea, [ - // Component - 'id', - ['id', 'elementId'], - 'class', - ['class', 'classNames'], - ['role', 'ariaRole'], - - // TextSupport - 'autocapitalize', - 'autocorrect', - 'autofocus', - 'disabled', - 'form', - 'maxlength', - 'minlength', - 'placeholder', - 'readonly', - 'required', - 'selectionDirection', - 'spellcheck', - 'tabindex', - 'title', - - // TextField - 'rows', - 'cols', - 'name', - 'selectionEnd', - 'selectionStart', - 'autocomplete', - 'wrap', - 'lang', - 'dir', - ]); -} - export default opaquify(Textarea, TextareaTemplate); diff --git a/packages/@ember/-internals/glimmer/lib/helpers/query-param.ts b/packages/@ember/-internals/glimmer/lib/helpers/query-param.ts deleted file mode 100644 index 644e68847a5..00000000000 --- a/packages/@ember/-internals/glimmer/lib/helpers/query-param.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** -@module ember -*/ -import { QueryParams } from '@ember/-internals/routing'; -import { assert, deprecate } from '@ember/debug'; -import { CapturedArguments } from '@glimmer/interfaces'; -import { createComputeRef } from '@glimmer/reference'; -import { reifyNamed } from '@glimmer/runtime'; -import { internalHelper } from './internal-helper'; - -/** - This is a helper to be used in conjunction with the link-to helper. - It will supply url query parameters to the target route. - - @example In this example we are setting the `direction` query param to the value `"asc"` - - ```app/templates/application.hbs - - Sort - - ``` - - @method query-params - @for Ember.Templates.helpers - @param {Object} hash takes a hash of query parameters - @return {Object} A `QueryParams` object for `{{link-to}}` - @public -*/ -export default internalHelper(({ positional, named }: CapturedArguments) => { - return createComputeRef(() => { - assert( - "The `query-params` helper only accepts named arguments, e.g. (query-params queryParamPropertyName='foo') as opposed to (query-params 'foo')", - positional.length === 0 - ); - - deprecate( - 'The `query-params` helper is deprecated. Invoke `` with the `@query` named argument and the `hash` helper instead.', - false, - { - id: 'ember-glimmer.link-to.positional-arguments', - until: '4.0.0', - for: 'ember-source', - url: 'https://deprecations.emberjs.com/v3.x#toc_ember-glimmer-link-to-positional-arguments', - since: { - enabled: '3.26.0-beta.1', - }, - } - ); - - return new QueryParams(Object.assign({}, reifyNamed(named) as any)); - }); -}); diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts index e5e786210dc..d008910b1cd 100644 --- a/packages/@ember/-internals/glimmer/lib/resolver.ts +++ b/packages/@ember/-internals/glimmer/lib/resolver.ts @@ -46,7 +46,6 @@ import { default as trackArray } from './helpers/-track-array'; import { default as action } from './helpers/action'; import { default as eachIn } from './helpers/each-in'; import { default as mut } from './helpers/mut'; -import { default as queryParams } from './helpers/query-param'; import { default as readonly } from './helpers/readonly'; import { default as unbound } from './helpers/unbound'; import actionModifier from './modifiers/action'; @@ -115,7 +114,6 @@ const BUILTIN_KEYWORD_HELPERS = { mut, readonly, unbound, - 'query-params': queryParams, '-hash': hash, '-each-in': eachIn, '-normalize-class': normalizeClassHelper, diff --git a/packages/@ember/-internals/glimmer/lib/setup-registry.ts b/packages/@ember/-internals/glimmer/lib/setup-registry.ts index 4f1977fe5ba..ca3eaa85352 100644 --- a/packages/@ember/-internals/glimmer/lib/setup-registry.ts +++ b/packages/@ember/-internals/glimmer/lib/setup-registry.ts @@ -1,14 +1,9 @@ import { privatize as P, Registry } from '@ember/-internals/container'; import { ENV } from '@ember/-internals/environment'; import { getOwner } from '@ember/-internals/owner'; -import { EMBER_MODERNIZED_BUILT_IN_COMPONENTS } from '@ember/canary-features'; import Component from './component'; -import LegacyLinkTo from './components/-link-to'; -import LegacyTextArea from './components/-textarea'; -import Checkbox from './components/checkbox'; import Input from './components/input'; import LinkTo from './components/link-to'; -import TextField from './components/text-field'; import Textarea from './components/textarea'; import { clientBuilder, rehydrationBuilder, serializeBuilder } from './dom'; import { Renderer } from './renderer'; @@ -48,19 +43,10 @@ export function setupEngineRegistry(registry: Registry): void { registry.optionsForType('helper', { instantiate: false }); - registry.register('component:-text-field', TextField); - registry.register('component:-checkbox', Checkbox); registry.register('component:input', Input); - if (EMBER_MODERNIZED_BUILT_IN_COMPONENTS) { - registry.register('component:link-to', LinkTo); - registry.register('component:-link-to', LegacyLinkTo); - registry.register('component:-textarea', LegacyTextArea); - registry.register('component:textarea', Textarea); - } else { - registry.register('component:link-to', LegacyLinkTo); - registry.register('component:textarea', LegacyTextArea); - } + registry.register('component:link-to', LinkTo); + registry.register('component:textarea', Textarea); if (!ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS) { registry.register(P`component:-default`, Component); diff --git a/packages/@ember/-internals/glimmer/lib/templates/-link-to.d.ts b/packages/@ember/-internals/glimmer/lib/templates/-link-to.d.ts deleted file mode 100644 index 30e2f374432..00000000000 --- a/packages/@ember/-internals/glimmer/lib/templates/-link-to.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { TemplateFactory } from '@glimmer/interfaces'; -declare const TEMPLATE: TemplateFactory; -export default TEMPLATE; diff --git a/packages/@ember/-internals/glimmer/lib/templates/-link-to.hbs b/packages/@ember/-internals/glimmer/lib/templates/-link-to.hbs deleted file mode 100644 index e67d811c27e..00000000000 --- a/packages/@ember/-internals/glimmer/lib/templates/-link-to.hbs +++ /dev/null @@ -1,5 +0,0 @@ -{{~#if (has-block)~}} - {{yield}} -{{~else~}} - {{this.linkTitle}} -{{~/if~}} diff --git a/packages/@ember/-internals/glimmer/lib/templates/input.hbs b/packages/@ember/-internals/glimmer/lib/templates/input.hbs index eada41c6e5e..917d85a90f5 100644 --- a/packages/@ember/-internals/glimmer/lib/templates/input.hbs +++ b/packages/@ember/-internals/glimmer/lib/templates/input.hbs @@ -1,68 +1,17 @@ -{{~#if this.modernized ~}} - -{{~else~}} - {{~#let (component '-checkbox') (component '-text-field') as |Checkbox TextField|~}} - {{~#if this.isCheckbox~}} - - {{~else~}} - - {{~/if~}} - {{~/let~}} -{{/if}} + {{on "change" this.change}} + {{on "input" this.input}} + {{on "keyup" this.keyUp}} + {{on "paste" this.valueDidChange}} + {{on "cut" this.valueDidChange}} +/> \ No newline at end of file diff --git a/packages/@ember/-internals/glimmer/lib/templates/link-to.hbs b/packages/@ember/-internals/glimmer/lib/templates/link-to.hbs index 9e018d66388..d8618e3668d 100644 --- a/packages/@ember/-internals/glimmer/lib/templates/link-to.hbs +++ b/packages/@ember/-internals/glimmer/lib/templates/link-to.hbs @@ -1,24 +1,18 @@ -{{~#if this.modernized~}} - {{yield}} -{{~else~}} - {{~#let (component '-link-to') as |LegacyLinkTo|~}} - {{yield}} - {{~/let~}} -{{~/if~}} + {{on 'click' this.click}} +>{{yield}} \ No newline at end of file diff --git a/packages/@ember/-internals/glimmer/lib/templates/textarea.hbs b/packages/@ember/-internals/glimmer/lib/templates/textarea.hbs index 103a4dcd9b6..a47d6bca457 100644 --- a/packages/@ember/-internals/glimmer/lib/templates/textarea.hbs +++ b/packages/@ember/-internals/glimmer/lib/templates/textarea.hbs @@ -1,49 +1,15 @@ -{{~#if this.modernized ~}} -