diff --git a/packages/ember-routing/lib/ext/controller.js b/packages/ember-routing/lib/ext/controller.js index bcb55374f48..cfabf635313 100644 --- a/packages/ember-routing/lib/ext/controller.js +++ b/packages/ember-routing/lib/ext/controller.js @@ -1,5 +1,7 @@ import { get } from 'ember-metal/property_get'; import ControllerMixin from 'ember-runtime/mixins/controller'; +import { prefixRouteNameArg } from 'ember-routing/utils'; +import isEnabled from 'ember-metal/features'; /** @module ember @@ -181,4 +183,16 @@ ControllerMixin.reopen({ } }); +if (isEnabled('ember-application-engines')) { + ControllerMixin.reopen({ + transitionToRoute(...args) { + return this._super.apply(this, prefixRouteNameArg(this, args)); + }, + + replaceRoute(...args) { + return this._super.apply(this, prefixRouteNameArg(this, args)); + } + }); +} + export default ControllerMixin; diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 812d3697642..f1489ea5100 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -27,7 +27,8 @@ import { import { stashParamNames, normalizeControllerQueryParams, - calculateCacheKey + calculateCacheKey, + prefixRouteNameArg } from 'ember-routing/utils'; import { getOwner } from 'container/owner'; import isEmpty from 'ember-metal/is_empty'; @@ -2262,38 +2263,6 @@ function deprecateQueryParamDefaultValuesSetOnController(controllerName, routeNa deprecate(`Configuring query parameter default values on controllers is deprecated. Please move the value for the property '${propName}' from the '${controllerName}' controller to the '${routeName}' route in the format: {queryParams: ${propName}: {defaultValue: }}`, false, { id: 'ember-routing.deprecate-query-param-default-values-set-on-controller', until: '3.0.0' }); } -/* - Returns an arguments array where the route name arg is prefixed based on the mount point - - @private -*/ -function prefixRouteNameArg(route, args) { - let routeName = args[0]; - let owner = getOwner(route); - let prefix = owner.mountPoint; - - // only alter the routeName if it's actually referencing a route. - if (owner.routable && typeof routeName === 'string') { - if (resemblesURL(routeName)) { - throw new EmberError('Route#transitionTo cannot be used for URLs. Please use the route name instead.'); - } else { - routeName = `${prefix}.${routeName}`; - args[0] = routeName; - } - } - - return args; -} - -/* - Check if a routeName resembles a url instead - - @private -*/ -function resemblesURL(str) { - return typeof str === 'string' && ( str === '' || str.charAt(0) === '/'); -} - if (isEnabled('ember-application-engines')) { Route.reopen({ replaceWith(...args) { @@ -2304,6 +2273,10 @@ if (isEnabled('ember-application-engines')) { return this._super.apply(this, prefixRouteNameArg(this, args)); }, + intermediateTransitionTo(...args) { + return this._super.apply(this, prefixRouteNameArg(this, args)); + }, + modelFor(_routeName, ...args) { let routeName; let owner = getOwner(this); diff --git a/packages/ember-routing/lib/utils.js b/packages/ember-routing/lib/utils.js index df5aa910a05..dff6bf999e3 100644 --- a/packages/ember-routing/lib/utils.js +++ b/packages/ember-routing/lib/utils.js @@ -1,5 +1,7 @@ import assign from 'ember-metal/assign'; import { get } from 'ember-metal/property_get'; +import { getOwner } from 'container/owner'; +import EmberError from 'ember-metal/error'; const ALL_PERIODS_REGEX = /\./g; @@ -165,3 +167,35 @@ function accumulateQueryParamDescriptors(_desc, accum) { accum[key] = tmp; } } + +/* + Check if a routeName resembles a url instead + + @private +*/ +function resemblesURL(str) { + return typeof str === 'string' && ( str === '' || str.charAt(0) === '/'); +} + +/* + Returns an arguments array where the route name arg is prefixed based on the mount point + + @private +*/ +export function prefixRouteNameArg(route, args) { + let routeName = args[0]; + let owner = getOwner(route); + let prefix = owner.mountPoint; + + // only alter the routeName if it's actually referencing a route. + if (owner.routable && typeof routeName === 'string') { + if (resemblesURL(routeName)) { + throw new EmberError('Route#transitionTo cannot be used for URLs. Please use the route name instead.'); + } else { + routeName = `${prefix}.${routeName}`; + args[0] = routeName; + } + } + + return args; +} diff --git a/packages/ember-routing/tests/ext/controller_test.js b/packages/ember-routing/tests/ext/controller_test.js new file mode 100644 index 00000000000..6a3b4453de6 --- /dev/null +++ b/packages/ember-routing/tests/ext/controller_test.js @@ -0,0 +1,33 @@ +import buildOwner from 'container/tests/test-helpers/build-owner'; +import Controller from 'ember-runtime/controllers/controller'; +import { setOwner } from 'container/owner'; +import isEnabled from 'ember-metal/features'; + +if (isEnabled('ember-application-engines')) { + QUnit.module('ember-routing/ext/controller'); + + QUnit.test('transitionToRoute considers an engine\'s mountPoint', function() { + expect(4); + + let router = { + transitionTo(route) { + return route; + } + }; + + let engineInstance = buildOwner({ + routable: true, + mountPoint: 'foo.bar' + }); + + let controller = Controller.create({ target: router }); + setOwner(controller, engineInstance); + + strictEqual(controller.transitionToRoute('application'), 'foo.bar.application', 'properly prefixes application route'); + strictEqual(controller.transitionToRoute('posts'), 'foo.bar.posts', 'properly prefixes child routes'); + throws(() => controller.transitionToRoute('/posts'), 'throws when trying to use a url'); + + let queryParams = {}; + strictEqual(controller.transitionToRoute(queryParams), queryParams, 'passes query param only transitions through'); + }); +} diff --git a/packages/ember-routing/tests/system/route_test.js b/packages/ember-routing/tests/system/route_test.js index 3f76fc3e62f..ef26e846310 100644 --- a/packages/ember-routing/tests/system/route_test.js +++ b/packages/ember-routing/tests/system/route_test.js @@ -412,4 +412,85 @@ if (isEnabled('ember-application-engines')) { strictEqual(route.modelFor('application'), applicationModel); strictEqual(route.modelFor('posts'), postsModel); }); + + QUnit.test('transitionTo considers an engine\'s mountPoint', function() { + expect(4); + + let router = { + transitionTo(route) { + return route; + } + }; + + let engineInstance = buildOwner({ + routable: true, + mountPoint: 'foo.bar' + }); + + let route = EmberRoute.create({ router }); + setOwner(route, engineInstance); + + strictEqual(route.transitionTo('application'), 'foo.bar.application', 'properly prefixes application route'); + strictEqual(route.transitionTo('posts'), 'foo.bar.posts', 'properly prefixes child routes'); + throws(() => route.transitionTo('/posts'), 'throws when trying to use a url'); + + let queryParams = {}; + strictEqual(route.transitionTo(queryParams), queryParams, 'passes query param only transitions through'); + }); + + QUnit.test('intermediateTransitionTo considers an engine\'s mountPoint', function() { + expect(4); + + let lastRoute; + let router = { + intermediateTransitionTo(route) { + lastRoute = route; + } + }; + + let engineInstance = buildOwner({ + routable: true, + mountPoint: 'foo.bar' + }); + + let route = EmberRoute.create({ router }); + setOwner(route, engineInstance); + + route.intermediateTransitionTo('application'); + strictEqual(lastRoute, 'foo.bar.application', 'properly prefixes application route'); + + route.intermediateTransitionTo('posts'); + strictEqual(lastRoute, 'foo.bar.posts', 'properly prefixes child routes'); + + throws(() => route.intermediateTransitionTo('/posts'), 'throws when trying to use a url'); + + let queryParams = {}; + route.intermediateTransitionTo(queryParams); + strictEqual(lastRoute, queryParams, 'passes query param only transitions through'); + }); + + QUnit.test('replaceWith considers an engine\'s mountPoint', function() { + expect(4); + + let router = { + replaceWith(route) { + return route; + } + }; + + let engineInstance = buildOwner({ + routable: true, + mountPoint: 'foo.bar' + }); + + let route = EmberRoute.create({ router }); + setOwner(route, engineInstance); + + strictEqual(route.replaceWith('application'), 'foo.bar.application', 'properly prefixes application route'); + strictEqual(route.replaceWith('posts'), 'foo.bar.posts', 'properly prefixes child routes'); + throws(() => route.replaceWith('/posts'), 'throws when trying to use a url'); + + let queryParams = {}; + strictEqual(route.replaceWith(queryParams), queryParams, 'passes query param only transitions through'); + }); }