2011-07-17 08:05:43 +00:00
|
|
|
|
'use strict';
|
|
|
|
|
|
|
2012-02-29 22:56:29 +00:00
|
|
|
|
|
2011-02-15 06:12:45 +00:00
|
|
|
|
/**
|
2011-11-10 06:23:36 +00:00
|
|
|
|
* @ngdoc object
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$routeProvider
|
2012-02-29 22:56:29 +00:00
|
|
|
|
* @function
|
2011-02-15 06:12:45 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @description
|
|
|
|
|
|
*
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* Used for configuring routes. See {@link ng.$route $route} for an example.
|
2011-02-15 06:12:45 +00:00
|
|
|
|
*/
|
2011-11-02 23:32:46 +00:00
|
|
|
|
function $RouteProvider(){
|
2012-02-15 23:45:07 +00:00
|
|
|
|
var routes = {};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc method
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$routeProvider#when
|
|
|
|
|
|
* @methodOf ng.$routeProvider
|
2012-02-15 23:45:07 +00:00
|
|
|
|
*
|
2012-03-20 07:38:08 +00:00
|
|
|
|
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* contains redundant trailing slash or is missing one, the route will still match and the
|
2013-01-14 19:01:51 +00:00
|
|
|
|
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
2012-03-20 07:38:08 +00:00
|
|
|
|
* route definition.
|
2013-01-14 19:01:51 +00:00
|
|
|
|
*
|
2012-11-12 21:09:53 +00:00
|
|
|
|
* * `path` can contain named groups starting with a colon (`:name`). All characters up
|
|
|
|
|
|
* to the next slash are matched and stored in `$routeParams` under the given `name`
|
|
|
|
|
|
* when the route matches.
|
|
|
|
|
|
* * `path` can contain named groups starting with a star (`*name`). All characters are
|
|
|
|
|
|
* eagerly stored in `$routeParams` under the given `name` when the route matches.
|
|
|
|
|
|
*
|
|
|
|
|
|
* For example, routes like `/color/:color/largecode/*largecode/edit` will match
|
|
|
|
|
|
* `/color/brown/largecode/code/with/slashs/edit` and extract:
|
|
|
|
|
|
*
|
|
|
|
|
|
* * `color: brown`
|
|
|
|
|
|
* * `largecode: code/with/slashs`.
|
|
|
|
|
|
*
|
2013-01-14 19:01:51 +00:00
|
|
|
|
*
|
2012-02-15 23:45:07 +00:00
|
|
|
|
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
|
|
|
|
|
* match.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Object properties:
|
|
|
|
|
|
*
|
2012-07-18 19:21:03 +00:00
|
|
|
|
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
|
2012-09-06 22:03:35 +00:00
|
|
|
|
* created scope or the name of a {@link angular.Module#controller registered controller}
|
2012-07-18 19:21:03 +00:00
|
|
|
|
* if passed as a string.
|
2012-11-03 20:11:07 +00:00
|
|
|
|
* - `template` – `{string=|function()=}` – html template as a string or function that returns
|
|
|
|
|
|
* an html template as a string which should be used by {@link ng.directive:ngView ngView} or
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* {@link ng.directive:ngInclude ngInclude} directives.
|
2012-11-03 20:11:07 +00:00
|
|
|
|
* This property takes precedence over `templateUrl`.
|
|
|
|
|
|
*
|
|
|
|
|
|
* If `template` is a function, it will be called with the following parameters:
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `{Array.<Object>}` - route parameters extracted from the current
|
|
|
|
|
|
* `$location.path()` by applying the current route
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
|
|
|
|
|
* template that should be used by {@link ng.directive:ngView ngView}.
|
|
|
|
|
|
*
|
|
|
|
|
|
* If `templateUrl` is a function, it will be called with the following parameters:
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `{Array.<Object>}` - route parameters extracted from the current
|
|
|
|
|
|
* `$location.path()` by applying the current route
|
|
|
|
|
|
*
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
|
|
|
|
|
* be injected into the controller. If any of these dependencies are promises, they will be
|
|
|
|
|
|
* resolved and converted to a value before the controller is instantiated and the
|
2012-09-06 22:03:35 +00:00
|
|
|
|
* `$routeChangeSuccess` event is fired. The map object is:
|
2012-05-23 04:12:19 +00:00
|
|
|
|
*
|
|
|
|
|
|
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
|
|
|
|
|
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* and the return value is treated as the dependency. If the result is a promise, it is resolved
|
|
|
|
|
|
* before its value is injected into the controller.
|
|
|
|
|
|
*
|
2012-02-15 23:45:07 +00:00
|
|
|
|
* - `redirectTo` – {(string|function())=} – value to update
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* {@link ng.$location $location} path with and trigger route redirection.
|
2012-02-15 23:45:07 +00:00
|
|
|
|
*
|
|
|
|
|
|
* If `redirectTo` is a function, it will be called with the following parameters:
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `{Object.<string>}` - route parameters extracted from the current
|
2012-05-17 23:36:18 +00:00
|
|
|
|
* `$location.path()` by applying the current route templateUrl.
|
2012-02-15 23:45:07 +00:00
|
|
|
|
* - `{string}` - current `$location.path()`
|
|
|
|
|
|
* - `{Object}` - current `$location.search()`
|
|
|
|
|
|
*
|
|
|
|
|
|
* The custom `redirectTo` function is expected to return a string which will be used
|
|
|
|
|
|
* to update `$location.path()` and `$location.search()`.
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
|
|
|
|
|
|
* changes.
|
|
|
|
|
|
*
|
2012-02-29 22:56:29 +00:00
|
|
|
|
* If the option is set to `false` and url in the browser changes, then
|
|
|
|
|
|
* `$routeUpdate` event is broadcasted on the root scope.
|
2012-02-15 23:45:07 +00:00
|
|
|
|
*
|
2013-02-23 20:45:48 +00:00
|
|
|
|
* - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
|
|
|
|
|
|
*
|
|
|
|
|
|
* If the option is set to `true`, then the particular route can be matched without being
|
|
|
|
|
|
* case sensitive
|
|
|
|
|
|
*
|
2012-04-03 22:28:09 +00:00
|
|
|
|
* @returns {Object} self
|
2012-02-15 23:45:07 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @description
|
|
|
|
|
|
* Adds a new route definition to the `$route` service.
|
|
|
|
|
|
*/
|
|
|
|
|
|
this.when = function(path, route) {
|
2013-02-23 20:45:48 +00:00
|
|
|
|
routes[path] = extend({reloadOnSearch: true, caseInsensitiveMatch: false}, route);
|
2012-03-20 07:38:08 +00:00
|
|
|
|
|
|
|
|
|
|
// create redirection for trailing slashes
|
|
|
|
|
|
if (path) {
|
|
|
|
|
|
var redirectPath = (path[path.length-1] == '/')
|
|
|
|
|
|
? path.substr(0, path.length-1)
|
|
|
|
|
|
: path +'/';
|
|
|
|
|
|
|
|
|
|
|
|
routes[redirectPath] = {redirectTo: path};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-04-03 22:28:09 +00:00
|
|
|
|
return this;
|
2012-02-15 23:45:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc method
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$routeProvider#otherwise
|
|
|
|
|
|
* @methodOf ng.$routeProvider
|
2012-02-15 23:45:07 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @description
|
|
|
|
|
|
* Sets route definition that will be used on route change when no other route definition
|
|
|
|
|
|
* is matched.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {Object} params Mapping information to be assigned to `$route.current`.
|
2012-04-03 22:28:09 +00:00
|
|
|
|
* @returns {Object} self
|
2012-02-15 23:45:07 +00:00
|
|
|
|
*/
|
|
|
|
|
|
this.otherwise = function(params) {
|
|
|
|
|
|
this.when(null, params);
|
2012-04-03 22:28:09 +00:00
|
|
|
|
return this;
|
2012-02-15 23:45:07 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-05-23 04:12:19 +00:00
|
|
|
|
this.$get = ['$rootScope', '$location', '$routeParams', '$q', '$injector', '$http', '$templateCache',
|
|
|
|
|
|
function( $rootScope, $location, $routeParams, $q, $injector, $http, $templateCache) {
|
2012-02-29 22:56:29 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc object
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$route
|
2012-02-29 22:56:29 +00:00
|
|
|
|
* @requires $location
|
|
|
|
|
|
* @requires $routeParams
|
|
|
|
|
|
*
|
|
|
|
|
|
* @property {Object} current Reference to the current route definition.
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* The route definition contains:
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `controller`: The controller constructor as define in route definition.
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* controller instantiation. The `locals` contain
|
|
|
|
|
|
* the resolved values of the `resolve` map. Additionally the `locals` also contain:
|
|
|
|
|
|
*
|
|
|
|
|
|
* - `$scope` - The current route scope.
|
|
|
|
|
|
* - `$template` - The current route template HTML.
|
|
|
|
|
|
*
|
2012-02-29 22:56:29 +00:00
|
|
|
|
* @property {Array.<Object>} routes Array of all configured routes.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @description
|
|
|
|
|
|
* Is used for deep-linking URLs to controllers and views (HTML partials).
|
|
|
|
|
|
* It watches `$location.url()` and tries to map the path to an existing route definition.
|
|
|
|
|
|
*
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* You can define routes through {@link ng.$routeProvider $routeProvider}'s API.
|
2012-02-29 22:56:29 +00:00
|
|
|
|
*
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* The `$route` service is typically used in conjunction with {@link ng.directive:ngView ngView}
|
|
|
|
|
|
* directive and the {@link ng.$routeParams $routeParams} service.
|
2012-02-29 22:56:29 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @example
|
|
|
|
|
|
This example shows how changing the URL hash causes the `$route` to match a route against the
|
2012-04-06 23:35:17 +00:00
|
|
|
|
URL, and the `ngView` pulls in the partial.
|
2012-02-29 22:56:29 +00:00
|
|
|
|
|
2012-06-12 06:49:24 +00:00
|
|
|
|
Note that this example is using {@link ng.directive:script inlined templates}
|
2012-02-29 22:56:29 +00:00
|
|
|
|
to get it working on jsfiddle as well.
|
|
|
|
|
|
|
2012-04-29 05:45:28 +00:00
|
|
|
|
<example module="ngView">
|
|
|
|
|
|
<file name="index.html">
|
|
|
|
|
|
<div ng-controller="MainCntl">
|
|
|
|
|
|
Choose:
|
|
|
|
|
|
<a href="Book/Moby">Moby</a> |
|
|
|
|
|
|
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
|
|
|
|
|
<a href="Book/Gatsby">Gatsby</a> |
|
|
|
|
|
|
<a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
|
|
|
|
|
|
<a href="Book/Scarlet">Scarlet Letter</a><br/>
|
|
|
|
|
|
|
|
|
|
|
|
<div ng-view></div>
|
|
|
|
|
|
<hr />
|
|
|
|
|
|
|
|
|
|
|
|
<pre>$location.path() = {{$location.path()}}</pre>
|
2012-05-17 23:36:18 +00:00
|
|
|
|
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
2012-04-29 05:45:28 +00:00
|
|
|
|
<pre>$route.current.params = {{$route.current.params}}</pre>
|
|
|
|
|
|
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
|
|
|
|
|
<pre>$routeParams = {{$routeParams}}</pre>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</file>
|
|
|
|
|
|
|
|
|
|
|
|
<file name="book.html">
|
|
|
|
|
|
controller: {{name}}<br />
|
|
|
|
|
|
Book Id: {{params.bookId}}<br />
|
|
|
|
|
|
</file>
|
|
|
|
|
|
|
|
|
|
|
|
<file name="chapter.html">
|
|
|
|
|
|
controller: {{name}}<br />
|
|
|
|
|
|
Book Id: {{params.bookId}}<br />
|
|
|
|
|
|
Chapter Id: {{params.chapterId}}
|
|
|
|
|
|
</file>
|
|
|
|
|
|
|
|
|
|
|
|
<file name="script.js">
|
|
|
|
|
|
angular.module('ngView', [], function($routeProvider, $locationProvider) {
|
|
|
|
|
|
$routeProvider.when('/Book/:bookId', {
|
2012-05-17 23:36:18 +00:00
|
|
|
|
templateUrl: 'book.html',
|
2012-05-23 04:12:19 +00:00
|
|
|
|
controller: BookCntl,
|
|
|
|
|
|
resolve: {
|
|
|
|
|
|
// I will cause a 1 second delay
|
|
|
|
|
|
delay: function($q, $timeout) {
|
|
|
|
|
|
var delay = $q.defer();
|
|
|
|
|
|
$timeout(delay.resolve, 1000);
|
|
|
|
|
|
return delay.promise;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-04-29 05:45:28 +00:00
|
|
|
|
});
|
|
|
|
|
|
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
2012-05-17 23:36:18 +00:00
|
|
|
|
templateUrl: 'chapter.html',
|
2012-04-29 05:45:28 +00:00
|
|
|
|
controller: ChapterCntl
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// configure html5 to get links working on jsfiddle
|
|
|
|
|
|
$locationProvider.html5Mode(true);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
function MainCntl($scope, $route, $routeParams, $location) {
|
|
|
|
|
|
$scope.$route = $route;
|
|
|
|
|
|
$scope.$location = $location;
|
|
|
|
|
|
$scope.$routeParams = $routeParams;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function BookCntl($scope, $routeParams) {
|
|
|
|
|
|
$scope.name = "BookCntl";
|
|
|
|
|
|
$scope.params = $routeParams;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ChapterCntl($scope, $routeParams) {
|
|
|
|
|
|
$scope.name = "ChapterCntl";
|
|
|
|
|
|
$scope.params = $routeParams;
|
|
|
|
|
|
}
|
|
|
|
|
|
</file>
|
|
|
|
|
|
|
|
|
|
|
|
<file name="scenario.js">
|
|
|
|
|
|
it('should load and compile correct template', function() {
|
|
|
|
|
|
element('a:contains("Moby: Ch1")').click();
|
|
|
|
|
|
var content = element('.doc-example-live [ng-view]').text();
|
|
|
|
|
|
expect(content).toMatch(/controller\: ChapterCntl/);
|
|
|
|
|
|
expect(content).toMatch(/Book Id\: Moby/);
|
|
|
|
|
|
expect(content).toMatch(/Chapter Id\: 1/);
|
|
|
|
|
|
|
|
|
|
|
|
element('a:contains("Scarlet")').click();
|
2012-05-23 04:12:19 +00:00
|
|
|
|
sleep(2); // promises are not part of scenario waiting
|
2012-04-29 05:45:28 +00:00
|
|
|
|
content = element('.doc-example-live [ng-view]').text();
|
|
|
|
|
|
expect(content).toMatch(/controller\: BookCntl/);
|
|
|
|
|
|
expect(content).toMatch(/Book Id\: Scarlet/);
|
|
|
|
|
|
});
|
|
|
|
|
|
</file>
|
|
|
|
|
|
</example>
|
2012-02-29 22:56:29 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc event
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$route#$routeChangeStart
|
|
|
|
|
|
* @eventOf ng.$route
|
2011-11-02 23:32:46 +00:00
|
|
|
|
* @eventType broadcast on root scope
|
|
|
|
|
|
* @description
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* Broadcasted before a route change. At this point the route services starts
|
|
|
|
|
|
* resolving all of the dependencies needed for the route change to occurs.
|
|
|
|
|
|
* Typically this involves fetching the view template as well as any dependencies
|
|
|
|
|
|
* defined in `resolve` route property. Once all of the dependencies are resolved
|
2012-06-01 18:31:10 +00:00
|
|
|
|
* `$routeChangeSuccess` is fired.
|
2011-11-02 23:32:46 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @param {Route} next Future route information.
|
|
|
|
|
|
* @param {Route} current Current route information.
|
|
|
|
|
|
*/
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc event
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$route#$routeChangeSuccess
|
|
|
|
|
|
* @eventOf ng.$route
|
2011-11-02 23:32:46 +00:00
|
|
|
|
* @eventType broadcast on root scope
|
|
|
|
|
|
* @description
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* Broadcasted after a route dependencies are resolved.
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* {@link ng.directive:ngView ngView} listens for the directive
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* to instantiate the controller and render the view.
|
2011-11-02 23:32:46 +00:00
|
|
|
|
*
|
2013-03-15 09:24:52 +00:00
|
|
|
|
* @param {Object} angularEvent Synthetic event object.
|
2011-11-02 23:32:46 +00:00
|
|
|
|
* @param {Route} current Current route information.
|
2013-03-15 09:24:52 +00:00
|
|
|
|
* @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered.
|
2011-11-02 23:32:46 +00:00
|
|
|
|
*/
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2012-05-23 04:12:19 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc event
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$route#$routeChangeError
|
|
|
|
|
|
* @eventOf ng.$route
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* @eventType broadcast on root scope
|
|
|
|
|
|
* @description
|
|
|
|
|
|
* Broadcasted if any of the resolve promises are rejected.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {Route} current Current route information.
|
|
|
|
|
|
* @param {Route} previous Previous route information.
|
|
|
|
|
|
* @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc event
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$route#$routeUpdate
|
|
|
|
|
|
* @eventOf ng.$route
|
2012-02-19 20:59:10 +00:00
|
|
|
|
* @eventType broadcast on root scope
|
2011-11-02 23:32:46 +00:00
|
|
|
|
* @description
|
|
|
|
|
|
*
|
|
|
|
|
|
* The `reloadOnSearch` property has been set to false, and we are reusing the same
|
|
|
|
|
|
* instance of the Controller.
|
|
|
|
|
|
*/
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2013-01-14 19:01:51 +00:00
|
|
|
|
var forceReload = false,
|
2011-11-02 23:32:46 +00:00
|
|
|
|
$route = {
|
|
|
|
|
|
routes: routes,
|
2011-02-15 06:12:45 +00:00
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @ngdoc method
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* @name ng.$route#reload
|
|
|
|
|
|
* @methodOf ng.$route
|
2011-11-02 23:32:46 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @description
|
2012-05-23 04:12:19 +00:00
|
|
|
|
* Causes `$route` service to reload the current route even if
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* {@link ng.$location $location} hasn't changed.
|
2012-02-29 22:56:29 +00:00
|
|
|
|
*
|
2012-06-12 06:49:24 +00:00
|
|
|
|
* As a result of that, {@link ng.directive:ngView ngView}
|
2012-02-29 22:56:29 +00:00
|
|
|
|
* creates new scope, reinstantiates the controller.
|
2011-11-02 23:32:46 +00:00
|
|
|
|
*/
|
|
|
|
|
|
reload: function() {
|
|
|
|
|
|
forceReload = true;
|
2012-05-22 23:45:56 +00:00
|
|
|
|
$rootScope.$evalAsync(updateRoute);
|
2011-11-02 23:32:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
};
|
2011-02-15 06:12:45 +00:00
|
|
|
|
|
2012-05-22 23:45:56 +00:00
|
|
|
|
$rootScope.$on('$locationChangeSuccess', updateRoute);
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
return $route;
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/////////////////////////////////////////////////////
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2013-01-14 19:01:51 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param on {string} current url
|
|
|
|
|
|
* @param when {string} route when template to match the url against
|
2013-02-23 20:45:48 +00:00
|
|
|
|
* @param whenProperties {Object} properties to define when's matching behavior
|
2013-01-14 19:01:51 +00:00
|
|
|
|
* @return {?Object}
|
|
|
|
|
|
*/
|
2013-02-23 20:45:48 +00:00
|
|
|
|
function switchRouteMatcher(on, when, whenProperties) {
|
2011-11-02 23:32:46 +00:00
|
|
|
|
// TODO(i): this code is convoluted and inefficient, we should construct the route matching
|
|
|
|
|
|
// regex only once and then reuse it
|
2013-01-14 19:01:51 +00:00
|
|
|
|
|
|
|
|
|
|
// Escape regexp special characters.
|
2012-11-12 21:09:53 +00:00
|
|
|
|
when = '^' + when.replace(/[-\/\\^$:*+?.()|[\]{}]/g, "\\$&") + '$';
|
2013-02-23 20:45:48 +00:00
|
|
|
|
|
2013-01-14 19:01:51 +00:00
|
|
|
|
var regex = '',
|
2011-11-02 23:32:46 +00:00
|
|
|
|
params = [],
|
|
|
|
|
|
dst = {};
|
2013-01-14 19:01:51 +00:00
|
|
|
|
|
2012-11-12 21:09:53 +00:00
|
|
|
|
var re = /\\([:*])(\w+)/g,
|
2013-01-14 19:01:51 +00:00
|
|
|
|
paramMatch,
|
|
|
|
|
|
lastMatchedIndex = 0;
|
|
|
|
|
|
|
|
|
|
|
|
while ((paramMatch = re.exec(when)) !== null) {
|
|
|
|
|
|
// Find each :param in `when` and replace it with a capturing group.
|
|
|
|
|
|
// Append all other sections of when unchanged.
|
|
|
|
|
|
regex += when.slice(lastMatchedIndex, paramMatch.index);
|
2012-11-12 21:09:53 +00:00
|
|
|
|
switch(paramMatch[1]) {
|
|
|
|
|
|
case ':':
|
|
|
|
|
|
regex += '([^\\/]*)';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '*':
|
|
|
|
|
|
regex += '(.*)';
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
params.push(paramMatch[2]);
|
2013-01-14 19:01:51 +00:00
|
|
|
|
lastMatchedIndex = re.lastIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
// Append trailing path part.
|
|
|
|
|
|
regex += when.substr(lastMatchedIndex);
|
|
|
|
|
|
|
2013-02-23 20:45:48 +00:00
|
|
|
|
var match = on.match(new RegExp(regex, whenProperties.caseInsensitiveMatch ? 'i' : ''));
|
2011-11-02 23:32:46 +00:00
|
|
|
|
if (match) {
|
|
|
|
|
|
forEach(params, function(name, index) {
|
|
|
|
|
|
dst[name] = match[index + 1];
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return match ? dst : null;
|
2011-02-15 06:12:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
function updateRoute() {
|
|
|
|
|
|
var next = parseRoute(),
|
2012-02-19 20:31:11 +00:00
|
|
|
|
last = $route.current;
|
2011-02-15 06:12:45 +00:00
|
|
|
|
|
2013-03-08 19:43:37 +00:00
|
|
|
|
if (next && last && next.$$route === last.$$route
|
2011-11-02 23:32:46 +00:00
|
|
|
|
&& equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
|
2012-02-19 20:31:11 +00:00
|
|
|
|
last.params = next.params;
|
|
|
|
|
|
copy(last.params, $routeParams);
|
|
|
|
|
|
$rootScope.$broadcast('$routeUpdate', last);
|
|
|
|
|
|
} else if (next || last) {
|
2011-11-02 23:32:46 +00:00
|
|
|
|
forceReload = false;
|
2012-06-01 18:31:10 +00:00
|
|
|
|
$rootScope.$broadcast('$routeChangeStart', next, last);
|
2011-11-02 23:32:46 +00:00
|
|
|
|
$route.current = next;
|
|
|
|
|
|
if (next) {
|
|
|
|
|
|
if (next.redirectTo) {
|
|
|
|
|
|
if (isString(next.redirectTo)) {
|
|
|
|
|
|
$location.path(interpolate(next.redirectTo, next.params)).search(next.params)
|
|
|
|
|
|
.replace();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
|
|
|
|
|
|
.replace();
|
|
|
|
|
|
}
|
2011-07-12 00:18:17 +00:00
|
|
|
|
}
|
2011-08-24 05:30:14 +00:00
|
|
|
|
}
|
2012-05-23 04:12:19 +00:00
|
|
|
|
|
|
|
|
|
|
$q.when(next).
|
|
|
|
|
|
then(function() {
|
|
|
|
|
|
if (next) {
|
2013-02-24 08:11:25 +00:00
|
|
|
|
var locals = extend({}, next.resolve),
|
2012-05-17 23:36:18 +00:00
|
|
|
|
template;
|
2012-05-23 04:12:19 +00:00
|
|
|
|
|
2013-02-24 08:11:25 +00:00
|
|
|
|
forEach(locals, function(value, key) {
|
|
|
|
|
|
locals[key] = isString(value) ? $injector.get(value) : $injector.invoke(value);
|
2012-05-23 04:12:19 +00:00
|
|
|
|
});
|
2013-02-24 08:11:25 +00:00
|
|
|
|
|
2012-05-17 23:36:18 +00:00
|
|
|
|
if (isDefined(template = next.template)) {
|
2012-11-03 20:11:07 +00:00
|
|
|
|
if (isFunction(template)) {
|
|
|
|
|
|
template = template(next.params);
|
|
|
|
|
|
}
|
2012-05-17 23:36:18 +00:00
|
|
|
|
} else if (isDefined(template = next.templateUrl)) {
|
2012-11-03 20:11:07 +00:00
|
|
|
|
if (isFunction(template)) {
|
|
|
|
|
|
template = template(next.params);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isDefined(template)) {
|
|
|
|
|
|
next.loadedTemplateUrl = template;
|
|
|
|
|
|
template = $http.get(template, {cache: $templateCache}).
|
|
|
|
|
|
then(function(response) { return response.data; });
|
|
|
|
|
|
}
|
2012-05-17 23:36:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
if (isDefined(template)) {
|
2013-02-24 08:11:25 +00:00
|
|
|
|
locals['$template'] = template;
|
2012-05-23 04:12:19 +00:00
|
|
|
|
}
|
2013-02-24 08:11:25 +00:00
|
|
|
|
return $q.all(locals);
|
2012-05-23 04:12:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
}).
|
|
|
|
|
|
// after route change
|
|
|
|
|
|
then(function(locals) {
|
|
|
|
|
|
if (next == $route.current) {
|
|
|
|
|
|
if (next) {
|
|
|
|
|
|
next.locals = locals;
|
|
|
|
|
|
copy(next.params, $routeParams);
|
|
|
|
|
|
}
|
2012-06-01 18:31:10 +00:00
|
|
|
|
$rootScope.$broadcast('$routeChangeSuccess', next, last);
|
2012-05-23 04:12:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
}, function(error) {
|
|
|
|
|
|
if (next == $route.current) {
|
|
|
|
|
|
$rootScope.$broadcast('$routeChangeError', next, last, error);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2011-08-15 15:34:11 +00:00
|
|
|
|
}
|
2011-03-23 16:33:29 +00:00
|
|
|
|
}
|
2011-08-24 05:30:14 +00:00
|
|
|
|
|
2011-08-15 15:34:11 +00:00
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @returns the current active route, by matching it against the URL
|
|
|
|
|
|
*/
|
|
|
|
|
|
function parseRoute() {
|
|
|
|
|
|
// Match a route
|
|
|
|
|
|
var params, match;
|
|
|
|
|
|
forEach(routes, function(route, path) {
|
2013-02-23 20:45:48 +00:00
|
|
|
|
if (!match && (params = switchRouteMatcher($location.path(), path, route))) {
|
2011-11-02 23:32:46 +00:00
|
|
|
|
match = inherit(route, {
|
|
|
|
|
|
params: extend({}, $location.search(), params),
|
|
|
|
|
|
pathParams: params});
|
2013-03-08 19:43:37 +00:00
|
|
|
|
match.$$route = route;
|
2011-11-02 23:32:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
// No route matched; fallback to "otherwise" route
|
|
|
|
|
|
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
|
|
|
|
|
|
}
|
2011-02-15 06:12:45 +00:00
|
|
|
|
|
2011-11-02 23:32:46 +00:00
|
|
|
|
/**
|
2013-03-21 19:09:47 +00:00
|
|
|
|
* @returns interpolation of the redirect path with the parameters
|
2011-11-02 23:32:46 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function interpolate(string, params) {
|
|
|
|
|
|
var result = [];
|
|
|
|
|
|
forEach((string||'').split(':'), function(segment, i) {
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
|
result.push(segment);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
var segmentMatch = segment.match(/(\w+)(.*)/);
|
|
|
|
|
|
var key = segmentMatch[1];
|
|
|
|
|
|
result.push(params[key]);
|
|
|
|
|
|
result.push(segmentMatch[2] || '');
|
|
|
|
|
|
delete params[key];
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return result.join('');
|
|
|
|
|
|
}
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|