Last active
June 10, 2016 20:53
-
-
Save tim-evans/d9e07256baaa8d61944205a66a29336b to your computer and use it in GitHub Desktop.
Router Service RFC polyfill
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
const { get, observer } = Ember; | |
/** | |
Returns whether a route is currently active | |
Example: | |
```handlebars | |
<li class="{{if (is-active 'blog.post') 'active'}}"> | |
{{link-to post.name "blog.post" post}} | |
</li> | |
``` | |
```handlebars | |
<li class="{{if (is-active 'blog.posts' (query-params page=1)) 'active'}}"> | |
{{link-to post.name "blog.posts" (query-params page=1)}} | |
</li> | |
``` | |
@public | |
@method is-active | |
@param {String} routeName The route name to check | |
@param {Object} ...models The context for the given route to be tested | |
@param {QueryParams} [queryParams] The query params to test against for the current route. | |
@return {Boolean} Whether the route is active | |
@for Helpers | |
*/ | |
export default Ember.Helper.extend({ | |
router: Ember.inject.service(), | |
compute([routeName, ...models], hash) { | |
let queryParams = models[models.length - 1]; | |
if (queryParams && queryParams.isQueryParams) { | |
queryParams = models.pop().values; | |
} else { | |
queryParams = null; | |
} | |
return get(this, 'router').isActive(routeName, ...models, queryParams); | |
}, | |
currentRouteChanged: observer('router.currentRoute', function () { | |
this.recompute(); | |
}) | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
const { get, set, getOwner } = Ember; | |
const { alias, reads } = Ember.computed; | |
/** | |
Polyfill for the [Router Service RFC](https://github.com/emberjs/rfcs/pull/95) | |
used here as a way to provide a boundary between Ember and other parts | |
of our apps. This boundary can be exploited to write tests that mock | |
out the router with a dummy object. | |
@class Router | |
@namespace Services | |
@public | |
*/ | |
export default Ember.Service.extend({ | |
init() { | |
let owner = getOwner ? getOwner(this) : this.container; | |
let router = owner.lookup('router:main'); | |
set(this, '_router', router); | |
router.on('didTransition', () => { | |
set(this, '_routeSegments', Ember.A(router.router.currentHandlerInfos)); | |
}); | |
// Set route segments on initialization of the router | |
if (router.router == null) { | |
let initRouterJs = router._initRouterJs; | |
router._initRouterJs = () => { | |
initRouterJs.call(router); | |
this.interceptRouterEvents(router.router); | |
} | |
} else { | |
this.interceptRouterEvents(router.router); | |
} | |
}, | |
/** | |
@private | |
Intercept router events and notify the service of any changes made. | |
*/ | |
interceptRouterEvents(router) { | |
set(this, '_routeSegments', Ember.A(router.currentHandlerInfos || [])); | |
let triggerEvent = router.triggerEvent; | |
router.triggerEvent = (...args) => { | |
let [handlerInfos, , [event]] = args; | |
triggerEvent.apply(router, args); | |
if (event === 'queryParamsDidChange') { | |
set(this, '_routeSegments', Ember.A(handlerInfos)); | |
} | |
}; | |
}, | |
/** | |
The `location` property determines the type of URL's that your | |
application will use. | |
The following location types are currently available: | |
* `history` - use the browser's history API to make the URLs look just like any standard URL | |
* `hash` - use `#` to separate the server part of the URL from the Ember part: `/blog/#/posts/new` | |
* `none` - do not store the Ember URL in the actual browser URL (mainly used for testing) | |
* `auto` - use the best option based on browser capabilites: `history` if possible, then `hash` if possible, otherwise `none` | |
Note: If using ember-cli, this value is defaulted to `auto` by the `locationType` setting of `/config/environment.js` | |
@property location | |
@default 'hash' | |
@see {Ember.Location} | |
@public | |
*/ | |
location: alias('_router.location'), | |
/** | |
Represents the URL of the root of the application, often '/'. This prefix is | |
assumed on all routes defined on this router. | |
@property rootURL | |
@default '/' | |
@public | |
*/ | |
rootURL: alias('_router.rootURL'), | |
/** | |
Represents the current route. This property is immutable, | |
and is updated by the service with every transition. | |
@method currentRouteName | |
@return {Object} The current route object, as a RouteInfo. | |
@public | |
*/ | |
currentRoute: reads('_routeSegments.lastObject'), | |
/** | |
Represents the current route name. | |
@method currentRouteName | |
@return {String} The current route name. | |
@public | |
*/ | |
currentRouteName: reads('currentRoute.name'), | |
/** | |
Represents the current URL. | |
@method currentURL | |
@return {String} The current URL. | |
@public | |
*/ | |
currentURL: reads('_router.url'), | |
/** | |
Returns the currently active route segment | |
for the model. | |
@method routeFor | |
@params {Object} model The model to test against | |
@params {Object} [conditions] Conditions to match | |
@params {Regex|String} [conditions.name] The name to check against. | |
@return {Object} The current route object, as a RouteInfo. | |
*/ | |
routeFor(model, conditions={}) { | |
return get(this, '_routeSegments').find(function (segment) { | |
let matches = segment.context === model; | |
if (matches && conditions.name) { | |
if (typeof conditions.name === 'string') { | |
matches = segment.name === conditions.name; | |
} else { | |
matches = conditions.name.test(segment.name); | |
} | |
} | |
return matches; | |
}); | |
}, | |
/** | |
Returns the name of the active route segment | |
for the model given. | |
@method routeNameFor | |
@params {Object} model The model to test against | |
@params {Object} [conditions] Conditions to match | |
@params {Regex|String} [conditions.name] The name to check against. | |
@return {String} The current name of the route segment for the model. | |
*/ | |
routeNameFor(model, conditions={}) { | |
let segment = this.routeFor(model, conditions); | |
return segment && segment.name; | |
}, | |
/** | |
This takes the same arguments as transitionTo, but | |
instead of initiating the transition it returns the | |
resulting URL as a string. | |
@method url | |
@param {String} routeName The route name to generate a URL for. | |
@param {Object} ...models The necessary context to provide to generate the URL. | |
@param {Object} queryParams Query parameters to append to the URL. | |
*/ | |
url(routeName, ...models /*, queryParams */) { | |
return get(this, '_router').generate(routeName, ...models, { queryParams: models.pop() }); | |
}, | |
/** | |
Determines if the supplied route is currently active. | |
@method isActive | |
@param {String} routeName The route name to check against. | |
@param {Object} ...models The context for the route. | |
@param {Object} queryParams Query parameters to test against. | |
@return {Boolean} | |
@public | |
*/ | |
isActive(routeName, ...models /*, queryParams */) { | |
return get(this, '_router').isActive(routeName, ...models, { queryParams: models.pop() }); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment