Skip to content

Commit

Permalink
feat: improve isActive function (strict equality an option)
Browse files Browse the repository at this point in the history
  • Loading branch information
troch committed Jul 8, 2015
1 parent 4487359 commit 732816f
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 27 deletions.
48 changes: 41 additions & 7 deletions dist/browser/router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,13 @@ var RouteNode = (function () {

if (names.length === 1) {
this.children.push(route);
// Push greedy splats to the bottom of the pile
this.children.sort(function (childA, childB) {
return childA.hasSplatParam ? -1 : 1;
// Push greedy spats to the bottom of the pile
this.children.sort(function (a, b) {
if (!a.parser.hasSpatParam && b.parser.hasSpatParam) return -1;
if (!b.parser.hasSpatParam && a.parser.hasSpatParam) return 1;
if (!a.parser.hasUrlParams && b.parser.hasUrlParams) return -1;
if (!b.parser.hasUrlParams && a.parser.hasUrlParams) return 1;
return 0;
});
} else {
// Locate parent node
Expand Down Expand Up @@ -657,14 +661,44 @@ var Router5 = (function () {

/**
* Whether or not the given route name with specified params is active.
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @return {Boolean} Whether nor not the route is active
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @param {Boolean} [equality=false] If set to false (default), isActive will return true
* if the provided route name and params are descendants
* of the active state.
* @return {Boolean} Whether nor not the route is active
*/
value: function isActive(name) {
var params = arguments[1] === undefined ? {} : arguments[1];
var strictEquality = arguments[2] === undefined ? false : arguments[2];

return this.areStatesEqual(makeState(name, params), this.getState());
var activeState = this.getState();

if (!activeState) return false;

if (strictEquality || activeState.name === name) {
return this.areStatesEqual(makeState(name, params), activeState);
} else {
return this.areStatesDescendants(makeState(name, params), activeState);
}
}
}, {
key: 'areStatesDescendants',

/**
* Whether two states are descendants
* @param {Object} parentState The parent state
* @param {Object} childState The child state
* @return {Boolean} Whether the two provided states are related
*/
value: function areStatesDescendants(parentState, childState) {
var regex = new RegExp('^' + parentState.name + '\\.(.*)$');
if (!regex.test(childState.name)) return false;
// If child state name extends parent state name, and all parent state params
// are in child state params.
return Object.keys(parentState.params).every(function (p) {
return parentState.params[p] === childState.params[p];
});
}
}, {
key: 'getLocation',
Expand Down
2 changes: 1 addition & 1 deletion dist/browser/router5.min.js

Large diffs are not rendered by default.

38 changes: 34 additions & 4 deletions dist/commonjs/router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,44 @@ var Router5 = (function () {

/**
* Whether or not the given route name with specified params is active.
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @return {Boolean} Whether nor not the route is active
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @param {Boolean} [equality=false] If set to false (default), isActive will return true
* if the provided route name and params are descendants
* of the active state.
* @return {Boolean} Whether nor not the route is active
*/
value: function isActive(name) {
var params = arguments[1] === undefined ? {} : arguments[1];
var strictEquality = arguments[2] === undefined ? false : arguments[2];

return this.areStatesEqual(makeState(name, params), this.getState());
var activeState = this.getState();

if (!activeState) return false;

if (strictEquality || activeState.name === name) {
return this.areStatesEqual(makeState(name, params), activeState);
} else {
return this.areStatesDescendants(makeState(name, params), activeState);
}
}
}, {
key: 'areStatesDescendants',

/**
* Whether two states are descendants
* @param {Object} parentState The parent state
* @param {Object} childState The child state
* @return {Boolean} Whether the two provided states are related
*/
value: function areStatesDescendants(parentState, childState) {
var regex = new RegExp('^' + parentState.name + '\\.(.*)$');
if (!regex.test(childState.name)) return false;
// If child state name extends parent state name, and all parent state params
// are in child state params.
return Object.keys(parentState.params).every(function (p) {
return parentState.params[p] === childState.params[p];
});
}
}, {
key: 'getLocation',
Expand Down
38 changes: 34 additions & 4 deletions dist/umd/router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,44 @@

/**
* Whether or not the given route name with specified params is active.
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @return {Boolean} Whether nor not the route is active
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @param {Boolean} [equality=false] If set to false (default), isActive will return true
* if the provided route name and params are descendants
* of the active state.
* @return {Boolean} Whether nor not the route is active
*/
value: function isActive(name) {
var params = arguments[1] === undefined ? {} : arguments[1];
var strictEquality = arguments[2] === undefined ? false : arguments[2];

return this.areStatesEqual(makeState(name, params), this.getState());
var activeState = this.getState();

if (!activeState) return false;

if (strictEquality || activeState.name === name) {
return this.areStatesEqual(makeState(name, params), activeState);
} else {
return this.areStatesDescendants(makeState(name, params), activeState);
}
}
}, {
key: 'areStatesDescendants',

/**
* Whether two states are descendants
* @param {Object} parentState The parent state
* @param {Object} childState The child state
* @return {Boolean} Whether the two provided states are related
*/
value: function areStatesDescendants(parentState, childState) {
var regex = new RegExp('^' + parentState.name + '\\.(.*)$');
if (!regex.test(childState.name)) return false;
// If child state name extends parent state name, and all parent state params
// are in child state params.
return Object.keys(parentState.params).every(function (p) {
return parentState.params[p] === childState.params[p];
});
}
}, {
key: 'getLocation',
Expand Down
35 changes: 30 additions & 5 deletions modules/Router5.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,37 @@ export default class Router5 {

/**
* Whether or not the given route name with specified params is active.
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @return {Boolean} Whether nor not the route is active
* @param {String} name The route name
* @param {Object} [params={}] The route parameters
* @param {Boolean} [equality=false] If set to false (default), isActive will return true
* if the provided route name and params are descendants
* of the active state.
* @return {Boolean} Whether nor not the route is active
*/
isActive(name, params = {}) {
return this.areStatesEqual(makeState(name, params), this.getState())
isActive(name, params = {}, strictEquality = false) {
let activeState = this.getState()

if (!activeState) return false

if (strictEquality || activeState.name === name) {
return this.areStatesEqual(makeState(name, params), activeState)
} else {
return this.areStatesDescendants(makeState(name, params), activeState)
}
}

/**
* Whether two states are descendants
* @param {Object} parentState The parent state
* @param {Object} childState The child state
* @return {Boolean} Whether the two provided states are related
*/
areStatesDescendants(parentState, childState) {
let regex = new RegExp('^' + parentState.name + '\\.(.*)$')
if (!regex.test(childState.name)) return false
// If child state name extends parent state name, and all parent state params
// are in child state params.
return Object.keys(parentState.params).every(p => parentState.params[p] === childState.params[p])
}

/**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"homepage": "http://router5.github.io",
"dependencies": {
"route-node": "~0.1.0"
"route-node": "~0.1.1"
},
"devDependencies": {
"babel": "^5.6.14",
Expand Down
26 changes: 21 additions & 5 deletions tests/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var listeners = {
}
};

var userRoutes = new RouteNode('users', '/users', [
var usersRoute = new RouteNode('users', '/users', [
new RouteNode('view', '/view/:id'),
new RouteNode('list', '/list')
]);
Expand All @@ -21,8 +21,13 @@ var ordersRoute = new RouteNode('orders', '/orders', [
new RouteNode('completed', '/completed')
]);

var sectionRoute = new RouteNode('section', '/:section', [
new RouteNode('view', '/view/:id')
]);

router = new Router5([
userRoutes
usersRoute,
sectionRoute
], {
defaultRoute: 'home'
})
Expand All @@ -38,6 +43,7 @@ describe('router5', function () {
it('should start with the default route', function () {
expect(window.location.hash).toBe('');
expect(router.getState()).toEqual(null)
expect(router.isActive('home')).toEqual(false)

// Starting twice shouldn't do anything
router.start().start();
Expand Down Expand Up @@ -98,8 +104,13 @@ describe('router5', function () {
window.dispatchEvent(evt);

expect(router.getState()).toEqual(homeState);

router.navigate('users');
router.registerComponent('users', {canDeactivate: function () { return false; }});
// Nothing will happen
window.dispatchEvent(evt);
expect(router.getState()).not.toEqual(homeState);
router.deregisterComponent('users');
});

it('should be able to remove listeners', function () {
Expand Down Expand Up @@ -220,10 +231,15 @@ describe('router5', function () {
expect(router.isActive('users.view', {id: 1})).toBe(true);
expect(router.isActive('users.view', {id: 2})).toBe(false);
expect(router.isActive('users.view')).toBe(false);

router.navigate('users');
expect(router.isActive('users')).toBe(true);
expect(router.isActive('users', {})).toBe(true);
expect(router.isActive('users', {}, true)).toBe(false);

router.navigate('section.view', {section: 'section1', id: 12});
expect(router.isActive('section', {section: 'section1'})).toBe(true);
expect(router.isActive('section.view', {section: 'section1', id: 12})).toBe(true);
expect(router.isActive('section.view', {section: 'section2', id: 12})).toBe(false);
expect(router.isActive('section.view', {section: 'section1', id: 123})).toBe(false);
expect(router.isActive('users.view', {id: 123})).toBe(false);
});
});

0 comments on commit 732816f

Please sign in to comment.