Skip to content

Commit 27fafbf

Browse files
committed
feat($transition): implement is() for matching
1 parent 8f885fd commit 27fafbf

File tree

2 files changed

+118
-9
lines changed

2 files changed

+118
-9
lines changed

src/transition.js

+35-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@ function $TransitionProvider() {
99

1010
var $transition = {}, events, stateMatcher = angular.noop, abstractKey = 'abstract';
1111

12+
function matchState(current, states) {
13+
var toMatch = angular.isArray(states) ? states : [states];
14+
15+
for (var i = 0; i < toMatch.length; i++) {
16+
var glob = GlobBuilder.fromString(toMatch[i]);
17+
18+
if ((glob && glob.matches(current.name)) || (!glob && toMatch[i] === current.name)) {
19+
return true;
20+
}
21+
}
22+
return false;
23+
}
24+
1225
// $transitionProvider.on({ from: "home", to: "somewhere.else" }, function($transition$, $http) {
1326
// // ...
1427
// });
@@ -78,6 +91,7 @@ function $TransitionProvider() {
7891
*/
7992
function Transition(fromState, fromParams, toState, toParams, options) {
8093
var transition = this; // Transition() object
94+
8195
// grab $transition's current path
8296
var toPath, fromPath = _fromPath; // Path() objects
8397
var retained, entering, exiting; // Path() objects
@@ -89,6 +103,12 @@ function $TransitionProvider() {
89103
};
90104
toState = states.to; fromState = states.from;
91105

106+
if (!toState || !fromState) {
107+
throw new Error("To or from state not valid for transition: " + angular.toJson({
108+
to: toState, from: fromState
109+
}));
110+
}
111+
92112
function isTargetStateValid() {
93113
var state = states.to;
94114

@@ -151,12 +171,14 @@ function $TransitionProvider() {
151171
var exitingElements = transition.exiting().slice(0).reverse().elements;
152172
var enteringElements = transition.entering().elements;
153173
var promiseChain = $q.when(true);
174+
154175
forEach(exitingElements, function(elem) {
155176
if (elem.state.onExit) {
156177
var nextStep = transitionStep(elem.state.onExit, fromPath.resolveContext(elem));
157178
promiseChain.then(nextStep);
158179
}
159180
});
181+
160182
forEach(enteringElements, function(elem) {
161183
var resolveContext = toPath.resolveContext(elem);
162184
promiseChain.then(function() { return elem.resolve(resolveContext, { policy: "lazy" }); });
@@ -232,6 +254,17 @@ function $TransitionProvider() {
232254
}
233255
}),
234256

257+
is: function(compare) {
258+
if (compare instanceof Transition) {
259+
// TODO: Also compare parameters
260+
return this.is({ to: compare.to.$state().name, from: compare.from.$state().name });
261+
}
262+
return !(
263+
(compare.to && !matchState(this.to.$state(), compare.to)) ||
264+
(compare.from && !matchState(this.from.$state(), compare.from))
265+
);
266+
},
267+
235268
isValid: function() {
236269
return isTargetStateValid() === null && !hasBeenSuperseded();
237270
},
@@ -343,8 +376,8 @@ function $TransitionProvider() {
343376
};
344377

345378
$transition.start = function start(state, params, options) {
346-
to = { state: state, params: params };
347-
return new Transition(from.state, from.params, state, params, options || {});
379+
to = { state: state, params: params || {} };
380+
return new Transition(from.state, from.params, state, params || {}, options || {});
348381
};
349382

350383
$transition.isActive = function isActive() {

test/transitionSpec.js

+83-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,55 @@
1-
describe('$transition:', function () {
1+
describe('transition', function () {
2+
3+
var transitionProvider, root = { name: "", path: [] }, matcher, matchStates = {
4+
"": root,
5+
"first": { name: "first", path: [root] },
6+
"second": { name: "second", path: [root] },
7+
"third": { name: "third", path: [root] }
8+
};
9+
10+
describe('provider', function() {
11+
12+
beforeEach(module('ui.router', function($transitionProvider) {
13+
transitionProvider = $transitionProvider;
14+
}));
15+
16+
beforeEach(inject(function($transition) {
17+
matcher = new StateMatcher(matchStates);
18+
19+
$transition.init(root, {}, function(ref, options) {
20+
return matcher.find(ref, options.relative);
21+
});
22+
}));
23+
24+
describe('events', function() {
25+
26+
it('should fire matching "on" events regardless of outcome', inject(function($transition) {
27+
var t = null;
28+
29+
transitionProvider.on({ from: "first", to: "second" }, function($transition$) {
30+
t = $transition$;
31+
});
32+
33+
$transition.init(matchStates.first, {}, function(ref, options) {
34+
return matcher.find(ref, options.relative);
35+
});
36+
37+
$transition.start("third");
38+
expect(t).toBeNull();
39+
40+
$transition.start("second");
41+
expect(t).not.toBeNull();
42+
}));
43+
44+
});
45+
});
46+
47+
248
var statesTree, statesMap = {};
349
var emptyPath;
450
var counts;
551
var asyncCount;
652

7-
8-
953
beforeEach(module('ui.router', function($stateProvider, $locationProvider) {
1054
locationProvider = $locationProvider;
1155
$locationProvider.html5Mode(false);
@@ -74,10 +118,42 @@ describe('$transition:', function () {
74118
return new Path(map(names, function(name) { return statesMap[name]; }));
75119
}
76120

77-
describe('Transition().runAsync', function () {
78-
it('should resolve all resolves in a PathElement', inject(function ($q, $state) {
79-
$state.go("B");
80-
$q.flush();
121+
describe('instance', function() {
122+
beforeEach(inject(function($transition) {
123+
matcher = new StateMatcher(matchStates);
124+
125+
$transition.init(root, {}, function(ref, options) {
126+
return matcher.find(ref, options.relative);
127+
});
81128
}));
129+
130+
describe('is', function() {
131+
it('should match rules', inject(function($transition) {
132+
var t = $transition.start("first");
133+
134+
expect(t.is({ to: "first" })).toBe(true);
135+
expect(t.is({ from: "" })).toBe(true);
136+
expect(t.is({ to: "first", from: "" })).toBe(true);
137+
138+
expect(t.is({ to: ["first", "second"] })).toBe(true);
139+
expect(t.is({ to: ["first", "second"], from: ["", "third"] })).toBe(true);
140+
expect(t.is({ to: "first", from: "**" })).toBe(true);
141+
142+
expect(t.is({ to: "second" })).toBe(false);
143+
expect(t.is({ from: "first" })).toBe(false);
144+
expect(t.is({ to: "first", from: "second" })).toBe(false);
145+
146+
expect(t.is({ to: ["", "third"] })).toBe(false);
147+
expect(t.is({ to: "**", from: "first" })).toBe(false);
148+
}));
149+
});
150+
151+
describe('runAsync', function () {
152+
it('should resolve all resolves in a PathElement', inject(function ($q, $state) {
153+
$state.go("B");
154+
$q.flush();
155+
}));
156+
});
82157
});
158+
83159
});

0 commit comments

Comments
 (0)