Skip to content

Commit 99d53ac

Browse files
nateabelechristopherthielen
authored andcommitted
WIP
1 parent db5ee64 commit 99d53ac

16 files changed

+1811
-973
lines changed

files.js

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ routerFiles = {
44
'src/resolve.js',
55
'src/templateFactory.js',
66
'src/urlMatcherFactory.js',
7+
'src/transition.js',
78
'src/urlRouter.js',
89
'src/state.js',
910
'src/view.js',
@@ -16,6 +17,10 @@ routerFiles = {
1617
'test/testUtils.js'
1718
],
1819
test: [
20+
// 'test/stateSpec.js',
21+
// 'test/resolveSpec.js',
22+
// 'test/urlMatcherFactorySpec.js',
23+
// 'test/urlRouterSpec.js',
1924
'test/*Spec.js',
2025
'test/compat/matchers.js'
2126
],

sample/app/app.js

+16-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,20 @@ angular.module('uiRouterSample', [
2222
)
2323

2424
.config(
25-
[ '$stateProvider', '$urlRouterProvider',
26-
function ($stateProvider, $urlRouterProvider) {
25+
[ '$stateProvider', '$urlRouterProvider', '$urlMatcherFactoryProvider',
26+
function ($stateProvider, $urlRouterProvider, $urlMatcherFactoryProvider) {
27+
28+
$urlMatcherFactoryProvider.type('contact', ['contacts', function(contacts) {
29+
return {
30+
encode: function(contact) {
31+
return contact.id;
32+
},
33+
decode: function(id) {
34+
return contacts.get(id);
35+
},
36+
pattern: /[0-9]{1,4}/
37+
};
38+
}]);
2739

2840
/////////////////////////////
2941
// Redirects and Otherwise //
@@ -34,8 +46,8 @@ angular.module('uiRouterSample', [
3446

3547
// The `when` method says if the url is ever the 1st param, then redirect to the 2nd param
3648
// Here we are just setting up some convenience urls.
37-
.when('/c?id', '/contacts/:id')
38-
.when('/user/:id', '/contacts/:id')
49+
// .when('/c?id', '/contacts/:id')
50+
// .when('/user/:id', '/contacts/:id')
3951

4052
// If the url is ever invalid, e.g. '/asdf', then redirect to '/' aka the home state
4153
.otherwise('/');

sample/app/contacts/contacts.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ angular.module('uiRouterSample.contacts', [
55
.config(
66
[ '$stateProvider', '$urlRouterProvider',
77
function ($stateProvider, $urlRouterProvider) {
8+
89
$stateProvider
910
//////////////
1011
// Contacts //
@@ -95,7 +96,7 @@ angular.module('uiRouterSample.contacts', [
9596
// So its url will end up being '/contacts/{contactId:[0-9]{1,8}}'. When the
9697
// url becomes something like '/contacts/42' then this state becomes active
9798
// and the $stateParams object becomes { contactId: 42 }.
98-
url: '/{contactId:[0-9]{1,4}}',
99+
url: '/{contact:contact}',
99100

100101
// If there is more than a single ui-view in the parent template, or you would
101102
// like to target a ui-view from even higher up the state tree, you can use the
@@ -113,7 +114,7 @@ angular.module('uiRouterSample.contacts', [
113114
templateUrl: 'app/contacts/contacts.detail.html',
114115
controller: ['$scope', '$stateParams', 'utils',
115116
function ( $scope, $stateParams, utils) {
116-
$scope.contact = utils.findById($scope.contacts, $stateParams.contactId);
117+
$scope.contact = $stateParams.contact
117118
}]
118119
},
119120

src/resolve.js

+50-49
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,30 @@ function $Resolve( $q, $injector) {
3333
* <pre>
3434
* $resolve.resolve(invocables, locals, parent, self)
3535
* </pre>
36-
* but the former is more efficient (in fact `resolve` just calls `study`
36+
* but the former is more efficient (in fact `resolve` just calls `study`
3737
* internally).
3838
*
3939
* @param {object} invocables Invocable objects
4040
* @return {function} a function to pass in locals, parent and self
4141
*/
4242
this.study = function (invocables) {
4343
if (!isObject(invocables)) throw new Error("'invocables' must be an object");
44-
44+
4545
// Perform a topological sort of invocables to build an ordered plan
4646
var plan = [], cycle = [], visited = {};
47+
4748
function visit(value, key) {
49+
4850
if (visited[key] === VISIT_DONE) return;
49-
51+
5052
cycle.push(key);
53+
5154
if (visited[key] === VISIT_IN_PROGRESS) {
5255
cycle.splice(0, cycle.indexOf(key));
5356
throw new Error("Cyclic dependency: " + cycle.join(" -> "));
5457
}
5558
visited[key] = VISIT_IN_PROGRESS;
56-
59+
5760
if (isString(value)) {
5861
plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
5962
} else {
@@ -63,61 +66,59 @@ function $Resolve( $q, $injector) {
6366
});
6467
plan.push(key, value, params);
6568
}
66-
69+
6770
cycle.pop();
6871
visited[key] = VISIT_DONE;
6972
}
73+
7074
forEach(invocables, visit);
7175
invocables = cycle = visited = null; // plan is all that's required
72-
76+
7377
function isResolve(value) {
7478
return isObject(value) && value.then && value.$$promises;
7579
}
76-
80+
7781
return function (locals, parent, self) {
7882
if (isResolve(locals) && self === undefined) {
7983
self = parent; parent = locals; locals = null;
8084
}
8185
if (!locals) locals = NO_LOCALS;
82-
else if (!isObject(locals)) {
83-
throw new Error("'locals' must be an object");
84-
}
86+
else if (!isObject(locals)) throw new Error("'locals' must be an object");
87+
8588
if (!parent) parent = NO_PARENT;
86-
else if (!isResolve(parent)) {
87-
throw new Error("'parent' must be a promise returned by $resolve.resolve()");
88-
}
89-
89+
else if (!isResolve(parent)) throw new Error("'parent' must be a promise returned by $resolve.resolve()");
90+
9091
// To complete the overall resolution, we have to wait for the parent
9192
// promise and for the promise for each invokable in our plan.
9293
var resolution = $q.defer(),
9394
result = resolution.promise,
9495
promises = result.$$promises = {},
9596
values = extend({}, locals),
96-
wait = 1 + plan.length/3,
97+
wait = 1 + plan.length / 3,
9798
merged = false;
98-
99+
99100
function done() {
100101
// Merge parent values we haven't got yet and publish our own $$values
101102
if (!--wait) {
102-
if (!merged) merge(values, parent.$$values);
103+
if (!merged) merge(values, parent.$$values);
103104
result.$$values = values;
104105
result.$$promises = true; // keep for isResolve()
105106
delete result.$$inheritedValues;
106107
resolution.resolve(values);
107108
}
108109
}
109-
110+
110111
function fail(reason) {
111112
result.$$failure = reason;
112113
resolution.reject(reason);
113114
}
114-
115+
115116
// Short-circuit if parent has already failed
116117
if (isDefined(parent.$$failure)) {
117118
fail(parent.$$failure);
118119
return result;
119120
}
120-
121+
121122
if (parent.$$inheritedValues) {
122123
merge(values, parent.$$inheritedValues);
123124
}
@@ -135,13 +136,13 @@ function $Resolve( $q, $injector) {
135136
extend(promises, parent.$$promises);
136137
parent.then(done, fail);
137138
}
138-
139+
139140
// Process each invocable in the plan, but ignore any where a local of the same name exists.
140-
for (var i=0, ii=plan.length; i<ii; i+=3) {
141+
for (var i = 0, ii = plan.length; i < ii; i += 3) {
141142
if (locals.hasOwnProperty(plan[i])) done();
142-
else invoke(plan[i], plan[i+1], plan[i+2]);
143+
else invoke(plan[i], plan[i + 1], plan[i + 2]);
143144
}
144-
145+
145146
function invoke(key, invocable, params) {
146147
// Create a deferred for this invocation. Failures will propagate to the resolution as well.
147148
var invocation = $q.defer(), waitParams = 0;
@@ -176,65 +177,65 @@ function $Resolve( $q, $injector) {
176177
// Publish promise synchronously; invocations further down in the plan may depend on it.
177178
promises[key] = invocation.promise;
178179
}
179-
180+
180181
return result;
181182
};
182183
};
183-
184+
184185
/**
185186
* @ngdoc function
186187
* @name ui.router.util.$resolve#resolve
187188
* @methodOf ui.router.util.$resolve
188189
*
189190
* @description
190-
* Resolves a set of invocables. An invocable is a function to be invoked via
191-
* `$injector.invoke()`, and can have an arbitrary number of dependencies.
191+
* Resolves a set of invocables. An invocable is a function to be invoked via
192+
* `$injector.invoke()`, and can have an arbitrary number of dependencies.
192193
* An invocable can either return a value directly,
193-
* or a `$q` promise. If a promise is returned it will be resolved and the
194-
* resulting value will be used instead. Dependencies of invocables are resolved
194+
* or a `$q` promise. If a promise is returned it will be resolved and the
195+
* resulting value will be used instead. Dependencies of invocables are resolved
195196
* (in this order of precedence)
196197
*
197198
* - from the specified `locals`
198199
* - from another invocable that is part of this `$resolve` call
199-
* - from an invocable that is inherited from a `parent` call to `$resolve`
200+
* - from an invocable that is inherited from a `parent` call to `$resolve`
200201
* (or recursively
201202
* - from any ancestor `$resolve` of that parent).
202203
*
203-
* The return value of `$resolve` is a promise for an object that contains
204+
* The return value of `$resolve` is a promise for an object that contains
204205
* (in this order of precedence)
205206
*
206207
* - any `locals` (if specified)
207208
* - the resolved return values of all injectables
208209
* - any values inherited from a `parent` call to `$resolve` (if specified)
209210
*
210-
* The promise will resolve after the `parent` promise (if any) and all promises
211-
* returned by injectables have been resolved. If any invocable
212-
* (or `$injector.invoke`) throws an exception, or if a promise returned by an
213-
* invocable is rejected, the `$resolve` promise is immediately rejected with the
214-
* same error. A rejection of a `parent` promise (if specified) will likewise be
215-
* propagated immediately. Once the `$resolve` promise has been rejected, no
211+
* The promise will resolve after the `parent` promise (if any) and all promises
212+
* returned by injectables have been resolved. If any invocable
213+
* (or `$injector.invoke`) throws an exception, or if a promise returned by an
214+
* invocable is rejected, the `$resolve` promise is immediately rejected with the
215+
* same error. A rejection of a `parent` promise (if specified) will likewise be
216+
* propagated immediately. Once the `$resolve` promise has been rejected, no
216217
* further invocables will be called.
217-
*
218+
*
218219
* Cyclic dependencies between invocables are not permitted and will caues `$resolve`
219-
* to throw an error. As a special case, an injectable can depend on a parameter
220-
* with the same name as the injectable, which will be fulfilled from the `parent`
221-
* injectable of the same name. This allows inherited values to be decorated.
220+
* to throw an error. As a special case, an injectable can depend on a parameter
221+
* with the same name as the injectable, which will be fulfilled from the `parent`
222+
* injectable of the same name. This allows inherited values to be decorated.
222223
* Note that in this case any other injectable in the same `$resolve` with the same
223224
* dependency would see the decorated value, not the inherited value.
224225
*
225-
* Note that missing dependencies -- unlike cyclic dependencies -- will cause an
226-
* (asynchronous) rejection of the `$resolve` promise rather than a (synchronous)
226+
* Note that missing dependencies -- unlike cyclic dependencies -- will cause an
227+
* (asynchronous) rejection of the `$resolve` promise rather than a (synchronous)
227228
* exception.
228229
*
229-
* Invocables are invoked eagerly as soon as all dependencies are available.
230+
* Invocables are invoked eagerly as soon as all dependencies are available.
230231
* This is true even for dependencies inherited from a `parent` call to `$resolve`.
231232
*
232-
* As a special case, an invocable can be a string, in which case it is taken to
233-
* be a service name to be passed to `$injector.get()`. This is supported primarily
234-
* for backwards-compatibility with the `resolve` property of `$routeProvider`
233+
* As a special case, an invocable can be a string, in which case it is taken to
234+
* be a service name to be passed to `$injector.get()`. This is supported primarily
235+
* for backwards-compatibility with the `resolve` property of `$routeProvider`
235236
* routes.
236237
*
237-
* @param {object} invocables functions to invoke or
238+
* @param {object} invocables functions to invoke or
238239
* `$injector` services to fetch.
239240
* @param {object} locals values to make available to the injectables
240241
* @param {object} parent a promise returned by another call to `$resolve`.

0 commit comments

Comments
 (0)