Skip to content

Commit c32b981

Browse files
committed
Final implementation of relative state targeting.
1 parent 1a8d961 commit c32b981

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

src/state.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,27 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
108108

109109
function findState(stateOrName, base) {
110110
var isStr = isString(stateOrName),
111-
name = isStr ? stateOrName : stateOrName.name,
112-
path = isStr ? name.match(/^((?:(?:\^)(?:\.)?){1,})(.+)/) : null;
111+
name = isStr ? stateOrName : stateOrName.name,
112+
path = name.indexOf(".") === 0 || name.indexOf("^") === 0;
113113

114-
if (path && path.length) {
115-
if (!base) throw new Error("No reference point given for path '" + stateOrName + "'");
116-
var rel = path[1].split("."), i = 0, pathLength = rel.length - 1, current = base;
114+
if (path) {
115+
if (!base) throw new Error("No reference point given for path '" + name + "'");
116+
var rel = name.split("."), i = 0, pathLength = rel.length, current = base;
117117

118118
for (; i < pathLength; i++) {
119-
if (rel[i] === "^") current = current.parent;
120-
if (!current) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
119+
if (rel[i] === "" && i === 0) {
120+
current = base;
121+
continue;
122+
}
123+
if (rel[i] === "^") {
124+
if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'");
125+
current = current.parent;
126+
continue;
127+
}
128+
break;
121129
}
122-
name = current.name + "." + path[2];
130+
rel = rel.slice(i).join(".");
131+
name = current.name + (current.name && rel ? "." : "") + rel;
123132
}
124133
var state = states[name];
125134

test/stateSpec.js

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,18 +212,42 @@ describe('state', function () {
212212

213213
describe('.go()', function() {
214214
it('transitions to a relative state', inject(function ($state, $q) {
215-
$state.transitionTo('about.person.item', { id: 5 });
216-
$q.flush();
217-
$state.go('^.^.sidebar');
218-
$q.flush();
215+
$state.transitionTo('about.person.item', { id: 5 }); $q.flush();
216+
$state.go('^.^.sidebar'); $q.flush();
217+
expect($state.$current.name).toBe('about.sidebar');
218+
219+
// Transitions to absolute state
220+
$state.go("home"); $q.flush();
221+
expect($state.$current.name).toBe('home');
222+
223+
224+
// Transition to a child state
225+
$state.go(".item", { id: 5 }); $q.flush();
226+
expect($state.$current.name).toBe('home.item');
227+
228+
// Transition to grandparent's sibling through root
229+
// (Equivalent to absolute transition, assuming the root is known).
230+
$state.go("^.^.about"); $q.flush();
231+
expect($state.$current.name).toBe('about');
232+
233+
// Transition to grandchild
234+
$state.go(".person.item", { person: "bob", id: 13 }); $q.flush();
235+
expect($state.$current.name).toBe('about.person.item');
236+
237+
// Transition to immediate parent
238+
$state.go("^"); $q.flush();
239+
expect($state.$current.name).toBe('about.person');
240+
241+
// Transition to parent's sibling
242+
$state.go("^.sidebar"); $q.flush();
219243
expect($state.$current.name).toBe('about.sidebar');
220244
}));
221245

222246
it('keeps parameters from common ancestor states', inject(function ($state, $stateParams, $q) {
223247
$state.transitionTo('about.person', { person: 'bob' });
224248
$q.flush();
225249

226-
$state.go('^item', { id: 5 });
250+
$state.go('.item', { id: 5 });
227251
$q.flush();
228252

229253
expect($state.$current.name).toBe('about.person.item');

0 commit comments

Comments
 (0)