Skip to content

Commit

Permalink
feat($state): includes() allows glob patterns for state matching.
Browse files Browse the repository at this point in the history
  • Loading branch information
jhicken committed Feb 23, 2014
1 parent 8ab9778 commit 2d5f6b3
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 2 deletions.
67 changes: 65 additions & 2 deletions src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,41 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
return state;
}

// Checks text to see if it looks like a glob.
function isGlob (text) {
return text.indexOf('*') > -1;
}

// Returns true if glob matches current $state name.
function doesStateMatchGlob (glob) {
var globSegments = glob.split('.'),
segments = $state.$current.name.split('.');

//match greedy starts
if (globSegments[0] === '**') {
segments = segments.slice(segments.indexOf(globSegments[1]));
segments.unshift('**');
}
//match greedy ends
if (globSegments[globSegments.length - 1] === '**') {
segments.splice(segments.indexOf(globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);
segments.push('**');
}

if (globSegments.length != segments.length) {
return false;
}

//match single stars
for (var i = 0, l = globSegments.length; i < l; i++) {
if (globSegments[i] === '*') {
segments[i] = '*';
}
}

return segments.join('') === globSegments.join('');
}


// Implicit root state that is always active
root = registerState({
Expand Down Expand Up @@ -970,19 +1005,46 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
*
* @example
* <pre>
* $state.$current.name = 'contacts.details.item';
*
* $state.includes("contacts"); // returns true
* $state.includes("contacts.details"); // returns true
* $state.includes("contacts.details.item"); // returns true
* $state.includes("contacts.list"); // returns false
* $state.includes("about"); // returns false
* </pre>
*
* @param {string|object} stateOrName A full or partial state name to be searched for within the current state name.
* @param {object=} params A param object, e.g. `{sectionId: section.id}`,
* @description
* Basic globing patterns will also work.
*
* @example
* <pre>
* $state.$current.name = 'contacts.details.item.url';
*
* $state.includes("*.details.*.*"); // returns true
* $state.includes("*.details.**"); // returns true
* $state.includes("**.item.**"); // returns true
* $state.includes("*.details.item.url"); // returns true
* $state.includes("*.details.*.url"); // returns true
* $state.includes("*.details.*"); // returns false
* $state.includes("item.**"); // returns false
* </pre>
*
* @param {string} stateOrName A partial name to be searched for within the current state name.
* @param {object} params A param object, e.g. `{sectionId: section.id}`,
* that you'd like to test against the current active state.
* @returns {boolean} Returns true if it does include the state
*/

$state.includes = function includes(stateOrName, params) {
if (isString(stateOrName) && isGlob(stateOrName)) {
if (doesStateMatchGlob(stateOrName)) {
stateOrName = $state.$current.name;
} else {
return false;
}
}

var state = findState(stateOrName);
if (!isDefined(state)) {
return undefined;
Expand All @@ -1001,6 +1063,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
return validParams;
};


/**
* @ngdoc function
* @name ui.router.state.$state#href
Expand Down
15 changes: 15 additions & 0 deletions test/stateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,21 @@ describe('state', function () {
expect($state.includes('about.person', {person: 'bob'})).toBe(true);
expect($state.includes('about.person', {person: 'steve'})).toBe(false);
}));

it('should return true when the current state is passed with partial glob patterns', inject(function ($state, $q) {
$state.transitionTo('about.person.item', {person: 'bob', id: 5}); $q.flush();
expect($state.includes('*.person.*')).toBe(true);
expect($state.includes('*.person.**')).toBe(true);
expect($state.includes('**.item.*')).toBe(false);
expect($state.includes('**.item')).toBe(true);
expect($state.includes('**.stuff.*')).toBe(false);
expect($state.includes('*.*.*')).toBe(true);
expect($state.includes('about.*.*')).toBe(true);
expect($state.includes('about.**')).toBe(true);
expect($state.includes('*.about.*')).toBe(false);
expect($state.includes('about.*.*', {person: 'bob'})).toBe(true);
expect($state.includes('about.*.*', {person: 'shawn'})).toBe(false);
}));
});

describe('.current', function () {
Expand Down

0 comments on commit 2d5f6b3

Please sign in to comment.