From c8bdb32ae2ce93e44ebcb1c4ccc885225aef22b2 Mon Sep 17 00:00:00 2001 From: Nathan Hammond Date: Fri, 21 Aug 2015 15:12:55 -0700 Subject: [PATCH] [BUGFIX beta] Make link-to a real component. --- .../node-managers/component-node-manager.js | 10 ++++++--- .../lib/keywords/link-to.js | 21 +++++++------------ .../tests/helpers/link-to_test.js | 13 ++++++++++++ .../ember-routing-views/lib/views/link.js | 12 +++++++---- packages/ember-views/lib/system/link-to.js | 5 +++++ 5 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 packages/ember-views/lib/system/link-to.js diff --git a/packages/ember-htmlbars/lib/node-managers/component-node-manager.js b/packages/ember-htmlbars/lib/node-managers/component-node-manager.js index 0bcb011be41..1cbec43cc79 100644 --- a/packages/ember-htmlbars/lib/node-managers/component-node-manager.js +++ b/packages/ember-htmlbars/lib/node-managers/component-node-manager.js @@ -6,6 +6,7 @@ import { get } from 'ember-metal/property_get'; import { set } from 'ember-metal/property_set'; import setProperties from 'ember-metal/set_properties'; import { MUTABLE_CELL } from 'ember-views/compat/attrs-proxy'; +import { HAS_BLOCK } from 'ember-views/system/link-to'; import { instrument } from 'ember-htmlbars/system/instrumentation-support'; import LegacyEmberComponent from 'ember-views/components/component'; import GlimmerComponent from 'ember-htmlbars/glimmer-component'; @@ -45,7 +46,10 @@ ComponentNodeManager.create = function(renderNode, env, options) { component = component || (isAngleBracket ? GlimmerComponent : LegacyEmberComponent); - let createOptions = { parentView }; + let createOptions = { + parentView, + [HAS_BLOCK]: !!templates.default + }; configureTagName(attrs, tagName, component, isAngleBracket, createOptions); @@ -65,8 +69,8 @@ ComponentNodeManager.create = function(renderNode, env, options) { // Instantiate the component component = createComponent(component, isAngleBracket, createOptions, renderNode, env, attrs); - // If the component specifies its template via the `layout properties - // instead of using the template looked up in the container, get them + // If the component specifies its layout via the `layout` property + // instead of using the template looked up in the container, get it // now that we have the component instance. layout = get(component, 'layout') || layout; diff --git a/packages/ember-routing-htmlbars/lib/keywords/link-to.js b/packages/ember-routing-htmlbars/lib/keywords/link-to.js index 8ee162ce0a2..26097642f2a 100644 --- a/packages/ember-routing-htmlbars/lib/keywords/link-to.js +++ b/packages/ember-routing-htmlbars/lib/keywords/link-to.js @@ -3,9 +3,8 @@ @submodule ember-routing-htmlbars */ -import { readArray } from 'ember-metal/streams/utils'; import Ember from 'ember-metal/core'; // assert -import merge from 'ember-metal/merge'; +import { RELATED_VIEW } from 'ember-views/system/link-to'; /** The `{{link-to}}` helper renders a link to the supplied @@ -315,19 +314,13 @@ export default { }, render(morph, env, scope, params, hash, template, inverse, visitor) { - var attrs = merge({}, hash); - - // TODO: Rewrite link-to to use arbitrary length positional params. - attrs.params = readArray(params); - - // Used for deprecations (to tell the user what view the deprecated syntax - // was used in). - attrs.view = env.view; - - // TODO: Remove once `hasBlock` is working again - attrs.hasBlock = !!template; + Ember.runInDebug(() => { + // Used for deprecations (to tell the user what view the deprecated syntax was used in). + // Until: 3.0.0 + hash[RELATED_VIEW] = env.view; + }); - env.hooks.component(morph, env, scope, '-link-to', params, attrs, { default: template }, visitor); + env.hooks.component(morph, env, scope, '-link-to', params, hash, { default: template }, visitor); }, rerender(morph, env, scope, params, hash, template, inverse, visitor) { diff --git a/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js b/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js index 89c3dd294d1..c9e83b5dca4 100644 --- a/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js +++ b/packages/ember-routing-htmlbars/tests/helpers/link-to_test.js @@ -29,6 +29,7 @@ registry.register('service:-routing', EmberObject.extend({ registry.register('component-lookup:main', ComponentLookup); registry.register('component:-link-to', LinkComponent); +registry.register('component:custom-link-to', LinkComponent.extend()); QUnit.module('ember-routing-htmlbars: link-to helper', { setup() { @@ -145,3 +146,15 @@ QUnit.test('unwraps controllers', function() { equal(view.$().text(), 'Text'); }); + +QUnit.test('able to safely extend the built-in component and use the normal path', function() { + view = EmberView.create({ + title: 'my custom link-to component', + template: compile('{{custom-link-to view.title}}'), + container: container + }); + + runAppend(view); + + equal(view.$().text(), 'my custom link-to component', 'rendered a custom-link-to component'); +}); diff --git a/packages/ember-routing-views/lib/views/link.js b/packages/ember-routing-views/lib/views/link.js index 83b8cff1b73..05d4e3416e6 100644 --- a/packages/ember-routing-views/lib/views/link.js +++ b/packages/ember-routing-views/lib/views/link.js @@ -14,6 +14,7 @@ import EmberComponent from 'ember-views/components/component'; import inject from 'ember-runtime/inject'; import 'ember-runtime/system/service'; // creates inject.service import ControllerMixin from 'ember-runtime/mixins/controller'; +import { HAS_BLOCK, RELATED_VIEW } from 'ember-views/system/link-to'; import linkToTemplate from 'ember-htmlbars/templates/link-to'; linkToTemplate.meta.revision = 'Ember@VERSION_STRING_PLACEHOLDER'; @@ -365,7 +366,7 @@ var LinkComponent = EmberComponent.extend({ if (lastParam && lastParam.isQueryParams) { params.pop(); } - let onlyQueryParamsSupplied = (this.attrs.hasBlock ? params.length === 0 : params.length === 1); + let onlyQueryParamsSupplied = (this[HAS_BLOCK] ? params.length === 0 : params.length === 1); if (onlyQueryParamsSupplied) { var appController = this.container.lookup('controller:application'); if (appController) { @@ -416,8 +417,7 @@ var LinkComponent = EmberComponent.extend({ this.set('disabled', attrs.disabledWhen); } - // TODO: Change to built-in hasBlock once it's available - if (!attrs.hasBlock) { + if (!this[HAS_BLOCK]) { this.set('linkTitle', params.shift()); } @@ -431,7 +431,7 @@ var LinkComponent = EmberComponent.extend({ while (ControllerMixin.detect(value)) { Ember.deprecate( 'Providing `{{link-to}}` with a param that is wrapped in a controller is deprecated. ' + - 'Please update `' + attrs.view + '` to use `{{link-to "post" someController.model}}` instead.', + (attrs[RELATED_VIEW] ? 'Please update `' + attrs[RELATED_VIEW] + '` to use `{{link-to "post" someController.model}}` instead.' : ''), false, { id: 'ember-routing-views.controller-wrapped-param', until: '3.0.0' } ); @@ -503,4 +503,8 @@ function getResolvedQueryParams(queryParamsObject, targetRouteName) { return resolvedQueryParams; } +LinkComponent.reopenClass({ + positionalParams: 'params' +}); + export default LinkComponent; diff --git a/packages/ember-views/lib/system/link-to.js b/packages/ember-views/lib/system/link-to.js new file mode 100644 index 00000000000..d12ab6e8ebf --- /dev/null +++ b/packages/ember-views/lib/system/link-to.js @@ -0,0 +1,5 @@ +import { symbol } from 'ember-metal/utils'; + +// These symbols will be used to limit link-to's public API surface area. +export let HAS_BLOCK = symbol('HAS_BLOCK'); +export let RELATED_VIEW = symbol('RELATED_VIEW');