Skip to content

Commit

Permalink
feat: add support for a canActivate method per route
Browse files Browse the repository at this point in the history
  • Loading branch information
troch committed Jul 20, 2015
1 parent 535f98c commit 424c987
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 8 deletions.
43 changes: 36 additions & 7 deletions modules/Router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export default class Router5 {
this.started = false
this._cbs = {}
this._cmps = {}
this._canAct = {}
this.lastStateAttempt = null
this.lastKnownState = null
this.rootNode = routes instanceof RouteNode ? routes : new RouteNode('', '', routes)
Expand Down Expand Up @@ -57,12 +58,18 @@ export default class Router5 {

/**
* Add a route to the router.
* @param {String} name The route name
* @param {String} path The route path
* @return {Router5} The Router5 instance
* @param {String} name The route name
* @param {String} path The route path
* @param {Function} canActivate A function to determine if the route can be activated.
* It will be invoked during a transition with `toState`
* and `fromState` parameters.
* @return {Router5} The Router5 instance
*/
addNode(name, path) {
this.rootNode.addNode(name, path)
addNode(name, path, canActivate) {
try {
this.rootNode.addNode(name, path)
this._canAct[name] = canActivate
} catch (e) {}
return this
}

Expand Down Expand Up @@ -279,6 +286,19 @@ export default class Router5 {
delete this._cmps[name]
}

/**
* [registerCanActivate description]
* @param {String} name The route name to register the canActivate method for
* @param {Function} canActivate The canActivate function. It should return `true`, `false`
* or a promise
* @return {Router5} The router instance
*/
canActivate(name, canActivate) {
if (this._canAct[name]) console.warn(`A canActivate was alread registered for route node ${name}.`)
this._canAct[name] = canActivate
return this
}

/**
* @private
*/
Expand Down Expand Up @@ -334,6 +354,7 @@ export default class Router5 {

let i
let cannotDeactivate = false
let cannotActivate = false
let fromStateIds = nameToIDs(fromState.name)
let toStateIds = nameToIDs(toState.name)
let maxI = Math.min(fromStateIds.length, toStateIds.length)
Expand All @@ -348,14 +369,22 @@ export default class Router5 {
.filter(comp => comp && comp.canDeactivate)
.some(comp => !comp.canDeactivate(toState, fromState))

if (!cannotDeactivate) {

if (!cannotDeactivate) {
cannotActivate = toStateIds.slice(i)
.map(id => this._canAct[id])
.filter(canAct => canAct)
.some(canAct => !canAct(toState, fromState))
}

if (!cannotDeactivate && !cannotActivate) {
this.lastKnownState = toState
this._invokeListeners('^' + (i > 0 ? fromStateIds[i - 1] : ''), toState, fromState)
this._invokeListeners('=' + toState.name, toState, fromState)
this._invokeListeners('*', toState, fromState)
}

return !cannotDeactivate
return !cannotDeactivate && !cannotActivate
}

/**
Expand Down
9 changes: 8 additions & 1 deletion tests/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ router = new Router5([
.setOption('useHash', true)
.setOption('hashPrefix', '!')
.add(ordersRoute)
.addNode('home', '/home');
.addNode('home', '/home')
.addNode('admin', '/admin', function () { return false; });

describe('router5', function () {
it('should throw an error if Router5 is not used as a constructor', function () {
Expand Down Expand Up @@ -242,5 +243,11 @@ describe('router5', function () {
expect(router.isActive('section.view', {section: 'section1', id: 123})).toBe(false);
expect(router.isActive('users.view', {id: 123})).toBe(false);
});

it('should block navigation if a route cannot be activated', function () {
router.navigate('home');
router.navigate('admin');
expect(router.isActive('home')).toBe(true);
});
});

0 comments on commit 424c987

Please sign in to comment.