diff --git a/packages/ember-routing/lib/services/router.js b/packages/ember-routing/lib/services/router.js index e4c385e157f..e9894c99631 100644 --- a/packages/ember-routing/lib/services/router.js +++ b/packages/ember-routing/lib/services/router.js @@ -7,6 +7,24 @@ import { Service, readOnly } from 'ember-runtime'; +import { + get, + isEmpty +} from 'ember-metal'; +import { assign } from 'ember-utils'; +import RouterDSL from '../system/dsl'; + + +function shallowEqual(a, b) { + let k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; +} /** The Router service is the public API that provides component/view layer @@ -19,6 +37,7 @@ import { const RouterService = Service.extend({ currentRouteName: readOnly('router.currentRouteName'), currentURL: readOnly('router.currentURL'), + currentState: readOnly('router.currentState'), location: readOnly('router.location'), rootURL: readOnly('router.rootURL'), router: null, @@ -79,6 +98,51 @@ const RouterService = Service.extend({ */ urlFor(/* routeName, ...models, options */) { return this.router.generate(...arguments); + }, + + /** + Determines whether a route is active. + + @method urlFor + @param {String} routeName the name of the route + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @param {Object} [options] optional hash with a queryParams property + containing a mapping of query parameters + @return {String} the string representing the generated URL + @public + */ + isActive(/* routeName, ...models, options */) { + if (!this.router.isActive(...arguments)) { return false; } +debugger; + let { routeName, models, queryParams } = this._extractArguments(...arguments); + let emptyQueryParams = Object.keys(queryParams).length; + + if (!emptyQueryParams) { + let visibleQueryParams = {}; + assign(visibleQueryParams, queryParams); + + this.router._prepareQueryParams(routeName, models, visibleQueryParams); + return shallowEqual(visibleQueryParams, queryParams); + } + + return true; + }, + + _extractArguments(...args) { + let routeName; + let models; + let possibleQueryParams = args[args.length - 1]; + let queryParams = {}; + + if (possibleQueryParams && possibleQueryParams.hasOwnProperty('queryParams')) { + queryParams = args.pop().queryParams; + } + + routeName = args.shift(); + models = args; + + return { routeName, models, queryParams }; } }); diff --git a/packages/ember-routing/lib/system/router_state.js b/packages/ember-routing/lib/system/router_state.js index 446136de6b2..09a572348d2 100644 --- a/packages/ember-routing/lib/system/router_state.js +++ b/packages/ember-routing/lib/system/router_state.js @@ -8,6 +8,7 @@ export default EmberObject.extend({ routerJsState: null, isActiveIntent(routeName, models, queryParams, queryParamsMustMatch) { + debugger; let state = this.routerJsState; if (!this.routerJs.isActiveIntent(routeName, models, null, state)) { return false; } diff --git a/packages/ember/tests/routing/router_service_test/isActive_test.js b/packages/ember/tests/routing/router_service_test/isActive_test.js new file mode 100644 index 00000000000..aaa91f9cf0a --- /dev/null +++ b/packages/ember/tests/routing/router_service_test/isActive_test.js @@ -0,0 +1,243 @@ +import { + Controller, + inject, + String +} from 'ember-runtime'; +import { Component } from 'ember-glimmer'; +import { Route, NoneLocation } from 'ember-routing'; +import { + get, + set +} from 'ember-metal'; +import { + RouterTestCase, + moduleFor +} from 'internal-test-helpers'; + +import { EMBER_ROUTING_ROUTER_SERVICE } from 'ember/features'; + +if (EMBER_ROUTING_ROUTER_SERVICE) { + moduleFor('Router Service - isActive', class extends RouterTestCase { + ['@test RouterService#isActive returns true for simple route'](assert) { + assert.expect(1); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child'); + }) + .then(() => { + return this.routerService.transitionTo('parent.sister'); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.sister')); + }); + } + + ['@test RouterService#isActive returns true for simple route with dynamic segments'](assert) { + assert.expect(1); + + let dynamicModel = { id: 1 }; + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('dynamic', dynamicModel); + }) + .then(() => { + assert.ok(this.routerService.isActive('dynamic', dynamicModel)); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { + assert.expect(2); + + let queryParams = this.buildQueryParams({ sort: 'ASC' }); + + this.registerController('parent.child', Controller.extend({ + queryParams: ['sort'], + sort: 'ASC' + }) + ); + debugger; + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.child', queryParams)); + assert.notOk(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'DESC' }))); + }); + } + + ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { + assert.expect(1); + + let queryParams = this.buildQueryParams({ sort: ['ascending'] }); + + return this.visit('/') + .then(() => { + return this.routerService.transitionTo('parent.child', queryParams); + }) + .then(() => { + assert.ok(this.routerService.isActive('parent.child', this.buildQueryParams({ sort: 'descending' }))); + }); + } + + // ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: null }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + // assert.equal('/child', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: undefined }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('parent.child', queryParams); + + // assert.equal('/child', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: 'bar' }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1?foo=bar', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1?selectedItems[]=a&selectedItems[]=b&selectedItems[]=c', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: null }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { + // assert.expect(1); + + // let queryParams = buildQueryParams({ foo: undefined }); + + // return this.visit('/').then(() => { + // let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); + + // assert.equal('/dynamic/1', expectedURL); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path'](assert) { + // assert.expect(1); + + // let expectedURL; + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('parent.child'); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // assert.equal(expectedURL, this.routerService.get('currentURL')); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments'](assert) { + // assert.expect(1); + + // let expectedURL; + // let dynamicModel = { id: 1 }; + + // this.registerRoute('dynamic', Route.extend({ + // model() { + // return dynamicModel; + // } + // })); + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('dynamic', dynamicModel); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // assert.equal(expectedURL, this.routerService.get('currentURL')); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path with query params'](assert) { + // assert.expect(1); + + // let expectedURL; + // let actualURL; + // let queryParams = buildQueryParams({ foo: 'bar' }); + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('parent.child', queryParams); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + // assert.equal(expectedURL, actualURL); + // }); + // } + + // ['@test RouterService#urlFor correctly transitions to route via generated path with dynamic segments and query params'](assert) { + // assert.expect(1); + + // let expectedURL; + // let actualURL; + // let queryParams = buildQueryParams({ foo: 'bar' }); + // let dynamicModel = { id: 1 }; + + // this.registerRoute('dynamic', Route.extend({ + // model() { + // return dynamicModel; + // } + // })); + + // return this.visit('/') + // .then(() => { + // expectedURL = this.routerService.urlFor('dynamic', dynamicModel, queryParams); + + // return this.routerService.transitionTo(expectedURL); + // }) + // .then(() => { + // actualURL = `${this.routerService.get('currentURL')}?foo=bar`; + + // assert.equal(expectedURL, actualURL); + // }); + // } + }); +} diff --git a/packages/ember/tests/routing/router_service_test/urlFor_test.js b/packages/ember/tests/routing/router_service_test/urlFor_test.js index c17fcffa8e4..a0d8e74fd0b 100644 --- a/packages/ember/tests/routing/router_service_test/urlFor_test.js +++ b/packages/ember/tests/routing/router_service_test/urlFor_test.js @@ -3,7 +3,6 @@ import { inject, String } from 'ember-runtime'; -import { Component } from 'ember-glimmer'; import { Route, NoneLocation } from 'ember-routing'; import { get, @@ -26,12 +25,6 @@ function setupController(app, name) { }); } -function buildQueryParams(queryParams) { - return { - queryParams - }; -} - if (EMBER_ROUTING_ROUTER_SERVICE) { moduleFor('Router Service - urlFor', class extends RouterTestCase { ['@test RouterService#urlFor returns URL for simple route'](assert) { @@ -61,7 +54,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with basic query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -73,7 +66,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with array as query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + let queryParams = this.buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -85,7 +78,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with null query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: null }); + let queryParams = this.buildQueryParams({ foo: null }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -97,7 +90,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with undefined query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: undefined }); + let queryParams = this.buildQueryParams({ foo: undefined }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('parent.child', queryParams); @@ -109,7 +102,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and basic query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -121,7 +114,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and array as query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); + let queryParams = this.buildQueryParams({ selectedItems: ['a', 'b', 'c'] }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -133,7 +126,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and null query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: null }); + let queryParams = this.buildQueryParams({ foo: null }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -145,7 +138,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { ['@test RouterService#urlFor returns URL for simple route with dynamic segments and undefined query params'](assert) { assert.expect(1); - let queryParams = buildQueryParams({ foo: undefined }); + let queryParams = this.buildQueryParams({ foo: undefined }); return this.visit('/').then(() => { let expectedURL = this.routerService.urlFor('dynamic', { id: 1 }, queryParams); @@ -198,7 +191,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { let expectedURL; let actualURL; - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); return this.visit('/') .then(() => { @@ -218,7 +211,7 @@ if (EMBER_ROUTING_ROUTER_SERVICE) { let expectedURL; let actualURL; - let queryParams = buildQueryParams({ foo: 'bar' }); + let queryParams = this.buildQueryParams({ foo: 'bar' }); let dynamicModel = { id: 1 }; this.add('route:dynamic', Route.extend({ diff --git a/packages/internal-test-helpers/lib/test-cases/router.js b/packages/internal-test-helpers/lib/test-cases/router.js index 1beaa0519c3..4fc8488e4aa 100644 --- a/packages/internal-test-helpers/lib/test-cases/router.js +++ b/packages/internal-test-helpers/lib/test-cases/router.js @@ -17,4 +17,10 @@ export default class RouterTestCase extends ApplicationTestCase { get routerService() { return this.applicationInstance.lookup('service:router'); } + + buildQueryParams(queryParams) { + return { + queryParams + }; + } }