Skip to content

Commit ea03a14

Browse files
committedDec 6, 2013
release 0.2.6
1 parent 4602609 commit ea03a14

18 files changed

+1915
-156
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#### The de-facto solution to flexible routing with nested views
44
---
5-
**[Download 0.2.5](http://angular-ui.github.io/ui-router/release/angular-ui-router.js)** (or **[Minified](http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js)**) **|**
5+
**[Download 0.2.6](http://angular-ui.github.io/ui-router/release/angular-ui-router.js)** (or **[Minified](http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js)**) **|**
66
**[Learn](#resources) |**
77
**[Discuss](https://groups.google.com/forum/#!categories/angular-ui/router) |**
88
**[Get Help](http://stackoverflow.com/questions/ask?tags=angularjs,angular-ui-router) |**

‎bower.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-ui-router",
3-
"version": "0.2.5",
3+
"version": "0.2.6",
44
"main": "./release/angular-ui-router.js",
55
"dependencies": {
66
"angular": ">= 1.1.5"

‎component.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-ui-router",
3-
"version": "0.2.5",
3+
"version": "0.2.6",
44
"description": "State-based routing for AngularJS",
55
"keywords": [
66
"angular",

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "angular-ui-router",
33
"description": "State-based routing for AngularJS",
4-
"version": "0.2.5",
4+
"version": "0.2.6",
55
"homepage": "http://angular-ui.github.com/",
66
"contributors": [
77
{
@@ -52,7 +52,7 @@
5252
"karma-chrome-launcher": "~0.1.0",
5353
"karma-html2js-preprocessor": "~0.1.0",
5454
"karma-jasmine": "~0.1.3",
55-
"karma-requirejs": "~0.1.0",
55+
"karma-requirejs": "~0.2.0",
5656
"karma-script-launcher": "~0.1.0",
5757
"karma-coffee-preprocessor": "~0.1.0",
5858
"karma": "~0.10.4",

‎release/angular-ui-router.js

+141-57
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* State-based routing for AngularJS
3-
* @version v0.2.5
3+
* @version v0.2.6
44
* @link http://angular-ui.github.com/
55
* @license MIT License, http://www.opensource.org/licenses/MIT
66
*/
@@ -57,6 +57,24 @@ function ancestors(first, second) {
5757
return path;
5858
}
5959

60+
/**
61+
* IE8-safe wrapper for `Object.keys()`.
62+
*
63+
* @param {Object} object A JavaScript object.
64+
* @return {Array} Returns the keys of the object as an array.
65+
*/
66+
function keys(object) {
67+
if (Object.keys) {
68+
return Object.keys(object);
69+
}
70+
var result = [];
71+
72+
angular.forEach(object, function(val, key) {
73+
result.push(key);
74+
});
75+
return result;
76+
}
77+
6078
/**
6179
* IE8-safe wrapper for `Array.prototype.indexOf()`.
6280
*
@@ -104,6 +122,61 @@ function inheritParams(currentParams, newParams, $current, $to) {
104122
return extend({}, inherited, newParams);
105123
}
106124

125+
/**
126+
* Normalizes a set of values to string or `null`, filtering them by a list of keys.
127+
*
128+
* @param {Array} keys The list of keys to normalize/return.
129+
* @param {Object} values An object hash of values to normalize.
130+
* @return {Object} Returns an object hash of normalized string values.
131+
*/
132+
function normalize(keys, values) {
133+
var normalized = {};
134+
135+
forEach(keys, function (name) {
136+
var value = values[name];
137+
normalized[name] = (value != null) ? String(value) : null;
138+
});
139+
return normalized;
140+
}
141+
142+
/**
143+
* Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
144+
*
145+
* @param {Object} a The first object.
146+
* @param {Object} b The second object.
147+
* @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
148+
* it defaults to the list of keys in `a`.
149+
* @return {Boolean} Returns `true` if the keys match, otherwise `false`.
150+
*/
151+
function equalForKeys(a, b, keys) {
152+
if (!keys) {
153+
keys = [];
154+
for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
155+
}
156+
157+
for (var i=0; i<keys.length; i++) {
158+
var k = keys[i];
159+
if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
160+
}
161+
return true;
162+
}
163+
164+
/**
165+
* Returns the subset of an object, based on a list of keys.
166+
*
167+
* @param {Array} keys
168+
* @param {Object} values
169+
* @return {Boolean} Returns a subset of `values`.
170+
*/
171+
function filterByKeys(keys, values) {
172+
var filtered = {};
173+
174+
forEach(keys, function (name) {
175+
filtered[name] = values[name];
176+
});
177+
return filtered;
178+
}
179+
107180
angular.module('ui.router.util', ['ng']);
108181
angular.module('ui.router.router', ['ui.router.util']);
109182
angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
@@ -799,7 +872,7 @@ angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);
799872
$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider', '$locationProvider'];
800873
function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $locationProvider) {
801874

802-
var root, states = {}, $state, queue = {};
875+
var root, states = {}, $state, queue = {}, abstractKey = 'abstract';
803876

804877
// Builds state properties from definition passed to registerState()
805878
var stateBuilder = {
@@ -976,10 +1049,10 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
9761049
states[name] = state;
9771050

9781051
// Register the state in the global state list and with $urlRouter if necessary.
979-
if (!state['abstract'] && state.url) {
1052+
if (!state[abstractKey] && state.url) {
9801053
$urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
9811054
if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
982-
$state.transitionTo(state, $match, false);
1055+
$state.transitionTo(state, $match, { location: false });
9831056
}
9841057
}]);
9851058
}
@@ -1116,7 +1189,7 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
11161189
throw new Error("No such state '" + to + "'");
11171190
}
11181191
}
1119-
if (toState['abstract']) throw new Error("Cannot transition to abstract state '" + to + "'");
1192+
if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'");
11201193
if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState);
11211194
to = toState;
11221195

@@ -1286,13 +1359,13 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
12861359
return url;
12871360
};
12881361

1289-
$state.get = function (stateOrName) {
1362+
$state.get = function (stateOrName, context) {
12901363
if (!isDefined(stateOrName)) {
12911364
var list = [];
12921365
forEach(states, function(state) { list.push(state.self); });
12931366
return list;
12941367
}
1295-
var state = findState(stateOrName);
1368+
var state = findState(stateOrName, context);
12961369
return (state && state.self) ? state.self : null;
12971370
};
12981371

@@ -1344,39 +1417,6 @@ function $StateProvider( $urlRouterProvider, $urlMatcherFactory, $
13441417
return $state;
13451418
}
13461419

1347-
function normalize(keys, values) {
1348-
var normalized = {};
1349-
1350-
forEach(keys, function (name) {
1351-
var value = values[name];
1352-
normalized[name] = (value != null) ? String(value) : null;
1353-
});
1354-
return normalized;
1355-
}
1356-
1357-
function equalForKeys(a, b, keys) {
1358-
// If keys not provided, assume keys from object 'a'
1359-
if (!keys) {
1360-
keys = [];
1361-
for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
1362-
}
1363-
1364-
for (var i=0; i<keys.length; i++) {
1365-
var k = keys[i];
1366-
if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
1367-
}
1368-
return true;
1369-
}
1370-
1371-
function filterByKeys(keys, values) {
1372-
var filtered = {};
1373-
1374-
forEach(keys, function (name) {
1375-
filtered[name] = values[name];
1376-
});
1377-
return filtered;
1378-
}
1379-
13801420
function shouldTriggerReload(to, from, locals, options) {
13811421
if ( to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false)) ) {
13821422
return true;
@@ -1420,9 +1460,7 @@ angular.module('ui.router.state').provider('$view', $ViewProvider);
14201460

14211461
$ViewDirective.$inject = ['$state', '$compile', '$controller', '$injector', '$anchorScroll'];
14221462
function $ViewDirective( $state, $compile, $controller, $injector, $anchorScroll) {
1423-
// TODO: Change to $injector.has() when we version bump to Angular 1.1.5.
1424-
// See: https://github.com/angular/angular.js/blob/master/CHANGELOG.md#115-triangle-squarification-2013-05-22
1425-
var $animator; try { $animator = $injector.get('$animator'); } catch (e) { /* do nothing */ }
1463+
var $animator = $injector.has('$animator') ? $injector.get('$animator') : null;
14261464
var viewIsUpdating = false;
14271465

14281466
var directive = {
@@ -1435,7 +1473,7 @@ function $ViewDirective( $state, $compile, $controller, $injector, $an
14351473
var viewScope, viewLocals,
14361474
name = attr[directive.name] || attr.name || '',
14371475
onloadExp = attr.onload || '',
1438-
animate = isDefined($animator) && $animator(scope, attr),
1476+
animate = $animator && $animator(scope, attr),
14391477
initialView = transclude(scope);
14401478

14411479
// Returns a set of DOM manipulation functions based on whether animation
@@ -1543,22 +1581,25 @@ function parseStateRef(ref) {
15431581
return { state: parsed[1], paramExpr: parsed[3] || null };
15441582
}
15451583

1546-
$StateRefDirective.$inject = ['$state'];
1547-
function $StateRefDirective($state) {
1584+
function stateContext(el) {
1585+
var stateData = el.parent().inheritedData('$uiView');
1586+
1587+
if (stateData && stateData.state && stateData.state.name) {
1588+
return stateData.state;
1589+
}
1590+
}
1591+
1592+
$StateRefDirective.$inject = ['$state', '$timeout'];
1593+
function $StateRefDirective($state, $timeout) {
15481594
return {
15491595
restrict: 'A',
1550-
link: function(scope, element, attrs) {
1596+
require: '?^uiSrefActive',
1597+
link: function(scope, element, attrs, uiSrefActive) {
15511598
var ref = parseStateRef(attrs.uiSref);
1552-
var params = null, url = null, base = $state.$current;
1599+
var params = null, url = null, base = stateContext(element) || $state.$current;
15531600
var isForm = element[0].nodeName === "FORM";
15541601
var attr = isForm ? "action" : "href", nav = true;
15551602

1556-
var stateData = element.parent().inheritedData('$uiView');
1557-
1558-
if (stateData && stateData.state && stateData.state.name) {
1559-
base = stateData.state;
1560-
}
1561-
15621603
var update = function(newVal) {
15631604
if (newVal) params = newVal;
15641605
if (!nav) return;
@@ -1570,6 +1611,9 @@ function $StateRefDirective($state) {
15701611
return false;
15711612
}
15721613
element[0][attr] = newHref;
1614+
if (uiSrefActive) {
1615+
uiSrefActive.$$setStateInfo(ref.state, params);
1616+
}
15731617
};
15741618

15751619
if (ref.paramExpr) {
@@ -1586,8 +1630,11 @@ function $StateRefDirective($state) {
15861630
var button = e.which || e.button;
15871631

15881632
if ((button === 0 || button == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
1589-
scope.$evalAsync(function() {
1590-
$state.go(ref.state, params, { relative: base });
1633+
// HACK: This is to allow ng-clicks to be processed before the transition is initiated:
1634+
$timeout(function() {
1635+
scope.$apply(function() {
1636+
$state.go(ref.state, params, { relative: base });
1637+
});
15911638
});
15921639
e.preventDefault();
15931640
}
@@ -1596,7 +1643,44 @@ function $StateRefDirective($state) {
15961643
};
15971644
}
15981645

1599-
angular.module('ui.router.state').directive('uiSref', $StateRefDirective);
1646+
$StateActiveDirective.$inject = ['$state', '$stateParams', '$interpolate'];
1647+
function $StateActiveDirective($state, $stateParams, $interpolate) {
1648+
return {
1649+
restrict: "A",
1650+
controller: function($scope, $element, $attrs) {
1651+
var state, params, activeClass;
1652+
1653+
// There probably isn't much point in $observing this
1654+
activeClass = $interpolate($attrs.uiSrefActive || '', false)($scope);
1655+
1656+
// Allow uiSref to communicate with uiSrefActive
1657+
this.$$setStateInfo = function(newState, newParams) {
1658+
state = $state.get(newState, stateContext($element));
1659+
params = newParams;
1660+
update();
1661+
};
1662+
1663+
$scope.$on('$stateChangeSuccess', update);
1664+
1665+
// Update route state
1666+
function update() {
1667+
if ($state.$current.self === state && matchesParams()) {
1668+
$element.addClass(activeClass);
1669+
} else {
1670+
$element.removeClass(activeClass);
1671+
}
1672+
}
1673+
1674+
function matchesParams() {
1675+
return !params || equalForKeys(params, $stateParams);
1676+
}
1677+
}
1678+
};
1679+
}
1680+
1681+
angular.module('ui.router.state')
1682+
.directive('uiSref', $StateRefDirective)
1683+
.directive('uiSrefActive', $StateActiveDirective);
16001684

16011685
$RouteProvider.$inject = ['$stateProvider', '$urlRouterProvider'];
16021686
function $RouteProvider( $stateProvider, $urlRouterProvider) {

‎release/angular-ui-router.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎release/doc/$resolve.html

+26-20
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ <h2>
6464

6565
<dt class="tag-source">Source:</dt>
6666
<dd class="tag-source"><ul class="dummy"><li>
67-
resolve.js, line 1
67+
<a href="resolve.js.html">resolve.js</a>, <a href="resolve.js.html#line1">line 1</a>
6868
</li></ul></dd>
6969

7070

@@ -118,40 +118,32 @@ <h4 class="name" id="resolve"><span class="type-signature"></span>resolve<span c
118118
and can have an arbitrary number of dependencies. An invocable can either return a value directly,
119119
or a <code>$q</code> promise. If a promise is returned it will be resolved and the resulting value will be
120120
used instead. Dependencies of invocables are resolved (in this order of precedence)</p>
121-
122121
<ul>
123122
<li>from the specified <code>locals</code></li>
124123
<li>from another invocable that is part of this <code>$resolve</code> call</li>
125124
<li>from an invocable that is inherited from a <code>parent</code> call to <code>$resolve</code> (or recursively
126125
from any ancestor <code>$resolve</code> of that parent).</li>
127126
</ul>
128-
129127
<p>The return value of <code>$resolve</code> is a promise for an object that contains (in this order of precedence)</p>
130-
131128
<ul>
132129
<li>any <code>locals</code> (if specified)</li>
133130
<li>the resolved return values of all injectables</li>
134131
<li>any values inherited from a <code>parent</code> call to <code>$resolve</code> (if specified)</li>
135132
</ul>
136-
137133
<p>The promise will resolve after the <code>parent</code> promise (if any) and all promises returned by injectables
138134
have been resolved. If any invocable (or <code>$injector.invoke</code>) throws an exception, or if a promise
139135
returned by an invocable is rejected, the <code>$resolve</code> promise is immediately rejected with the same error.
140136
A rejection of a <code>parent</code> promise (if specified) will likewise be propagated immediately. Once the
141137
<code>$resolve</code> promise has been rejected, no further invocables will be called.</p>
142-
143138
<p>Cyclic dependencies between invocables are not permitted and will caues <code>$resolve</code> to throw an
144139
error. As a special case, an injectable can depend on a parameter with the same name as the injectable,
145140
which will be fulfilled from the <code>parent</code> injectable of the same name. This allows inherited values
146141
to be decorated. Note that in this case any other injectable in the same <code>$resolve</code> with the same
147142
dependency would see the decorated value, not the inherited value.</p>
148-
149143
<p>Note that missing dependencies -- unlike cyclic dependencies -- will cause an (asynchronous) rejection
150144
of the <code>$resolve</code> promise rather than a (synchronous) exception.</p>
151-
152145
<p>Invocables are invoked eagerly as soon as all dependencies are available. This is true even for
153146
dependencies inherited from a <code>parent</code> call to <code>$resolve</code>.</p>
154-
155147
<p>As a special case, an invocable can be a string, in which case it is taken to be a service name
156148
to be passed to <code>$injector.get()</code>. This is supported primarily for backwards-compatibility with the
157149
<code>resolve</code> property of <code>$routeProvider</code> routes.</p>
@@ -196,10 +188,7 @@ <h5>Parameters:</h5>
196188
<td class="type">
197189

198190

199-
<span class="param-type">Object.&lt;string, Function</span>
200-
|
201-
202-
<span class="param-type">string></span>
191+
<span class="param-type">Object.&lt;string, (function()|string)></span>
203192

204193

205194

@@ -210,6 +199,8 @@ <h5>Parameters:</h5>
210199

211200

212201

202+
203+
213204
</td>
214205

215206

@@ -241,6 +232,8 @@ <h5>Parameters:</h5>
241232

242233

243234

235+
236+
244237
</td>
245238

246239

@@ -272,6 +265,8 @@ <h5>Parameters:</h5>
272265

273266

274267

268+
269+
275270
</td>
276271

277272

@@ -303,6 +298,8 @@ <h5>Parameters:</h5>
303298

304299

305300

301+
302+
306303
</td>
307304

308305

@@ -339,7 +336,7 @@ <h5>Parameters:</h5>
339336

340337
<dt class="tag-source">Source:</dt>
341338
<dd class="tag-source"><ul class="dummy"><li>
342-
resolve.js, line 209
339+
<a href="resolve.js.html">resolve.js</a>, <a href="resolve.js.html#line209">line 209</a>
343340
</li></ul></dd>
344341

345342

@@ -352,6 +349,10 @@ <h5>Parameters:</h5>
352349

353350

354351

352+
353+
354+
355+
355356

356357

357358

@@ -386,7 +387,7 @@ <h5>Returns:</h5>
386387

387388

388389
<dt>
389-
<h4 class="name" id="study"><span class="type-signature"></span>study<span class="signature">(invocables)</span><span class="type-signature"> &rarr; {Function}</span></h4>
390+
<h4 class="name" id="study"><span class="type-signature"></span>study<span class="signature">(invocables)</span><span class="type-signature"> &rarr; {function}</span></h4>
390391

391392

392393
</dt>
@@ -480,7 +481,7 @@ <h5>Parameters:</h5>
480481

481482
<dt class="tag-source">Source:</dt>
482483
<dd class="tag-source"><ul class="dummy"><li>
483-
resolve.js, line 29
484+
<a href="resolve.js.html">resolve.js</a>, <a href="resolve.js.html#line29">line 29</a>
484485
</li></ul></dd>
485486

486487

@@ -493,6 +494,10 @@ <h5>Parameters:</h5>
493494

494495

495496

497+
498+
499+
500+
496501

497502

498503

@@ -508,7 +513,7 @@ <h5>Returns:</h5>
508513
</dt>
509514
<dd>
510515

511-
<span class="param-type">Function</span>
516+
<span class="param-type">function</span>
512517

513518

514519
</dd>
@@ -535,15 +540,16 @@ <h5>Returns:</h5>
535540
</div>
536541

537542
<nav>
538-
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#inheritParams">inheritParams</a></li></ul>
543+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
539544
</nav>
540545

541546
<br clear="both">
542547

543548
<footer>
544-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.1.1</a> on Wed Dec 04 2013 21:16:33 GMT-0500 (EST)
549+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
545550
</footer>
546551

547552
<script> prettyPrint(); </script>
553+
<script src="scripts/linenumber.js"> </script>
548554
</body>
549-
</html>
555+
</html>

‎release/doc/$templateFactory.html

+47-14
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ <h4 class="name" id="$templateFactory"><span class="type-signature"></span>new $
8080

8181
<dt class="tag-source">Source:</dt>
8282
<dd class="tag-source"><ul class="dummy"><li>
83-
templateFactory.js, line 1
83+
<a href="templateFactory.js.html">templateFactory.js</a>, <a href="templateFactory.js.html#line1">line 1</a>
8484
</li></ul></dd>
8585

8686

@@ -93,6 +93,10 @@ <h4 class="name" id="$templateFactory"><span class="type-signature"></span>new $
9393

9494

9595

96+
97+
98+
99+
96100

97101

98102

@@ -193,6 +197,8 @@ <h5>Parameters:</h5>
193197

194198

195199

200+
201+
196202
</td>
197203

198204

@@ -235,7 +241,7 @@ <h6>Properties</h6>
235241
<span class="param-type">string</span>
236242
|
237243

238-
<span class="param-type">Function</span>
244+
<span class="param-type">function</span>
239245

240246

241247

@@ -262,7 +268,7 @@ <h6>Properties</h6>
262268
<span class="param-type">string</span>
263269
|
264270

265-
<span class="param-type">Function</span>
271+
<span class="param-type">function</span>
266272

267273

268274

@@ -286,7 +292,7 @@ <h6>Properties</h6>
286292
<td class="type">
287293

288294

289-
<span class="param-type">Function</span>
295+
<span class="param-type">function</span>
290296

291297

292298

@@ -327,6 +333,8 @@ <h6>Properties</h6>
327333

328334

329335

336+
337+
330338
</td>
331339

332340

@@ -358,6 +366,8 @@ <h6>Properties</h6>
358366

359367

360368

369+
370+
361371
</td>
362372

363373

@@ -395,7 +405,7 @@ <h6>Properties</h6>
395405

396406
<dt class="tag-source">Source:</dt>
397407
<dd class="tag-source"><ul class="dummy"><li>
398-
templateFactory.js, line 12
408+
<a href="templateFactory.js.html">templateFactory.js</a>, <a href="templateFactory.js.html#line12">line 12</a>
399409
</li></ul></dd>
400410

401411

@@ -408,6 +418,10 @@ <h6>Properties</h6>
408418

409419

410420

421+
422+
423+
424+
411425

412426

413427

@@ -496,7 +510,7 @@ <h5>Parameters:</h5>
496510
<span class="param-type">string</span>
497511
|
498512

499-
<span class="param-type">Function</span>
513+
<span class="param-type">function</span>
500514

501515

502516

@@ -561,7 +575,7 @@ <h5>Parameters:</h5>
561575

562576
<dt class="tag-source">Source:</dt>
563577
<dd class="tag-source"><ul class="dummy"><li>
564-
templateFactory.js, line 41
578+
<a href="templateFactory.js.html">templateFactory.js</a>, <a href="templateFactory.js.html#line41">line 41</a>
565579
</li></ul></dd>
566580

567581

@@ -574,6 +588,10 @@ <h5>Parameters:</h5>
574588

575589

576590

591+
592+
593+
594+
577595

578596

579597

@@ -661,7 +679,7 @@ <h5>Parameters:</h5>
661679
<span class="param-type">string</span>
662680
|
663681

664-
<span class="param-type">Function</span>
682+
<span class="param-type">function</span>
665683

666684

667685

@@ -725,7 +743,7 @@ <h5>Parameters:</h5>
725743

726744
<dt class="tag-source">Source:</dt>
727745
<dd class="tag-source"><ul class="dummy"><li>
728-
templateFactory.js, line 55
746+
<a href="templateFactory.js.html">templateFactory.js</a>, <a href="templateFactory.js.html#line55">line 55</a>
729747
</li></ul></dd>
730748

731749

@@ -738,6 +756,10 @@ <h5>Parameters:</h5>
738756

739757

740758

759+
760+
761+
762+
741763

742764

743765

@@ -824,7 +846,7 @@ <h5>Parameters:</h5>
824846
<td class="type">
825847

826848

827-
<span class="param-type">Function</span>
849+
<span class="param-type">function</span>
828850

829851

830852

@@ -835,6 +857,8 @@ <h5>Parameters:</h5>
835857

836858

837859

860+
861+
838862
</td>
839863

840864

@@ -864,6 +888,8 @@ <h5>Parameters:</h5>
864888

865889

866890

891+
892+
867893
</td>
868894

869895

@@ -895,6 +921,8 @@ <h5>Parameters:</h5>
895921

896922

897923

924+
925+
898926
</td>
899927

900928

@@ -931,7 +959,7 @@ <h5>Parameters:</h5>
931959

932960
<dt class="tag-source">Source:</dt>
933961
<dd class="tag-source"><ul class="dummy"><li>
934-
templateFactory.js, line 72
962+
<a href="templateFactory.js.html">templateFactory.js</a>, <a href="templateFactory.js.html#line72">line 72</a>
935963
</li></ul></dd>
936964

937965

@@ -944,6 +972,10 @@ <h5>Parameters:</h5>
944972

945973

946974

975+
976+
977+
978+
947979

948980

949981

@@ -993,15 +1025,16 @@ <h5>Returns:</h5>
9931025
</div>
9941026

9951027
<nav>
996-
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#inheritParams">inheritParams</a></li></ul>
1028+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
9971029
</nav>
9981030

9991031
<br clear="both">
10001032

10011033
<footer>
1002-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.1.1</a> on Wed Dec 04 2013 21:16:33 GMT-0500 (EST)
1034+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
10031035
</footer>
10041036

10051037
<script> prettyPrint(); </script>
1038+
<script src="scripts/linenumber.js"> </script>
10061039
</body>
1007-
</html>
1040+
</html>

‎release/doc/$urlMatcherFactory.html

+19-6
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ <h4 class="name" id="$urlMatcherFactory"><span class="type-signature"></span>new
8181

8282
<dt class="tag-source">Source:</dt>
8383
<dd class="tag-source"><ul class="dummy"><li>
84-
urlMatcherFactory.js, line 219
84+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line219">line 219</a>
8585
</li></ul></dd>
8686

8787

@@ -94,6 +94,10 @@ <h4 class="name" id="$urlMatcherFactory"><span class="type-signature"></span>new
9494

9595

9696

97+
98+
99+
100+
97101

98102

99103

@@ -212,7 +216,7 @@ <h5>Parameters:</h5>
212216

213217
<dt class="tag-source">Source:</dt>
214218
<dd class="tag-source"><ul class="dummy"><li>
215-
urlMatcherFactory.js, line 226
219+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line226">line 226</a>
216220
</li></ul></dd>
217221

218222

@@ -225,6 +229,10 @@ <h5>Parameters:</h5>
225229

226230

227231

232+
233+
234+
235+
228236

229237

230238

@@ -347,7 +355,7 @@ <h5>Parameters:</h5>
347355

348356
<dt class="tag-source">Source:</dt>
349357
<dd class="tag-source"><ul class="dummy"><li>
350-
urlMatcherFactory.js, line 238
358+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line238">line 238</a>
351359
</li></ul></dd>
352360

353361

@@ -360,6 +368,10 @@ <h5>Parameters:</h5>
360368

361369

362370

371+
372+
373+
374+
363375

364376

365377

@@ -402,15 +414,16 @@ <h5>Returns:</h5>
402414
</div>
403415

404416
<nav>
405-
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#inheritParams">inheritParams</a></li></ul>
417+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
406418
</nav>
407419

408420
<br clear="both">
409421

410422
<footer>
411-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.1.1</a> on Wed Dec 04 2013 21:16:33 GMT-0500 (EST)
423+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
412424
</footer>
413425

414426
<script> prettyPrint(); </script>
427+
<script src="scripts/linenumber.js"> </script>
415428
</body>
416-
</html>
429+
</html>

‎release/doc/UrlMatcher.html

+35-29
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,21 @@ <h4 class="name" id="UrlMatcher"><span class="type-signature"></span>new UrlMatc
5252
of search parameters. Multiple search parameter names are separated by '&amp;'. Search parameters
5353
do not influence whether or not a URL is matched, but their values are passed through into
5454
the matched parameters returned by <a href="UrlMatcher.html#exec">exec</a>.</p>
55-
5655
<p>Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
5756
syntax, which optionally allows a regular expression for the parameter to be specified:</p>
58-
5957
<ul>
6058
<li>':' name - colon placeholder</li>
6159
<li>'*' name - catch-all placeholder</li>
6260
<li>'{' name '}' - curly placeholder</li>
6361
<li>'{' name ':' regexp '}' - curly placeholder with regexp. Should the regexp itself contain
6462
curly braces, they must be in matched pairs or escaped with a backslash.</li>
6563
</ul>
66-
6764
<p>Parameter names may contain only word characters (latin letters, digits, and underscore) and
6865
must be unique within the pattern (across both path and search parameters). For colon
6966
placeholders or curly placeholders without an explicit regexp, a path parameter matches any
7067
number of characters other than '/'. For catch-all placeholders the path parameter matches
7168
any number of characters.</p>
72-
7369
<h3>Examples</h3>
74-
7570
<ul>
7671
<li>'/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for
7772
trailing slashes, and patterns have to match the entire path, not just a prefix.</li>
@@ -218,7 +213,7 @@ <h5 class="subsection-title">Properties:</h5>
218213

219214
<dt class="tag-source">Source:</dt>
220215
<dd class="tag-source"><ul class="dummy"><li>
221-
urlMatcherFactory.js, line 44
216+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line44">line 44</a>
222217
</li></ul></dd>
223218

224219

@@ -231,6 +226,10 @@ <h5 class="subsection-title">Properties:</h5>
231226

232227

233228

229+
230+
231+
232+
234233

235234

236235

@@ -272,14 +271,10 @@ <h4 class="name" id="concat"><span class="type-signature"></span>concat<span cla
272271
search parameters of the specified pattern to this pattern. The current pattern is not
273272
modified. This can be understood as creating a pattern for URLs that are relative to (or
274273
suffixes of) the current pattern.</p>
275-
276274
<h3>Example</h3>
277-
278275
<p>The following two matchers are equivalent:</p>
279-
280-
<div class="highlight"><pre lang="">new UrlMatcher('/user/{id}?q').concat('/details?date');
281-
new UrlMatcher('/user/{id}/details?q&date');
282-
</pre></div>
276+
<pre><code>new UrlMatcher('/user/{id}?q').concat('/details?date');
277+
new UrlMatcher('/user/{id}/details?q&amp;date');</code></pre>
283278
</div>
284279

285280

@@ -360,7 +355,7 @@ <h5>Parameters:</h5>
360355

361356
<dt class="tag-source">Source:</dt>
362357
<dd class="tag-source"><ul class="dummy"><li>
363-
urlMatcherFactory.js, line 128
358+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line128">line 128</a>
364359
</li></ul></dd>
365360

366361

@@ -373,6 +368,10 @@ <h5>Parameters:</h5>
373368

374369

375370

371+
372+
373+
374+
376375

377376

378377

@@ -419,12 +418,9 @@ <h4 class="name" id="exec"><span class="type-signature"></span>exec<span class="
419418
of any search parameters that are mentioned in the pattern, but their value may be null if
420419
they are not present in <code>searchParams</code>. This means that search parameters are always treated
421420
as optional.</p>
422-
423421
<h3>Example</h3>
424-
425-
<div class="highlight"><pre lang="">new UrlMatcher('/user/{id}?q&r').exec('/user/bob', { x:'1', q:'hello' });
426-
// returns { id:'bob', q:'hello', r:null }
427-
</pre></div>
422+
<pre><code>new UrlMatcher('/user/{id}?q&amp;r').exec('/user/bob', { x:'1', q:'hello' });
423+
// returns { id:'bob', q:'hello', r:null }</code></pre>
428424
</div>
429425

430426

@@ -528,7 +524,7 @@ <h5>Parameters:</h5>
528524

529525
<dt class="tag-source">Source:</dt>
530526
<dd class="tag-source"><ul class="dummy"><li>
531-
urlMatcherFactory.js, line 156
527+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line156">line 156</a>
532528
</li></ul></dd>
533529

534530

@@ -541,6 +537,10 @@ <h5>Parameters:</h5>
541537

542538

543539

540+
541+
542+
543+
544544

545545

546546

@@ -585,12 +585,9 @@ <h4 class="name" id="format"><span class="type-signature"></span>format<span cla
585585
<p>Creates a URL that matches this pattern by substituting the specified values
586586
for the path and search parameters. Null values for path parameters are
587587
treated as empty strings.</p>
588-
589588
<h3>Example</h3>
590-
591-
<div class="highlight"><pre lang="">new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
592-
// returns '/user/bob?q=yes'
593-
</pre></div>
589+
<pre><code>new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
590+
// returns '/user/bob?q=yes'</code></pre>
594591
</div>
595592

596593

@@ -671,7 +668,7 @@ <h5>Parameters:</h5>
671668

672669
<dt class="tag-source">Source:</dt>
673670
<dd class="tag-source"><ul class="dummy"><li>
674-
urlMatcherFactory.js, line 195
671+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line195">line 195</a>
675672
</li></ul></dd>
676673

677674

@@ -684,6 +681,10 @@ <h5>Parameters:</h5>
684681

685682

686683

684+
685+
686+
687+
687688

688689

689690

@@ -758,7 +759,7 @@ <h4 class="name" id="parameters"><span class="type-signature"></span>parameters<
758759

759760
<dt class="tag-source">Source:</dt>
760761
<dd class="tag-source"><ul class="dummy"><li>
761-
urlMatcherFactory.js, line 177
762+
<a href="urlMatcherFactory.js.html">urlMatcherFactory.js</a>, <a href="urlMatcherFactory.js.html#line177">line 177</a>
762763
</li></ul></dd>
763764

764765

@@ -771,6 +772,10 @@ <h4 class="name" id="parameters"><span class="type-signature"></span>parameters<
771772

772773

773774

775+
776+
777+
778+
774779

775780

776781

@@ -818,15 +823,16 @@ <h5>Returns:</h5>
818823
</div>
819824

820825
<nav>
821-
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#inheritParams">inheritParams</a></li></ul>
826+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
822827
</nav>
823828

824829
<br clear="both">
825830

826831
<footer>
827-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.1.1</a> on Wed Dec 04 2013 21:16:33 GMT-0500 (EST)
832+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
828833
</footer>
829834

830835
<script> prettyPrint(); </script>
836+
<script src="scripts/linenumber.js"> </script>
831837
</body>
832-
</html>
838+
</html>

‎release/doc/common.js.html

+222
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>JSDoc: Source: common.js</title>
6+
7+
<script src="scripts/prettify/prettify.js"> </script>
8+
<script src="scripts/prettify/lang-css.js"> </script>
9+
<!--[if lt IE 9]>
10+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11+
<![endif]-->
12+
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13+
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14+
</head>
15+
16+
<body>
17+
18+
<div id="main">
19+
20+
<h1 class="page-title">Source: common.js</h1>
21+
22+
23+
24+
25+
26+
<section>
27+
<article>
28+
<pre class="prettyprint source"><code>/*jshint globalstrict:true*/
29+
/*global angular:false*/
30+
'use strict';
31+
32+
var isDefined = angular.isDefined,
33+
isFunction = angular.isFunction,
34+
isString = angular.isString,
35+
isObject = angular.isObject,
36+
isArray = angular.isArray,
37+
forEach = angular.forEach,
38+
extend = angular.extend,
39+
copy = angular.copy;
40+
41+
function inherit(parent, extra) {
42+
return extend(new (extend(function() {}, { prototype: parent }))(), extra);
43+
}
44+
45+
function merge(dst) {
46+
forEach(arguments, function(obj) {
47+
if (obj !== dst) {
48+
forEach(obj, function(value, key) {
49+
if (!dst.hasOwnProperty(key)) dst[key] = value;
50+
});
51+
}
52+
});
53+
return dst;
54+
}
55+
56+
/**
57+
* Finds the common ancestor path between two states.
58+
*
59+
* @param {Object} first The first state.
60+
* @param {Object} second The second state.
61+
* @return {Array} Returns an array of state names in descending order, not including the root.
62+
*/
63+
function ancestors(first, second) {
64+
var path = [];
65+
66+
for (var n in first.path) {
67+
if (first.path[n] === "") continue;
68+
if (!second.path[n]) break;
69+
path.push(first.path[n]);
70+
}
71+
return path;
72+
}
73+
74+
/**
75+
* IE8-safe wrapper for `Object.keys()`.
76+
*
77+
* @param {Object} object A JavaScript object.
78+
* @return {Array} Returns the keys of the object as an array.
79+
*/
80+
function keys(object) {
81+
if (Object.keys) {
82+
return Object.keys(object);
83+
}
84+
var result = [];
85+
86+
angular.forEach(object, function(val, key) {
87+
result.push(key);
88+
});
89+
return result;
90+
}
91+
92+
/**
93+
* IE8-safe wrapper for `Array.prototype.indexOf()`.
94+
*
95+
* @param {Array} array A JavaScript array.
96+
* @param {*} value A value to search the array for.
97+
* @return {Number} Returns the array index value of `value`, or `-1` if not present.
98+
*/
99+
function arraySearch(array, value) {
100+
if (Array.prototype.indexOf) {
101+
return array.indexOf(value, Number(arguments[2]) || 0);
102+
}
103+
var len = array.length >>> 0, from = Number(arguments[2]) || 0;
104+
from = (from &lt; 0) ? Math.ceil(from) : Math.floor(from);
105+
106+
if (from &lt; 0) from += len;
107+
108+
for (; from &lt; len; from++) {
109+
if (from in array && array[from] === value) return from;
110+
}
111+
return -1;
112+
}
113+
114+
/**
115+
* Merges a set of parameters with all parameters inherited between the common parents of the
116+
* current state and a given destination state.
117+
*
118+
* @param {Object} currentParams The value of the current state parameters ($stateParams).
119+
* @param {Object} newParams The set of parameters which will be composited with inherited params.
120+
* @param {Object} $current Internal definition of object representing the current state.
121+
* @param {Object} $to Internal definition of object representing state to transition to.
122+
*/
123+
function inheritParams(currentParams, newParams, $current, $to) {
124+
var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];
125+
126+
for (var i in parents) {
127+
if (!parents[i].params || !parents[i].params.length) continue;
128+
parentParams = parents[i].params;
129+
130+
for (var j in parentParams) {
131+
if (arraySearch(inheritList, parentParams[j]) >= 0) continue;
132+
inheritList.push(parentParams[j]);
133+
inherited[parentParams[j]] = currentParams[parentParams[j]];
134+
}
135+
}
136+
return extend({}, inherited, newParams);
137+
}
138+
139+
/**
140+
* Normalizes a set of values to string or `null`, filtering them by a list of keys.
141+
*
142+
* @param {Array} keys The list of keys to normalize/return.
143+
* @param {Object} values An object hash of values to normalize.
144+
* @return {Object} Returns an object hash of normalized string values.
145+
*/
146+
function normalize(keys, values) {
147+
var normalized = {};
148+
149+
forEach(keys, function (name) {
150+
var value = values[name];
151+
normalized[name] = (value != null) ? String(value) : null;
152+
});
153+
return normalized;
154+
}
155+
156+
/**
157+
* Performs a non-strict comparison of the subset of two objects, defined by a list of keys.
158+
*
159+
* @param {Object} a The first object.
160+
* @param {Object} b The second object.
161+
* @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,
162+
* it defaults to the list of keys in `a`.
163+
* @return {Boolean} Returns `true` if the keys match, otherwise `false`.
164+
*/
165+
function equalForKeys(a, b, keys) {
166+
if (!keys) {
167+
keys = [];
168+
for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility
169+
}
170+
171+
for (var i=0; i&lt;keys.length; i++) {
172+
var k = keys[i];
173+
if (a[k] != b[k]) return false; // Not '===', values aren't necessarily normalized
174+
}
175+
return true;
176+
}
177+
178+
/**
179+
* Returns the subset of an object, based on a list of keys.
180+
*
181+
* @param {Array} keys
182+
* @param {Object} values
183+
* @return {Boolean} Returns a subset of `values`.
184+
*/
185+
function filterByKeys(keys, values) {
186+
var filtered = {};
187+
188+
forEach(keys, function (name) {
189+
filtered[name] = values[name];
190+
});
191+
return filtered;
192+
}
193+
194+
angular.module('ui.router.util', ['ng']);
195+
angular.module('ui.router.router', ['ui.router.util']);
196+
angular.module('ui.router.state', ['ui.router.router', 'ui.router.util']);
197+
angular.module('ui.router', ['ui.router.state']);
198+
angular.module('ui.router.compat', ['ui.router']);
199+
200+
</code></pre>
201+
</article>
202+
</section>
203+
204+
205+
206+
207+
</div>
208+
209+
<nav>
210+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
211+
</nav>
212+
213+
<br clear="both">
214+
215+
<footer>
216+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
217+
</footer>
218+
219+
<script> prettyPrint(); </script>
220+
<script src="scripts/linenumber.js"> </script>
221+
</body>
222+
</html>

‎release/doc/global.html

+680-18
Large diffs are not rendered by default.

‎release/doc/index.html

+4-3
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,16 @@ <h3> </h3>
4848
</div>
4949

5050
<nav>
51-
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#inheritParams">inheritParams</a></li></ul>
51+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
5252
</nav>
5353

5454
<br clear="both">
5555

5656
<footer>
57-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.1.1</a> on Wed Dec 04 2013 21:16:33 GMT-0500 (EST)
57+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
5858
</footer>
5959

6060
<script> prettyPrint(); </script>
61+
<script src="scripts/linenumber.js"> </script>
6162
</body>
62-
</html>
63+
</html>

‎release/doc/resolve.js.html

+265
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>JSDoc: Source: resolve.js</title>
6+
7+
<script src="scripts/prettify/prettify.js"> </script>
8+
<script src="scripts/prettify/lang-css.js"> </script>
9+
<!--[if lt IE 9]>
10+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11+
<![endif]-->
12+
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13+
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14+
</head>
15+
16+
<body>
17+
18+
<div id="main">
19+
20+
<h1 class="page-title">Source: resolve.js</h1>
21+
22+
23+
24+
25+
26+
<section>
27+
<article>
28+
<pre class="prettyprint source"><code>/**
29+
* Service (`ui-util`). Manages resolution of (acyclic) graphs of promises.
30+
* @module $resolve
31+
* @requires $q
32+
* @requires $injector
33+
*/
34+
$Resolve.$inject = ['$q', '$injector'];
35+
function $Resolve( $q, $injector) {
36+
37+
var VISIT_IN_PROGRESS = 1,
38+
VISIT_DONE = 2,
39+
NOTHING = {},
40+
NO_DEPENDENCIES = [],
41+
NO_LOCALS = NOTHING,
42+
NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
43+
44+
45+
/**
46+
* Studies a set of invocables that are likely to be used multiple times.
47+
* $resolve.study(invocables)(locals, parent, self)
48+
* is equivalent to
49+
* $resolve.resolve(invocables, locals, parent, self)
50+
* but the former is more efficient (in fact `resolve` just calls `study` internally).
51+
* See {@link module:$resolve/resolve} for details.
52+
* @function
53+
* @param {Object} invocables
54+
* @return {Function}
55+
*/
56+
this.study = function (invocables) {
57+
if (!isObject(invocables)) throw new Error("'invocables' must be an object");
58+
59+
// Perform a topological sort of invocables to build an ordered plan
60+
var plan = [], cycle = [], visited = {};
61+
function visit(value, key) {
62+
if (visited[key] === VISIT_DONE) return;
63+
64+
cycle.push(key);
65+
if (visited[key] === VISIT_IN_PROGRESS) {
66+
cycle.splice(0, cycle.indexOf(key));
67+
throw new Error("Cyclic dependency: " + cycle.join(" -> "));
68+
}
69+
visited[key] = VISIT_IN_PROGRESS;
70+
71+
if (isString(value)) {
72+
plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
73+
} else {
74+
var params = $injector.annotate(value);
75+
forEach(params, function (param) {
76+
if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
77+
});
78+
plan.push(key, value, params);
79+
}
80+
81+
cycle.pop();
82+
visited[key] = VISIT_DONE;
83+
}
84+
forEach(invocables, visit);
85+
invocables = cycle = visited = null; // plan is all that's required
86+
87+
function isResolve(value) {
88+
return isObject(value) && value.then && value.$$promises;
89+
}
90+
91+
return function (locals, parent, self) {
92+
if (isResolve(locals) && self === undefined) {
93+
self = parent; parent = locals; locals = null;
94+
}
95+
if (!locals) locals = NO_LOCALS;
96+
else if (!isObject(locals)) {
97+
throw new Error("'locals' must be an object");
98+
}
99+
if (!parent) parent = NO_PARENT;
100+
else if (!isResolve(parent)) {
101+
throw new Error("'parent' must be a promise returned by $resolve.resolve()");
102+
}
103+
104+
// To complete the overall resolution, we have to wait for the parent
105+
// promise and for the promise for each invokable in our plan.
106+
var resolution = $q.defer(),
107+
result = resolution.promise,
108+
promises = result.$$promises = {},
109+
values = extend({}, locals),
110+
wait = 1 + plan.length/3,
111+
merged = false;
112+
113+
function done() {
114+
// Merge parent values we haven't got yet and publish our own $$values
115+
if (!--wait) {
116+
if (!merged) merge(values, parent.$$values);
117+
result.$$values = values;
118+
result.$$promises = true; // keep for isResolve()
119+
resolution.resolve(values);
120+
}
121+
}
122+
123+
function fail(reason) {
124+
result.$$failure = reason;
125+
resolution.reject(reason);
126+
}
127+
128+
// Short-circuit if parent has already failed
129+
if (isDefined(parent.$$failure)) {
130+
fail(parent.$$failure);
131+
return result;
132+
}
133+
134+
// Merge parent values if the parent has already resolved, or merge
135+
// parent promises and wait if the parent resolve is still in progress.
136+
if (parent.$$values) {
137+
merged = merge(values, parent.$$values);
138+
done();
139+
} else {
140+
extend(promises, parent.$$promises);
141+
parent.then(done, fail);
142+
}
143+
144+
// Process each invocable in the plan, but ignore any where a local of the same name exists.
145+
for (var i=0, ii=plan.length; i&lt;ii; i+=3) {
146+
if (locals.hasOwnProperty(plan[i])) done();
147+
else invoke(plan[i], plan[i+1], plan[i+2]);
148+
}
149+
150+
function invoke(key, invocable, params) {
151+
// Create a deferred for this invocation. Failures will propagate to the resolution as well.
152+
var invocation = $q.defer(), waitParams = 0;
153+
function onfailure(reason) {
154+
invocation.reject(reason);
155+
fail(reason);
156+
}
157+
// Wait for any parameter that we have a promise for (either from parent or from this
158+
// resolve; in that case study() will have made sure it's ordered before us in the plan).
159+
forEach(params, function (dep) {
160+
if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
161+
waitParams++;
162+
promises[dep].then(function (result) {
163+
values[dep] = result;
164+
if (!(--waitParams)) proceed();
165+
}, onfailure);
166+
}
167+
});
168+
if (!waitParams) proceed();
169+
function proceed() {
170+
if (isDefined(result.$$failure)) return;
171+
try {
172+
invocation.resolve($injector.invoke(invocable, self, values));
173+
invocation.promise.then(function (result) {
174+
values[key] = result;
175+
done();
176+
}, onfailure);
177+
} catch (e) {
178+
onfailure(e);
179+
}
180+
}
181+
// Publish promise synchronously; invocations further down in the plan may depend on it.
182+
promises[key] = invocation.promise;
183+
}
184+
185+
return result;
186+
};
187+
};
188+
189+
/**
190+
* Resolves a set of invocables. An invocable is a function to be invoked via `$injector.invoke()`,
191+
* and can have an arbitrary number of dependencies. An invocable can either return a value directly,
192+
* or a `$q` promise. If a promise is returned it will be resolved and the resulting value will be
193+
* used instead. Dependencies of invocables are resolved (in this order of precedence)
194+
*
195+
* - from the specified `locals`
196+
* - from another invocable that is part of this `$resolve` call
197+
* - from an invocable that is inherited from a `parent` call to `$resolve` (or recursively
198+
* from any ancestor `$resolve` of that parent).
199+
*
200+
* The return value of `$resolve` is a promise for an object that contains (in this order of precedence)
201+
*
202+
* - any `locals` (if specified)
203+
* - the resolved return values of all injectables
204+
* - any values inherited from a `parent` call to `$resolve` (if specified)
205+
*
206+
* The promise will resolve after the `parent` promise (if any) and all promises returned by injectables
207+
* have been resolved. If any invocable (or `$injector.invoke`) throws an exception, or if a promise
208+
* returned by an invocable is rejected, the `$resolve` promise is immediately rejected with the same error.
209+
* A rejection of a `parent` promise (if specified) will likewise be propagated immediately. Once the
210+
* `$resolve` promise has been rejected, no further invocables will be called.
211+
*
212+
* Cyclic dependencies between invocables are not permitted and will caues `$resolve` to throw an
213+
* error. As a special case, an injectable can depend on a parameter with the same name as the injectable,
214+
* which will be fulfilled from the `parent` injectable of the same name. This allows inherited values
215+
* to be decorated. Note that in this case any other injectable in the same `$resolve` with the same
216+
* dependency would see the decorated value, not the inherited value.
217+
*
218+
* Note that missing dependencies -- unlike cyclic dependencies -- will cause an (asynchronous) rejection
219+
* of the `$resolve` promise rather than a (synchronous) exception.
220+
*
221+
* Invocables are invoked eagerly as soon as all dependencies are available. This is true even for
222+
* dependencies inherited from a `parent` call to `$resolve`.
223+
*
224+
* As a special case, an invocable can be a string, in which case it is taken to be a service name
225+
* to be passed to `$injector.get()`. This is supported primarily for backwards-compatibility with the
226+
* `resolve` property of `$routeProvider` routes.
227+
*
228+
* @function
229+
* @param {Object.&lt;string, Function|string>} invocables functions to invoke or `$injector` services to fetch.
230+
* @param {Object.&lt;string, *>} [locals] values to make available to the injectables
231+
* @param {Promise.&lt;Object>} [parent] a promise returned by another call to `$resolve`.
232+
* @param {Object} [self] the `this` for the invoked methods
233+
* @return {Promise.&lt;Object>} Promise for an object that contains the resolved return value
234+
* of all invocables, as well as any inherited and local values.
235+
*/
236+
this.resolve = function (invocables, locals, parent, self) {
237+
return this.study(invocables)(locals, parent, self);
238+
};
239+
}
240+
241+
angular.module('ui.router.util').service('$resolve', $Resolve);
242+
243+
</code></pre>
244+
</article>
245+
</section>
246+
247+
248+
249+
250+
</div>
251+
252+
<nav>
253+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
254+
</nav>
255+
256+
<br clear="both">
257+
258+
<footer>
259+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
260+
</footer>
261+
262+
<script> prettyPrint(); </script>
263+
<script src="scripts/linenumber.js"> </script>
264+
</body>
265+
</html>

‎release/doc/scripts/linenumber.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(function() {
2+
var counter = 0;
3+
var numbered;
4+
var source = document.getElementsByClassName('prettyprint source');
5+
6+
if (source && source[0]) {
7+
source = source[0].getElementsByTagName('code')[0];
8+
9+
numbered = source.innerHTML.split('\n');
10+
numbered = numbered.map(function(item) {
11+
counter++;
12+
return '<span id="line' + counter + '" class="line"></span>' + item;
13+
});
14+
15+
source.innerHTML = numbered.join('\n');
16+
}
17+
})();

‎release/doc/styles/jsdoc-default.css

+9-2
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,14 @@ h6
195195
font-family: Consolas, "Lucida Console", Monaco, monospace;
196196
}
197197

198-
.details { margin-top: 14px; }
199-
.details dt { width:100px; float:left; border-left: 2px solid #DDD; padding-left: 10px; padding-top: 6px; }
198+
.details { margin-top: 14px; border-left: 2px solid #DDD; }
199+
.details dt { width:100px; float:left; padding-left: 10px; padding-top: 6px; }
200200
.details dd { margin-left: 50px; }
201201
.details ul { margin: 0; }
202202
.details ul { list-style-type: none; }
203203
.details li { margin-left: 30px; padding-top: 6px; }
204+
.details pre.prettyprint { margin: 0 }
205+
.details .object-value { padding-top: 0; }
204206

205207
.description {
206208
margin-bottom: 1em;
@@ -240,6 +242,11 @@ h6
240242
border-left: 3px #ddd solid;
241243
}
242244

245+
.prettyprint code span.line
246+
{
247+
display: inline-block;
248+
}
249+
243250
.params, .props
244251
{
245252
border-spacing: 0;

‎release/doc/templateFactory.js.html

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>JSDoc: Source: templateFactory.js</title>
6+
7+
<script src="scripts/prettify/prettify.js"> </script>
8+
<script src="scripts/prettify/lang-css.js"> </script>
9+
<!--[if lt IE 9]>
10+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11+
<![endif]-->
12+
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13+
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14+
</head>
15+
16+
<body>
17+
18+
<div id="main">
19+
20+
<h1 class="page-title">Source: templateFactory.js</h1>
21+
22+
23+
24+
25+
26+
<section>
27+
<article>
28+
<pre class="prettyprint source"><code>/**
29+
* Service. Manages loading of templates.
30+
* @constructor
31+
* @name $templateFactory
32+
* @requires $http
33+
* @requires $templateCache
34+
* @requires $injector
35+
*/
36+
$TemplateFactory.$inject = ['$http', '$templateCache', '$injector'];
37+
function $TemplateFactory( $http, $templateCache, $injector) {
38+
39+
/**
40+
* Creates a template from a configuration object.
41+
* @function
42+
* @name $templateFactory#fromConfig
43+
* @methodOf $templateFactory
44+
* @param {Object} config Configuration object for which to load a template. The following
45+
* properties are search in the specified order, and the first one that is defined is
46+
* used to create the template:
47+
* @param {string|Function} config.template html string template or function to load via
48+
* {@link $templateFactory#fromString fromString}.
49+
* @param {string|Function} config.templateUrl url to load or a function returning the url
50+
* to load via {@link $templateFactory#fromUrl fromUrl}.
51+
* @param {Function} config.templateProvider function to invoke via
52+
* {@link $templateFactory#fromProvider fromProvider}.
53+
* @param {Object} params Parameters to pass to the template function.
54+
* @param {Object} [locals] Locals to pass to `invoke` if the template is loaded via a
55+
* `templateProvider`. Defaults to `{ params: params }`.
56+
* @return {string|Promise.&lt;string>} The template html as a string, or a promise for that string,
57+
* or `null` if no template is configured.
58+
*/
59+
this.fromConfig = function (config, params, locals) {
60+
return (
61+
isDefined(config.template) ? this.fromString(config.template, params) :
62+
isDefined(config.templateUrl) ? this.fromUrl(config.templateUrl, params) :
63+
isDefined(config.templateProvider) ? this.fromProvider(config.templateProvider, params, locals) :
64+
null
65+
);
66+
};
67+
68+
/**
69+
* Creates a template from a string or a function returning a string.
70+
* @function
71+
* @name $templateFactory#fromString
72+
* @methodOf $templateFactory
73+
* @param {string|Function} template html template as a string or function that returns an html
74+
* template as a string.
75+
* @param {Object} params Parameters to pass to the template function.
76+
* @return {string|Promise.&lt;string>} The template html as a string, or a promise for that string.
77+
*/
78+
this.fromString = function (template, params) {
79+
return isFunction(template) ? template(params) : template;
80+
};
81+
82+
/**
83+
* Loads a template from the a URL via `$http` and `$templateCache`.
84+
* @function
85+
* @name $templateFactory#fromUrl
86+
* @methodOf $templateFactory
87+
* @param {string|Function} url url of the template to load, or a function that returns a url.
88+
* @param {Object} params Parameters to pass to the url function.
89+
* @return {string|Promise.&lt;string>} The template html as a string, or a promise for that string.
90+
*/
91+
this.fromUrl = function (url, params) {
92+
if (isFunction(url)) url = url(params);
93+
if (url == null) return null;
94+
else return $http
95+
.get(url, { cache: $templateCache })
96+
.then(function(response) { return response.data; });
97+
};
98+
99+
/**
100+
* Creates a template by invoking an injectable provider function.
101+
* @function
102+
* @name $templateFactory#fromUrl
103+
* @methodOf $templateFactory
104+
* @param {Function} provider Function to invoke via `$injector.invoke`
105+
* @param {Object} params Parameters for the template.
106+
* @param {Object} [locals] Locals to pass to `invoke`. Defaults to `{ params: params }`.
107+
* @return {string|Promise.&lt;string>} The template html as a string, or a promise for that string.
108+
*/
109+
this.fromProvider = function (provider, params, locals) {
110+
return $injector.invoke(provider, null, locals || { params: params });
111+
};
112+
}
113+
114+
angular.module('ui.router.util').service('$templateFactory', $TemplateFactory);
115+
</code></pre>
116+
</article>
117+
</section>
118+
119+
120+
121+
122+
</div>
123+
124+
<nav>
125+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
126+
</nav>
127+
128+
<br clear="both">
129+
130+
<footer>
131+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
132+
</footer>
133+
134+
<script> prettyPrint(); </script>
135+
<script src="scripts/linenumber.js"> </script>
136+
</body>
137+
</html>

‎release/doc/urlMatcherFactory.js.html

+306
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>JSDoc: Source: urlMatcherFactory.js</title>
6+
7+
<script src="scripts/prettify/prettify.js"> </script>
8+
<script src="scripts/prettify/lang-css.js"> </script>
9+
<!--[if lt IE 9]>
10+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
11+
<![endif]-->
12+
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
13+
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
14+
</head>
15+
16+
<body>
17+
18+
<div id="main">
19+
20+
<h1 class="page-title">Source: urlMatcherFactory.js</h1>
21+
22+
23+
24+
25+
26+
<section>
27+
<article>
28+
<pre class="prettyprint source"><code>/**
29+
* Matches URLs against patterns and extracts named parameters from the path or the search
30+
* part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list
31+
* of search parameters. Multiple search parameter names are separated by '&'. Search parameters
32+
* do not influence whether or not a URL is matched, but their values are passed through into
33+
* the matched parameters returned by {@link UrlMatcher#exec exec}.
34+
*
35+
* Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace
36+
* syntax, which optionally allows a regular expression for the parameter to be specified:
37+
*
38+
* * ':' name - colon placeholder
39+
* * '*' name - catch-all placeholder
40+
* * '{' name '}' - curly placeholder
41+
* * '{' name ':' regexp '}' - curly placeholder with regexp. Should the regexp itself contain
42+
* curly braces, they must be in matched pairs or escaped with a backslash.
43+
*
44+
* Parameter names may contain only word characters (latin letters, digits, and underscore) and
45+
* must be unique within the pattern (across both path and search parameters). For colon
46+
* placeholders or curly placeholders without an explicit regexp, a path parameter matches any
47+
* number of characters other than '/'. For catch-all placeholders the path parameter matches
48+
* any number of characters.
49+
*
50+
* ### Examples
51+
*
52+
* * '/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for
53+
* trailing slashes, and patterns have to match the entire path, not just a prefix.
54+
* * '/user/:id' - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or
55+
* '/user/bob/details'. The second path segment will be captured as the parameter 'id'.
56+
* * '/user/{id}' - Same as the previous example, but using curly brace syntax.
57+
* * '/user/{id:[^/]*}' - Same as the previous example.
58+
* * '/user/{id:[0-9a-fA-F]{1,8}}' - Similar to the previous example, but only matches if the id
59+
* parameter consists of 1 to 8 hex digits.
60+
* * '/files/{path:.*}' - Matches any URL starting with '/files/' and captures the rest of the
61+
* path into the parameter 'path'.
62+
* * '/files/*path' - ditto.
63+
*
64+
* @constructor
65+
* @param {string} pattern the pattern to compile into a matcher.
66+
*
67+
* @property {string} prefix A static prefix of this pattern. The matcher guarantees that any
68+
* URL matching this matcher (i.e. any string for which {@link UrlMatcher#exec exec()} returns
69+
* non-null) will start with this prefix.
70+
*/
71+
function UrlMatcher(pattern) {
72+
73+
// Find all placeholders and create a compiled pattern, using either classic or curly syntax:
74+
// '*' name
75+
// ':' name
76+
// '{' name '}'
77+
// '{' name ':' regexp '}'
78+
// The regular expression is somewhat complicated due to the need to allow curly braces
79+
// inside the regular expression. The placeholder regexp breaks down as follows:
80+
// ([:*])(\w+) classic placeholder ($1 / $2)
81+
// \{(\w+)(?:\:( ... ))?\} curly brace placeholder ($3) with optional regexp ... ($4)
82+
// (?: ... | ... | ... )+ the regexp consists of any number of atoms, an atom being either
83+
// [^{}\\]+ - anything other than curly braces or backslash
84+
// \\. - a backslash escape
85+
// \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms
86+
var placeholder = /([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,
87+
names = {}, compiled = '^', last = 0, m,
88+
segments = this.segments = [],
89+
params = this.params = [];
90+
91+
function addParameter(id) {
92+
if (!/^\w+(-+\w+)*$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'");
93+
if (names[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'");
94+
names[id] = true;
95+
params.push(id);
96+
}
97+
98+
function quoteRegExp(string) {
99+
return string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&");
100+
}
101+
102+
this.source = pattern;
103+
104+
// Split into static segments separated by path parameter placeholders.
105+
// The number of segments is always 1 more than the number of parameters.
106+
var id, regexp, segment;
107+
while ((m = placeholder.exec(pattern))) {
108+
id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null
109+
regexp = m[4] || (m[1] == '*' ? '.*' : '[^/]*');
110+
segment = pattern.substring(last, m.index);
111+
if (segment.indexOf('?') >= 0) break; // we're into the search part
112+
compiled += quoteRegExp(segment) + '(' + regexp + ')';
113+
addParameter(id);
114+
segments.push(segment);
115+
last = placeholder.lastIndex;
116+
}
117+
segment = pattern.substring(last);
118+
119+
// Find any search parameter names and remove them from the last segment
120+
var i = segment.indexOf('?');
121+
if (i >= 0) {
122+
var search = this.sourceSearch = segment.substring(i);
123+
segment = segment.substring(0, i);
124+
this.sourcePath = pattern.substring(0, last+i);
125+
126+
// Allow parameters to be separated by '?' as well as '&' to make concat() easier
127+
forEach(search.substring(1).split(/[&?]/), addParameter);
128+
} else {
129+
this.sourcePath = pattern;
130+
this.sourceSearch = '';
131+
}
132+
133+
compiled += quoteRegExp(segment) + '$';
134+
segments.push(segment);
135+
this.regexp = new RegExp(compiled);
136+
this.prefix = segments[0];
137+
}
138+
139+
/**
140+
* Returns a new matcher for a pattern constructed by appending the path part and adding the
141+
* search parameters of the specified pattern to this pattern. The current pattern is not
142+
* modified. This can be understood as creating a pattern for URLs that are relative to (or
143+
* suffixes of) the current pattern.
144+
*
145+
* ### Example
146+
* The following two matchers are equivalent:
147+
* ```
148+
* new UrlMatcher('/user/{id}?q').concat('/details?date');
149+
* new UrlMatcher('/user/{id}/details?q&date');
150+
* ```
151+
*
152+
* @param {string} pattern The pattern to append.
153+
* @return {UrlMatcher} A matcher for the concatenated pattern.
154+
*/
155+
UrlMatcher.prototype.concat = function (pattern) {
156+
// Because order of search parameters is irrelevant, we can add our own search
157+
// parameters to the end of the new pattern. Parse the new pattern by itself
158+
// and then join the bits together, but it's much easier to do this on a string level.
159+
return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch);
160+
};
161+
162+
UrlMatcher.prototype.toString = function () {
163+
return this.source;
164+
};
165+
166+
/**
167+
* Tests the specified path against this matcher, and returns an object containing the captured
168+
* parameter values, or null if the path does not match. The returned object contains the values
169+
* of any search parameters that are mentioned in the pattern, but their value may be null if
170+
* they are not present in `searchParams`. This means that search parameters are always treated
171+
* as optional.
172+
*
173+
* ### Example
174+
* ```
175+
* new UrlMatcher('/user/{id}?q&r').exec('/user/bob', { x:'1', q:'hello' });
176+
* // returns { id:'bob', q:'hello', r:null }
177+
* ```
178+
*
179+
* @param {string} path The URL path to match, e.g. `$location.path()`.
180+
* @param {Object} searchParams URL search parameters, e.g. `$location.search()`.
181+
* @return {Object} The captured parameter values.
182+
*/
183+
UrlMatcher.prototype.exec = function (path, searchParams) {
184+
var m = this.regexp.exec(path);
185+
if (!m) return null;
186+
187+
var params = this.params, nTotal = params.length,
188+
nPath = this.segments.length-1,
189+
values = {}, i;
190+
191+
if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'");
192+
193+
for (i=0; i&lt;nPath; i++) values[params[i]] = m[i+1];
194+
for (/**/; i&lt;nTotal; i++) values[params[i]] = searchParams[params[i]];
195+
196+
return values;
197+
};
198+
199+
/**
200+
* Returns the names of all path and search parameters of this pattern in an unspecified order.
201+
* @return {Array.&lt;string>} An array of parameter names. Must be treated as read-only. If the
202+
* pattern has no parameters, an empty array is returned.
203+
*/
204+
UrlMatcher.prototype.parameters = function () {
205+
return this.params;
206+
};
207+
208+
/**
209+
* Creates a URL that matches this pattern by substituting the specified values
210+
* for the path and search parameters. Null values for path parameters are
211+
* treated as empty strings.
212+
*
213+
* ### Example
214+
* ```
215+
* new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
216+
* // returns '/user/bob?q=yes'
217+
* ```
218+
*
219+
* @param {Object} values the values to substitute for the parameters in this pattern.
220+
* @return {string} the formatted URL (path and optionally search part).
221+
*/
222+
UrlMatcher.prototype.format = function (values) {
223+
var segments = this.segments, params = this.params;
224+
if (!values) return segments.join('');
225+
226+
var nPath = segments.length-1, nTotal = params.length,
227+
result = segments[0], i, search, value;
228+
229+
for (i=0; i&lt;nPath; i++) {
230+
value = values[params[i]];
231+
// TODO: Maybe we should throw on null here? It's not really good style to use '' and null interchangeabley
232+
if (value != null) result += encodeURIComponent(value);
233+
result += segments[i+1];
234+
}
235+
for (/**/; i&lt;nTotal; i++) {
236+
value = values[params[i]];
237+
if (value != null) {
238+
result += (search ? '&' : '?') + params[i] + '=' + encodeURIComponent(value);
239+
search = true;
240+
}
241+
}
242+
243+
return result;
244+
};
245+
246+
/**
247+
* Service. Factory for {@link UrlMatcher} instances. The factory is also available to providers
248+
* under the name `$urlMatcherFactoryProvider`.
249+
* @constructor
250+
* @name $urlMatcherFactory
251+
*/
252+
function $UrlMatcherFactory() {
253+
/**
254+
* Creates a {@link UrlMatcher} for the specified pattern.
255+
* @function
256+
* @name $urlMatcherFactory#compile
257+
* @methodOf $urlMatcherFactory
258+
* @param {string} pattern The URL pattern.
259+
* @return {UrlMatcher} The UrlMatcher.
260+
*/
261+
this.compile = function (pattern) {
262+
return new UrlMatcher(pattern);
263+
};
264+
265+
/**
266+
* Returns true if the specified object is a UrlMatcher, or false otherwise.
267+
* @function
268+
* @name $urlMatcherFactory#isMatcher
269+
* @methodOf $urlMatcherFactory
270+
* @param {Object} o
271+
* @return {boolean}
272+
*/
273+
this.isMatcher = function (o) {
274+
return isObject(o) && isFunction(o.exec) && isFunction(o.format) && isFunction(o.concat);
275+
};
276+
277+
this.$get = function () {
278+
return this;
279+
};
280+
}
281+
282+
// Register as a provider so it's available to other providers
283+
angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);
284+
</code></pre>
285+
</article>
286+
</section>
287+
288+
289+
290+
291+
</div>
292+
293+
<nav>
294+
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
295+
</nav>
296+
297+
<br clear="both">
298+
299+
<footer>
300+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Fri Dec 06 2013 14:17:59 GMT-0500 (EST)
301+
</footer>
302+
303+
<script> prettyPrint(); </script>
304+
<script src="scripts/linenumber.js"> </script>
305+
</body>
306+
</html>

0 commit comments

Comments
 (0)
Please sign in to comment.