124 lines
4.3 KiB
JavaScript
Raw Normal View History

angular.module('ngComponentRouter').
value('$route', null). // can be overloaded with ngRouteShim
// Because Angular 1 has no notion of a root component, we use an object with unique identity
// to represent this. Can be overloaded with a component name
value('$routerRootComponent', new Object()).
// Unfortunately, $location doesn't expose what the current hashPrefix is
// So we have to monkey patch the $locationProvider to capture this value
provider('$locationHashPrefix', ['$locationProvider', $locationHashPrefixProvider]).
factory('$rootRouter', ['$q', '$location', '$browser', '$rootScope', '$injector', '$routerRootComponent', '$locationHashPrefix', routerFactory]);
function $locationHashPrefixProvider($locationProvider) {
// Get hold of the original hashPrefix method
var hashPrefixFn = $locationProvider.hashPrefix.bind($locationProvider);
// Read the current hashPrefix (in case it was set before this monkey-patch occurred)
var hashPrefix = hashPrefixFn();
// Override the helper so that we can read any changes to the prefix (after this monkey-patch)
$locationProvider.hashPrefix = function(prefix) {
if (angular.isDefined(prefix)) {
hashPrefix = prefix;
}
return hashPrefixFn(prefix);
}
// Return the final hashPrefix as the value of this service
this.$get = function() { return hashPrefix; };
}
function routerFactory($q, $location, $browser, $rootScope, $injector, $routerRootComponent, $locationHashPrefix) {
// When this file is processed, the line below is replaced with
// the contents of `../lib/facades.es5`.
//{{FACADES}}
refactor(router): improve recognition and generation pipeline This is a big change. @matsko also deserves much of the credit for the implementation. Previously, `ComponentInstruction`s held all the state for async components. Now, we introduce several subclasses for `Instruction` to describe each type of navigation. BREAKING CHANGE: Redirects now use the Link DSL syntax. Before: ``` @RouteConfig([ { path: '/foo', redirectTo: '/bar' }, { path: '/bar', component: BarCmp } ]) ``` After: ``` @RouteConfig([ { path: '/foo', redirectTo: ['Bar'] }, { path: '/bar', component: BarCmp, name: 'Bar' } ]) ``` BREAKING CHANGE: This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading and encapsulating large routes with sub-routes easier. Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`: @RouteConfig([ { path: '/tab', redirectTo: '/tab/users' } { path: '/tab', component: TabsCmp, name: 'Tab' } ]) AppCmp { ... } Now the recommended way to handle this is case is to use `useAsDefault` like so: ``` @RouteConfig([ { path: '/tab', component: TabsCmp, name: 'Tab' } ]) AppCmp { ... } @RouteConfig([ { path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' }, { path: '/users', component: UsersCmp, name: 'Users' } ]) TabsCmp { ... } ``` In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route. Closes #4728 Closes #4228 Closes #4170 Closes #4490 Closes #4694 Closes #5200 Closes #5475
2015-11-23 18:07:37 -08:00
var exports = {
Injectable: function () {},
OpaqueToken: function () {},
Inject: function () {}
};
var routerRequire = function () {return exports;};
// When this file is processed, the line below is replaced with
// the contents of the compiled TypeScript classes.
//{{SHARED_CODE}}
function getComponentConstructor(name) {
var serviceName = name + 'Directive';
if ($injector.has(serviceName)) {
var definitions = $injector.get(serviceName);
if (definitions.length > 1) {
throw new BaseException('too many directives named "' + name + '"');
}
return definitions[0].controller;
} else {
throw new BaseException('directive "' + name + '" is not registered');
}
}
//TODO: this is a hack to replace the exiting implementation at run-time
exports.getCanActivateHook = function (directiveName) {
var controller = getComponentConstructor(directiveName);
return controller.$canActivate && function (next, prev) {
return $injector.invoke(controller.$canActivate, null, {
$nextInstruction: next,
$prevInstruction: prev
});
};
};
// This hack removes assertions about the type of the "component"
// property in a route config
exports.assertComponentExists = function () {};
refactor(router): improve recognition and generation pipeline This is a big change. @matsko also deserves much of the credit for the implementation. Previously, `ComponentInstruction`s held all the state for async components. Now, we introduce several subclasses for `Instruction` to describe each type of navigation. BREAKING CHANGE: Redirects now use the Link DSL syntax. Before: ``` @RouteConfig([ { path: '/foo', redirectTo: '/bar' }, { path: '/bar', component: BarCmp } ]) ``` After: ``` @RouteConfig([ { path: '/foo', redirectTo: ['Bar'] }, { path: '/bar', component: BarCmp, name: 'Bar' } ]) ``` BREAKING CHANGE: This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading and encapsulating large routes with sub-routes easier. Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`: @RouteConfig([ { path: '/tab', redirectTo: '/tab/users' } { path: '/tab', component: TabsCmp, name: 'Tab' } ]) AppCmp { ... } Now the recommended way to handle this is case is to use `useAsDefault` like so: ``` @RouteConfig([ { path: '/tab', component: TabsCmp, name: 'Tab' } ]) AppCmp { ... } @RouteConfig([ { path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' }, { path: '/users', component: UsersCmp, name: 'Users' } ]) TabsCmp { ... } ``` In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route. Closes #4728 Closes #4228 Closes #4170 Closes #4490 Closes #4694 Closes #5200 Closes #5475
2015-11-23 18:07:37 -08:00
angular.stringifyInstruction = function (instruction) {
return instruction.toRootUrl();
};
var RouteRegistry = exports.RouteRegistry;
var RootRouter = exports.RootRouter;
// Override this method to actually get hold of the child routes
RouteRegistry.prototype.configFromComponent = function (component) {
var that = this;
if (isString(component)) {
// Don't read the annotations component a type more than once
// this prevents an infinite loop if a component routes recursively.
if (this._rules.has(component)) {
return;
}
var controller = getComponentConstructor(component);
if (angular.isArray(controller.$routeConfig)) {
controller.$routeConfig.forEach(function (config) {
var loader = config.loader;
if (isPresent(loader)) {
config = angular.extend({}, config, { loader: function() { return $injector.invoke(loader); } });
}
that.config(component, config);
});
}
}
}
var registry = new RouteRegistry($routerRootComponent);
var location = new Location();
var router = new RootRouter(registry, location, $routerRootComponent);
$rootScope.$watch(function () { return $location.url(); }, function (path) {
if (router.lastNavigationAttempt !== path) {
router.navigateByUrl(path);
}
});
router.subscribe(function () {
$rootScope.$broadcast('$routeChangeSuccess', {});
});
return router;
}