engines/bastion/vendor/assets/javascripts/bastion/angular-route/angular-route.js in katello-3.15.3.1 vs engines/bastion/vendor/assets/javascripts/bastion/angular-route/angular-route.js in katello-3.16.0.rc1
- old
+ new
@@ -1,47 +1,139 @@
/**
- * @license AngularJS v1.5.5
- * (c) 2010-2016 Google, Inc. http://angularjs.org
+ * @license AngularJS v1.7.9
+ * (c) 2010-2018 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular) {'use strict';
+/* global shallowCopy: true */
+
/**
+ * Creates a shallow copy of an object, an array or a primitive.
+ *
+ * Assumes that there are no proto properties for objects.
+ */
+function shallowCopy(src, dst) {
+ if (isArray(src)) {
+ dst = dst || [];
+
+ for (var i = 0, ii = src.length; i < ii; i++) {
+ dst[i] = src[i];
+ }
+ } else if (isObject(src)) {
+ dst = dst || {};
+
+ for (var key in src) {
+ if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
+ dst[key] = src[key];
+ }
+ }
+ }
+
+ return dst || src;
+}
+
+/* global routeToRegExp: true */
+
+/**
+ * @param {string} path - The path to parse. (It is assumed to have query and hash stripped off.)
+ * @param {Object} opts - Options.
+ * @return {Object} - An object containing an array of path parameter names (`keys`) and a regular
+ * expression (`regexp`) that can be used to identify a matching URL and extract the path
+ * parameter values.
+ *
+ * @description
+ * Parses the given path, extracting path parameter names and a regular expression to match URLs.
+ *
+ * Originally inspired by `pathRexp` in `visionmedia/express/lib/utils.js`.
+ */
+function routeToRegExp(path, opts) {
+ var keys = [];
+
+ var pattern = path
+ .replace(/([().])/g, '\\$1')
+ .replace(/(\/)?:(\w+)(\*\?|[?*])?/g, function(_, slash, key, option) {
+ var optional = option === '?' || option === '*?';
+ var star = option === '*' || option === '*?';
+ keys.push({name: key, optional: optional});
+ slash = slash || '';
+ return (
+ (optional ? '(?:' + slash : slash + '(?:') +
+ (star ? '(.+?)' : '([^/]+)') +
+ (optional ? '?)?' : ')')
+ );
+ })
+ .replace(/([/$*])/g, '\\$1');
+
+ if (opts.ignoreTrailingSlashes) {
+ pattern = pattern.replace(/\/+$/, '') + '/*';
+ }
+
+ return {
+ keys: keys,
+ regexp: new RegExp(
+ '^' + pattern + '(?:[?#]|$)',
+ opts.caseInsensitiveMatch ? 'i' : ''
+ )
+ };
+}
+
+/* global routeToRegExp: false */
+/* global shallowCopy: false */
+
+// `isArray` and `isObject` are necessary for `shallowCopy()` (included via `src/shallowCopy.js`).
+// They are initialized inside the `$RouteProvider`, to ensure `window.angular` is available.
+var isArray;
+var isObject;
+var isDefined;
+var noop;
+
+/**
* @ngdoc module
* @name ngRoute
* @description
*
- * # ngRoute
+ * The `ngRoute` module provides routing and deeplinking services and directives for AngularJS apps.
*
- * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
- *
* ## Example
- * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
+ * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`.
*
- *
- * <div doc-module-components="ngRoute"></div>
*/
- /* global -ngRouteModule */
-var ngRouteModule = angular.module('ngRoute', ['ng']).
- provider('$route', $RouteProvider),
- $routeMinErr = angular.$$minErr('ngRoute');
+/* global -ngRouteModule */
+var ngRouteModule = angular.
+ module('ngRoute', []).
+ info({ angularVersion: '1.7.9' }).
+ provider('$route', $RouteProvider).
+ // Ensure `$route` will be instantiated in time to capture the initial `$locationChangeSuccess`
+ // event (unless explicitly disabled). This is necessary in case `ngView` is included in an
+ // asynchronously loaded template.
+ run(instantiateRoute);
+var $routeMinErr = angular.$$minErr('ngRoute');
+var isEagerInstantiationEnabled;
+
/**
* @ngdoc provider
* @name $routeProvider
+ * @this
*
* @description
*
* Used for configuring routes.
*
* ## Example
- * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
+ * See {@link ngRoute.$route#examples $route} for an example of configuring and using `ngRoute`.
*
* ## Dependencies
* Requires the {@link ngRoute `ngRoute`} module to be installed.
*/
function $RouteProvider() {
+ isArray = angular.isArray;
+ isObject = angular.isObject;
+ isDefined = angular.isDefined;
+ noop = angular.noop;
+
function inherit(parent, extra) {
return angular.extend(Object.create(parent), extra);
}
var routes = {};
@@ -73,34 +165,38 @@
* @param {Object} route Mapping information to be assigned to `$route.current` on route
* match.
*
* Object properties:
*
- * - `controller` – `{(string|function()=}` – Controller fn that should be associated with
+ * - `controller` – `{(string|Function)=}` – Controller fn that should be associated with
* newly created scope or the name of a {@link angular.Module#controller registered
* controller} if passed as a string.
* - `controllerAs` – `{string=}` – An identifier name for a reference to the controller.
* If present, the controller will be published to scope under the `controllerAs` name.
- * - `template` – `{string=|function()=}` – html template as a string or a function that
+ * - `template` – `{(string|Function)=}` – html template as a string or a function that
* returns an html template as a string which should be used by {@link
* ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
* 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
+ * One of `template` or `templateUrl` is required.
+ *
+ * - `templateUrl` – `{(string|Function)=}` – path or function that returns a path to an html
* template that should be used by {@link ngRoute.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
*
- * - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
+ * One of `templateUrl` or `template` is required.
+ *
+ * - `resolve` - `{Object.<string, Function>=}` - An optional map of dependencies which should
* be injected into the controller. If any of these dependencies are promises, the router
* will wait for them all to be resolved or one to be rejected before the controller is
* instantiated.
* If all the promises are resolved successfully, the values of the resolved promises are
* injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
@@ -116,39 +212,74 @@
* does not collide with other properties on the scope.
* </div>
* The map object is:
*
* - `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.
+ * - `factory` - `{string|Function}`: If `string` then it is an alias for a service.
* Otherwise if function, then it is {@link auto.$injector#invoke injected}
* 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. Be aware that
* `ngRoute.$routeParams` will still refer to the previous route within these resolve
* functions. Use `$route.current.params` to access the new route parameters, instead.
*
* - `resolveAs` - `{string=}` - The name under which the `resolve` map will be available on
* the scope of the route. If omitted, defaults to `$resolve`.
*
- * - `redirectTo` – `{(string|function())=}` – value to update
+ * - `redirectTo` – `{(string|Function)=}` – value to update
* {@link ng.$location $location} path with and trigger route redirection.
*
* If `redirectTo` is a function, it will be called with the following parameters:
*
* - `{Object.<string>}` - route parameters extracted from the current
* `$location.path()` by applying the current route templateUrl.
* - `{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()`.
+ * to update `$location.url()`. If the function throws an error, no further processing will
+ * take place and the {@link ngRoute.$route#$routeChangeError $routeChangeError} event will
+ * be fired.
*
+ * Routes that specify `redirectTo` will not have their controllers, template functions
+ * or resolves called, the `$location` will be changed to the redirect url and route
+ * processing will stop. The exception to this is if the `redirectTo` is a function that
+ * returns `undefined`. In this case the route transition occurs as though there was no
+ * redirection.
+ *
+ * - `resolveRedirectTo` – `{Function=}` – a function that will (eventually) return the value
+ * to update {@link ng.$location $location} URL with and trigger route redirection. In
+ * contrast to `redirectTo`, dependencies can be injected into `resolveRedirectTo` and the
+ * return value can be either a string or a promise that will be resolved to a string.
+ *
+ * Similar to `redirectTo`, if the return value is `undefined` (or a promise that gets
+ * resolved to `undefined`), no redirection takes place and the route transition occurs as
+ * though there was no redirection.
+ *
+ * If the function throws an error or the returned promise gets rejected, no further
+ * processing will take place and the
+ * {@link ngRoute.$route#$routeChangeError $routeChangeError} event will be fired.
+ *
+ * `redirectTo` takes precedence over `resolveRedirectTo`, so specifying both on the same
+ * route definition, will cause the latter to be ignored.
+ *
+ * - `[reloadOnUrl=true]` - `{boolean=}` - reload route when any part of the URL changes
+ * (including the path) even if the new URL maps to the same route.
+ *
+ * If the option is set to `false` and the URL in the browser changes, but the new URL maps
+ * to the same route, then a `$routeUpdate` event is broadcasted on the root scope (without
+ * reloading the route).
+ *
* - `[reloadOnSearch=true]` - `{boolean=}` - reload route when only `$location.search()`
* or `$location.hash()` changes.
*
- * If the option is set to `false` and url in the browser changes, then
- * `$routeUpdate` event is broadcasted on the root scope.
+ * If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate`
+ * event is broadcasted on the root scope (without reloading the route).
*
+ * <div class="alert alert-warning">
+ * **Note:** This option has no effect if `reloadOnUrl` is set to `false`.
+ * </div>
+ *
* - `[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
*
@@ -157,31 +288,35 @@
* @description
* Adds a new route definition to the `$route` service.
*/
this.when = function(path, route) {
//copy original route object to preserve params inherited from proto chain
- var routeCopy = angular.copy(route);
+ var routeCopy = shallowCopy(route);
+ if (angular.isUndefined(routeCopy.reloadOnUrl)) {
+ routeCopy.reloadOnUrl = true;
+ }
if (angular.isUndefined(routeCopy.reloadOnSearch)) {
routeCopy.reloadOnSearch = true;
}
if (angular.isUndefined(routeCopy.caseInsensitiveMatch)) {
routeCopy.caseInsensitiveMatch = this.caseInsensitiveMatch;
}
routes[path] = angular.extend(
routeCopy,
- path && pathRegExp(path, routeCopy)
+ {originalPath: path},
+ path && routeToRegExp(path, routeCopy)
);
// create redirection for trailing slashes
if (path) {
- var redirectPath = (path[path.length - 1] == '/')
+ var redirectPath = (path[path.length - 1] === '/')
? path.substr(0, path.length - 1)
: path + '/';
routes[redirectPath] = angular.extend(
- {redirectTo: path},
- pathRegExp(redirectPath, routeCopy)
+ {originalPath: path, redirectTo: path},
+ routeToRegExp(redirectPath, routeCopy)
);
}
return this;
};
@@ -195,51 +330,10 @@
* using this provider should be matched using a case insensitive
* algorithm. Defaults to `false`.
*/
this.caseInsensitiveMatch = false;
- /**
- * @param path {string} path
- * @param opts {Object} options
- * @return {?Object}
- *
- * @description
- * Normalizes the given path, returning a regular expression
- * and the original path.
- *
- * Inspired by pathRexp in visionmedia/express/lib/utils.js.
- */
- function pathRegExp(path, opts) {
- var insensitive = opts.caseInsensitiveMatch,
- ret = {
- originalPath: path,
- regexp: path
- },
- keys = ret.keys = [];
-
- path = path
- .replace(/([().])/g, '\\$1')
- .replace(/(\/)?:(\w+)(\*\?|[\?\*])?/g, function(_, slash, key, option) {
- var optional = (option === '?' || option === '*?') ? '?' : null;
- var star = (option === '*' || option === '*?') ? '*' : null;
- keys.push({ name: key, optional: !!optional });
- slash = slash || '';
- return ''
- + (optional ? '' : slash)
- + '(?:'
- + (optional ? slash : '')
- + (star && '(.+?)' || '([^/]+)')
- + (optional || '')
- + ')'
- + (optional || '');
- })
- .replace(/([\/$\*])/g, '\\$1');
-
- ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
- return ret;
- }
-
/**
* @ngdoc method
* @name $routeProvider#otherwise
*
* @description
@@ -256,19 +350,61 @@
}
this.when(null, params);
return this;
};
+ /**
+ * @ngdoc method
+ * @name $routeProvider#eagerInstantiationEnabled
+ * @kind function
+ *
+ * @description
+ * Call this method as a setter to enable/disable eager instantiation of the
+ * {@link ngRoute.$route $route} service upon application bootstrap. You can also call it as a
+ * getter (i.e. without any arguments) to get the current value of the
+ * `eagerInstantiationEnabled` flag.
+ *
+ * Instantiating `$route` early is necessary for capturing the initial
+ * {@link ng.$location#$locationChangeStart $locationChangeStart} event and navigating to the
+ * appropriate route. Usually, `$route` is instantiated in time by the
+ * {@link ngRoute.ngView ngView} directive. Yet, in cases where `ngView` is included in an
+ * asynchronously loaded template (e.g. in another directive's template), the directive factory
+ * might not be called soon enough for `$route` to be instantiated _before_ the initial
+ * `$locationChangeSuccess` event is fired. Eager instantiation ensures that `$route` is always
+ * instantiated in time, regardless of when `ngView` will be loaded.
+ *
+ * The default value is true.
+ *
+ * **Note**:<br />
+ * You may want to disable the default behavior when unit-testing modules that depend on
+ * `ngRoute`, in order to avoid an unexpected request for the default route's template.
+ *
+ * @param {boolean=} enabled - If provided, update the internal `eagerInstantiationEnabled` flag.
+ *
+ * @returns {*} The current value of the `eagerInstantiationEnabled` flag if used as a getter or
+ * itself (for chaining) if used as a setter.
+ */
+ isEagerInstantiationEnabled = true;
+ this.eagerInstantiationEnabled = function eagerInstantiationEnabled(enabled) {
+ if (isDefined(enabled)) {
+ isEagerInstantiationEnabled = enabled;
+ return this;
+ }
+ return isEagerInstantiationEnabled;
+ };
+
+
this.$get = ['$rootScope',
'$location',
'$routeParams',
'$q',
'$injector',
'$templateRequest',
'$sce',
- function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
+ '$browser',
+ function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce, $browser) {
/**
* @ngdoc service
* @name $route
* @requires $location
@@ -349,16 +485,16 @@
* $scope.$location = $location;
* $scope.$routeParams = $routeParams;
* })
*
* .controller('BookController', function($scope, $routeParams) {
- * $scope.name = "BookController";
+ * $scope.name = 'BookController';
* $scope.params = $routeParams;
* })
*
* .controller('ChapterController', function($scope, $routeParams) {
- * $scope.name = "ChapterController";
+ * $scope.name = 'ChapterController';
* $scope.params = $routeParams;
* })
*
* .config(function($routeProvider, $locationProvider) {
* $routeProvider
@@ -387,19 +523,19 @@
*
* <file name="protractor.js" type="protractor">
* it('should load and compile correct template', function() {
* element(by.linkText('Moby: Ch1')).click();
* var content = element(by.css('[ng-view]')).getText();
- * expect(content).toMatch(/controller\: ChapterController/);
- * expect(content).toMatch(/Book Id\: Moby/);
- * expect(content).toMatch(/Chapter Id\: 1/);
+ * expect(content).toMatch(/controller: ChapterController/);
+ * expect(content).toMatch(/Book Id: Moby/);
+ * expect(content).toMatch(/Chapter Id: 1/);
*
* element(by.partialLinkText('Scarlet')).click();
*
* content = element(by.css('[ng-view]')).getText();
- * expect(content).toMatch(/controller\: BookController/);
- * expect(content).toMatch(/Book Id\: Scarlet/);
+ * expect(content).toMatch(/controller: BookController/);
+ * expect(content).toMatch(/Book Id: Scarlet/);
* });
* </file>
* </example>
*/
@@ -443,25 +579,28 @@
/**
* @ngdoc event
* @name $route#$routeChangeError
* @eventType broadcast on root scope
* @description
- * Broadcasted if any of the resolve promises are rejected.
+ * Broadcasted if a redirection function fails or any redirection or resolve promises are
+ * rejected.
*
* @param {Object} angularEvent Synthetic event object
* @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.
+ * @param {Route} rejection The thrown error or the rejection reason of the promise. Usually
+ * the rejection reason is the error that caused the promise to get rejected.
*/
/**
* @ngdoc event
* @name $route#$routeUpdate
* @eventType broadcast on root scope
* @description
- * The `reloadOnSearch` property has been set to false, and we are reusing the same
- * instance of the Controller.
+ * Broadcasted if the same instance of a route (including template, controller instance,
+ * resolved dependencies, etc.) is being reused. This can happen if either `reloadOnSearch` or
+ * `reloadOnUrl` has been set to `false`.
*
* @param {Object} angularEvent Synthetic event object
* @param {Route} current Current/previous route information.
*/
@@ -517,11 +656,11 @@
newParams = angular.extend({}, this.current.params, newParams);
$location.path(interpolate(this.current.$$route.originalPath, newParams));
// interpolate modifies newParams, only query params are left
$location.search(newParams);
} else {
- throw $routeMinErr('norout', 'Tried updating route when with no current route');
+ throw $routeMinErr('norout', 'Tried updating route with no current route');
}
}
};
$rootScope.$on('$locationChangeStart', prepareRoute);
@@ -565,13 +704,11 @@
function prepareRoute($locationEvent) {
var lastRoute = $route.current;
preparedRoute = parseRoute();
- preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route
- && angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
- && !preparedRoute.reloadOnSearch && !forceReload;
+ preparedRouteIsUpdateOnly = isNavigationUpdateOnly(preparedRoute, lastRoute);
if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
if ($locationEvent) {
$locationEvent.preventDefault();
@@ -589,70 +726,150 @@
angular.copy(lastRoute.params, $routeParams);
$rootScope.$broadcast('$routeUpdate', lastRoute);
} else if (nextRoute || lastRoute) {
forceReload = false;
$route.current = nextRoute;
- if (nextRoute) {
- if (nextRoute.redirectTo) {
- if (angular.isString(nextRoute.redirectTo)) {
- $location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
- .replace();
- } else {
- $location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
- .replace();
- }
- }
- }
- $q.when(nextRoute).
- then(function() {
- if (nextRoute) {
- var locals = angular.extend({}, nextRoute.resolve),
- template, templateUrl;
+ var nextRoutePromise = $q.resolve(nextRoute);
- angular.forEach(locals, function(value, key) {
- locals[key] = angular.isString(value) ?
- $injector.get(value) : $injector.invoke(value, null, null, key);
- });
+ $browser.$$incOutstandingRequestCount('$route');
- if (angular.isDefined(template = nextRoute.template)) {
- if (angular.isFunction(template)) {
- template = template(nextRoute.params);
+ nextRoutePromise.
+ then(getRedirectionData).
+ then(handlePossibleRedirection).
+ then(function(keepProcessingRoute) {
+ return keepProcessingRoute && nextRoutePromise.
+ then(resolveLocals).
+ then(function(locals) {
+ // after route change
+ if (nextRoute === $route.current) {
+ if (nextRoute) {
+ nextRoute.locals = locals;
+ angular.copy(nextRoute.params, $routeParams);
+ }
+ $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
}
- } else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
- if (angular.isFunction(templateUrl)) {
- templateUrl = templateUrl(nextRoute.params);
- }
- if (angular.isDefined(templateUrl)) {
- nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl);
- template = $templateRequest(templateUrl);
- }
- }
- if (angular.isDefined(template)) {
- locals['$template'] = template;
- }
- return $q.all(locals);
- }
- }).
- then(function(locals) {
- // after route change
- if (nextRoute == $route.current) {
- if (nextRoute) {
- nextRoute.locals = locals;
- angular.copy(nextRoute.params, $routeParams);
- }
- $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
- }
- }, function(error) {
- if (nextRoute == $route.current) {
+ });
+ }).catch(function(error) {
+ if (nextRoute === $route.current) {
$rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
}
+ }).finally(function() {
+ // Because `commitRoute()` is called from a `$rootScope.$evalAsync` block (see
+ // `$locationWatch`), this `$$completeOutstandingRequest()` call will not cause
+ // `outstandingRequestCount` to hit zero. This is important in case we are redirecting
+ // to a new route which also requires some asynchronous work.
+
+ $browser.$$completeOutstandingRequest(noop, '$route');
});
}
}
+ function getRedirectionData(route) {
+ var data = {
+ route: route,
+ hasRedirection: false
+ };
+ if (route) {
+ if (route.redirectTo) {
+ if (angular.isString(route.redirectTo)) {
+ data.path = interpolate(route.redirectTo, route.params);
+ data.search = route.params;
+ data.hasRedirection = true;
+ } else {
+ var oldPath = $location.path();
+ var oldSearch = $location.search();
+ var newUrl = route.redirectTo(route.pathParams, oldPath, oldSearch);
+
+ if (angular.isDefined(newUrl)) {
+ data.url = newUrl;
+ data.hasRedirection = true;
+ }
+ }
+ } else if (route.resolveRedirectTo) {
+ return $q.
+ resolve($injector.invoke(route.resolveRedirectTo)).
+ then(function(newUrl) {
+ if (angular.isDefined(newUrl)) {
+ data.url = newUrl;
+ data.hasRedirection = true;
+ }
+
+ return data;
+ });
+ }
+ }
+
+ return data;
+ }
+
+ function handlePossibleRedirection(data) {
+ var keepProcessingRoute = true;
+
+ if (data.route !== $route.current) {
+ keepProcessingRoute = false;
+ } else if (data.hasRedirection) {
+ var oldUrl = $location.url();
+ var newUrl = data.url;
+
+ if (newUrl) {
+ $location.
+ url(newUrl).
+ replace();
+ } else {
+ newUrl = $location.
+ path(data.path).
+ search(data.search).
+ replace().
+ url();
+ }
+
+ if (newUrl !== oldUrl) {
+ // Exit out and don't process current next value,
+ // wait for next location change from redirect
+ keepProcessingRoute = false;
+ }
+ }
+
+ return keepProcessingRoute;
+ }
+
+ function resolveLocals(route) {
+ if (route) {
+ var locals = angular.extend({}, route.resolve);
+ angular.forEach(locals, function(value, key) {
+ locals[key] = angular.isString(value) ?
+ $injector.get(value) :
+ $injector.invoke(value, null, null, key);
+ });
+ var template = getTemplateFor(route);
+ if (angular.isDefined(template)) {
+ locals['$template'] = template;
+ }
+ return $q.all(locals);
+ }
+ }
+
+ function getTemplateFor(route) {
+ var template, templateUrl;
+ if (angular.isDefined(template = route.template)) {
+ if (angular.isFunction(template)) {
+ template = template(route.params);
+ }
+ } else if (angular.isDefined(templateUrl = route.templateUrl)) {
+ if (angular.isFunction(templateUrl)) {
+ templateUrl = templateUrl(route.params);
+ }
+ if (angular.isDefined(templateUrl)) {
+ route.loadedTemplateUrl = $sce.valueOf(templateUrl);
+ template = $templateRequest(templateUrl);
+ }
+ }
+ return template;
+ }
+
/**
* @returns {Object} the current active route, by matching it against the URL
*/
function parseRoute() {
// Match a route
@@ -668,10 +885,33 @@
// No route matched; fallback to "otherwise" route
return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
}
/**
+ * @param {Object} newRoute - The new route configuration (as returned by `parseRoute()`).
+ * @param {Object} oldRoute - The previous route configuration (as returned by `parseRoute()`).
+ * @returns {boolean} Whether this is an "update-only" navigation, i.e. the URL maps to the same
+ * route and it can be reused (based on the config and the type of change).
+ */
+ function isNavigationUpdateOnly(newRoute, oldRoute) {
+ // IF this is not a forced reload
+ return !forceReload
+ // AND both `newRoute`/`oldRoute` are defined
+ && newRoute && oldRoute
+ // AND they map to the same Route Definition Object
+ && (newRoute.$$route === oldRoute.$$route)
+ // AND `reloadOnUrl` is disabled
+ && (!newRoute.reloadOnUrl
+ // OR `reloadOnSearch` is disabled
+ || (!newRoute.reloadOnSearch
+ // AND both routes have the same path params
+ && angular.equals(newRoute.pathParams, oldRoute.pathParams)
+ )
+ );
+ }
+
+ /**
* @returns {string} interpolation of the redirect path with the parameters
*/
function interpolate(string, params) {
var result = [];
angular.forEach((string || '').split(':'), function(segment, i) {
@@ -688,17 +928,26 @@
return result.join('');
}
}];
}
+instantiateRoute.$inject = ['$injector'];
+function instantiateRoute($injector) {
+ if (isEagerInstantiationEnabled) {
+ // Instantiate `$route`
+ $injector.get('$route');
+ }
+}
+
ngRouteModule.provider('$routeParams', $RouteParamsProvider);
/**
* @ngdoc service
* @name $routeParams
* @requires $route
+ * @this
*
* @description
* The `$routeParams` service allows you to retrieve the current set of route parameters.
*
* Requires the {@link ngRoute `ngRoute`} module to be installed.
@@ -738,11 +987,10 @@
* @ngdoc directive
* @name ngView
* @restrict ECA
*
* @description
- * # Overview
* `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
* including the rendered template of the current route into the main layout (`index.html`) file.
* Every time the current route changes, the included view changes with it according to the
* configuration of the `$route` service.
*
@@ -754,17 +1002,10 @@
* | {@link ng.$animate#enter enter} | when the new element is inserted to the DOM |
* | {@link ng.$animate#leave leave} | when the old element is removed from to the DOM |
*
* The enter and leave animation occur concurrently.
*
- * @knownIssue If `ngView` is contained in an asynchronously loaded template (e.g. in another
- * directive's templateUrl or in a template loaded using `ngInclude`), then you need to
- * make sure that `$route` is instantiated in time to capture the initial
- * `$locationChangeStart` event and load the appropriate view. One way to achieve this
- * is to have it as a dependency in a `.run` block:
- * `myModule.run(['$route', function() {}]);`
- *
* @scope
* @priority 400
* @param {string=} onload Expression to evaluate whenever the view updates.
*
* @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
@@ -871,39 +1112,39 @@
});
$locationProvider.html5Mode(true);
}])
.controller('MainCtrl', ['$route', '$routeParams', '$location',
- function($route, $routeParams, $location) {
+ function MainCtrl($route, $routeParams, $location) {
this.$route = $route;
this.$location = $location;
this.$routeParams = $routeParams;
}])
- .controller('BookCtrl', ['$routeParams', function($routeParams) {
- this.name = "BookCtrl";
+ .controller('BookCtrl', ['$routeParams', function BookCtrl($routeParams) {
+ this.name = 'BookCtrl';
this.params = $routeParams;
}])
- .controller('ChapterCtrl', ['$routeParams', function($routeParams) {
- this.name = "ChapterCtrl";
+ .controller('ChapterCtrl', ['$routeParams', function ChapterCtrl($routeParams) {
+ this.name = 'ChapterCtrl';
this.params = $routeParams;
}]);
</file>
<file name="protractor.js" type="protractor">
it('should load and compile correct template', function() {
element(by.linkText('Moby: Ch1')).click();
var content = element(by.css('[ng-view]')).getText();
- expect(content).toMatch(/controller\: ChapterCtrl/);
- expect(content).toMatch(/Book Id\: Moby/);
- expect(content).toMatch(/Chapter Id\: 1/);
+ expect(content).toMatch(/controller: ChapterCtrl/);
+ expect(content).toMatch(/Book Id: Moby/);
+ expect(content).toMatch(/Chapter Id: 1/);
element(by.partialLinkText('Scarlet')).click();
content = element(by.css('[ng-view]')).getText();
- expect(content).toMatch(/controller\: BookCtrl/);
- expect(content).toMatch(/Book Id\: Scarlet/);
+ expect(content).toMatch(/controller: BookCtrl/);
+ expect(content).toMatch(/Book Id: Scarlet/);
});
</file>
</example>
*/
@@ -942,12 +1183,12 @@
currentScope.$destroy();
currentScope = null;
}
if (currentElement) {
previousLeaveAnimation = $animate.leave(currentElement);
- previousLeaveAnimation.then(function() {
- previousLeaveAnimation = null;
+ previousLeaveAnimation.done(function(response) {
+ if (response !== false) previousLeaveAnimation = null;
});
currentElement = null;
}
}
@@ -964,11 +1205,11 @@
// However, using ng-view on an element with additional content does not make sense...
// Note: We can't remove them in the cloneAttchFn of $transclude as that
// function is called before linking the content, which would apply child
// directives to non existing elements.
var clone = $transclude(newScope, function(clone) {
- $animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter() {
- if (angular.isDefined(autoScrollExp)
+ $animate.enter(clone, null, currentElement || $element).done(function onNgViewEnter(response) {
+ if (response !== false && angular.isDefined(autoScrollExp)
&& (!autoScrollExp || scope.$eval(autoScrollExp))) {
$anchorScroll();
}
});
cleanupLastView();