build: remove modules/angular1_router (#34551)
This code is no longer being used or needed. PR Close #34551
This commit is contained in:
parent
10e29355db
commit
ff72751f13
|
@ -87,7 +87,6 @@ module.exports = function(config) {
|
||||||
'dist/all/@angular/localize/schematics/**',
|
'dist/all/@angular/localize/schematics/**',
|
||||||
'dist/all/@angular/router/**/test/**',
|
'dist/all/@angular/router/**/test/**',
|
||||||
'dist/all/@angular/platform-browser/testing/e2e_util.js',
|
'dist/all/@angular/platform-browser/testing/e2e_util.js',
|
||||||
'dist/all/angular1_router.js',
|
|
||||||
'dist/examples/**/e2e_test/**',
|
'dist/examples/**/e2e_test/**',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var fs = require('fs');
|
|
||||||
var ts = require('typescript');
|
|
||||||
|
|
||||||
var files = [
|
|
||||||
'utils.ts',
|
|
||||||
'url_parser.ts',
|
|
||||||
'lifecycle/lifecycle_annotations_impl.ts',
|
|
||||||
'lifecycle/route_lifecycle_reflector.ts',
|
|
||||||
'route_config/route_config_impl.ts',
|
|
||||||
'route_config/route_config_normalizer.ts',
|
|
||||||
'rules/route_handlers/async_route_handler.ts',
|
|
||||||
'rules/route_handlers/sync_route_handler.ts',
|
|
||||||
'rules/rules.ts',
|
|
||||||
'rules/rule_set.ts',
|
|
||||||
'rules/route_paths/route_path.ts',
|
|
||||||
'rules/route_paths/param_route_path.ts',
|
|
||||||
'rules/route_paths/regex_route_path.ts',
|
|
||||||
'instruction.ts',
|
|
||||||
'route_registry.ts',
|
|
||||||
'router.ts'
|
|
||||||
];
|
|
||||||
|
|
||||||
var PRELUDE = '(function(){\n';
|
|
||||||
var POSTLUDE = '\n}());\n';
|
|
||||||
|
|
||||||
function main(modulesDirectory) {
|
|
||||||
var angular1RouterModuleDirectory = modulesDirectory + '/angular1_router';
|
|
||||||
|
|
||||||
var facades = fs.readFileSync(
|
|
||||||
angular1RouterModuleDirectory + '/lib/facades.es5', 'utf8');
|
|
||||||
var directives = fs.readFileSync(
|
|
||||||
angular1RouterModuleDirectory + '/src/ng_outlet.ts', 'utf8');
|
|
||||||
var moduleTemplate = fs.readFileSync(
|
|
||||||
angular1RouterModuleDirectory + '/src/module_template.js', 'utf8');
|
|
||||||
|
|
||||||
var dir = modulesDirectory + '/angular2/src/router/';
|
|
||||||
var sharedCode = files.reduce(function (prev, file) {
|
|
||||||
return prev + transform(fs.readFileSync(dir + file, 'utf8'));
|
|
||||||
}, '');
|
|
||||||
|
|
||||||
// we have to use a function callback for replace to prevent it from interpreting `$`
|
|
||||||
// as a replacement command character
|
|
||||||
var out = moduleTemplate.replace('//{{FACADES}}', function() { return facades; })
|
|
||||||
.replace('//{{SHARED_CODE}}', function() { return sharedCode; });
|
|
||||||
return PRELUDE + transform(directives) + out + POSTLUDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Given a directory name and a file's TypeScript content, return an object with the ES5 code,
|
|
||||||
* sourcemap, and exported variable identifier name for the content.
|
|
||||||
*/
|
|
||||||
var IMPORT_RE = new RegExp("import \\{?([\\w\\n_, ]+)\\}? from '(.+)';?", 'g');
|
|
||||||
var INJECT_RE = new RegExp("@Inject\\(ROUTER_PRIMARY_COMPONENT\\)", 'g');
|
|
||||||
var INJECTABLE_RE = new RegExp("@Injectable\\(\\)", 'g');
|
|
||||||
var REQUIRE_RE = new RegExp("require\\('(.*?)'\\);", 'g');
|
|
||||||
function transform(contents) {
|
|
||||||
contents = contents.replace(INJECT_RE, '').replace(INJECTABLE_RE, '');
|
|
||||||
contents = contents.replace(IMPORT_RE, function (match, imports, includePath) {
|
|
||||||
//TODO: remove special-case
|
|
||||||
if (isFacadeModule(includePath) || includePath === './router_outlet') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
});
|
|
||||||
contents = ts.transpile(contents, {
|
|
||||||
target: ts.ScriptTarget.ES5,
|
|
||||||
module: ts.ModuleKind.CommonJS
|
|
||||||
});
|
|
||||||
|
|
||||||
// Rename require functions from transpiled imports
|
|
||||||
contents = contents.replace(REQUIRE_RE, 'routerRequire(\'$1\');');
|
|
||||||
|
|
||||||
return contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFacadeModule(modulePath) {
|
|
||||||
return modulePath.indexOf('facade') > -1 ||
|
|
||||||
modulePath === 'angular2/src/core/reflection/reflection';
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = function(modulesDirectory, outputDirectory) {
|
|
||||||
if (!fs.existsSync(outputDirectory)) {
|
|
||||||
fs.mkdirSync(outputDirectory);
|
|
||||||
}
|
|
||||||
fs.writeFileSync(
|
|
||||||
outputDirectory + '/angular_1_router.js', main(modulesDirectory));
|
|
||||||
};
|
|
||||||
|
|
||||||
// CLI entry point
|
|
||||||
if (require.main === module) {
|
|
||||||
try {
|
|
||||||
var args = process.argv;
|
|
||||||
args.shift(); // node
|
|
||||||
args.shift(); // scriptfile.js
|
|
||||||
if (args.length < 2) {
|
|
||||||
// tslint:disable-next-line:no-console
|
|
||||||
console.log("usage: $0 outFile path/to/modules");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
var outfile = args.shift();
|
|
||||||
var directory = args.shift();
|
|
||||||
fs.writeFileSync(outfile, main(directory));
|
|
||||||
} catch (e) {
|
|
||||||
// tslint:disable-next-line:no-console
|
|
||||||
console.log(e.message);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title></title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div ng-app="myApp" ng-controller="MyCtrl">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<script src="../../node_modules/angular/angular.js"></script>
|
|
||||||
<script src="../../dist/angular_1_router.js"></script>
|
|
||||||
<script>
|
|
||||||
angular.module('myApp', ['ngComponentRouter'])
|
|
||||||
.controller('MyCtrl', ['$rootRouter', function ($rootRouter) {
|
|
||||||
console.log($rootRouter);
|
|
||||||
$rootRouter.navigateByUrl('/')
|
|
||||||
.then(console.log.bind(console, 'resolve'), console.log.bind(console, 'reject'));
|
|
||||||
}]);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,38 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var browserProvidersConf = require('../../browser-providers.conf.js');
|
|
||||||
|
|
||||||
// This runs the tests for the router in AngularJS
|
|
||||||
|
|
||||||
module.exports = function (config) {
|
|
||||||
var options = {
|
|
||||||
frameworks: ['jasmine'],
|
|
||||||
|
|
||||||
files: [
|
|
||||||
'../../node_modules/core-js/client/core.js',
|
|
||||||
'../../node_modules/angular/angular.js',
|
|
||||||
'../../node_modules/angular-animate/angular-animate.js',
|
|
||||||
'../../node_modules/angular-mocks/angular-mocks.js',
|
|
||||||
|
|
||||||
'../../dist/angular_1_router.js',
|
|
||||||
'src/ng_route_shim.js',
|
|
||||||
|
|
||||||
'test/*.es5.js',
|
|
||||||
'test/**/*_spec.js'
|
|
||||||
],
|
|
||||||
|
|
||||||
customLaunchers: browserProvidersConf.customLaunchers,
|
|
||||||
|
|
||||||
browsers: ['Chrome']
|
|
||||||
};
|
|
||||||
|
|
||||||
config.set(options);
|
|
||||||
};
|
|
|
@ -1,329 +0,0 @@
|
||||||
function CONST() {
|
|
||||||
return (function(target) {
|
|
||||||
return target;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function CONST_EXPR(expr) {
|
|
||||||
return expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPresent (x) {
|
|
||||||
return !!x;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isBlank (x) {
|
|
||||||
return !x;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isString(obj) {
|
|
||||||
return typeof obj === 'string';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isType (x) {
|
|
||||||
return typeof x === 'function';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isStringMap(obj) {
|
|
||||||
return typeof obj === 'object' && obj !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isArray(obj) {
|
|
||||||
return Array.isArray(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTypeNameForDebugging (fn) {
|
|
||||||
return fn.name || 'Root';
|
|
||||||
}
|
|
||||||
|
|
||||||
var PromiseWrapper = {
|
|
||||||
resolve: function (reason) {
|
|
||||||
return $q.when(reason);
|
|
||||||
},
|
|
||||||
|
|
||||||
reject: function (reason) {
|
|
||||||
return $q.reject(reason);
|
|
||||||
},
|
|
||||||
|
|
||||||
catchError: function (promise, fn) {
|
|
||||||
return promise.then(null, fn);
|
|
||||||
},
|
|
||||||
all: function (promises) {
|
|
||||||
return $q.all(promises);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var RegExpWrapper = {
|
|
||||||
create: function(regExpStr, flags) {
|
|
||||||
flags = flags ? flags.replace(/g/g, '') : '';
|
|
||||||
return new RegExp(regExpStr, flags + 'g');
|
|
||||||
},
|
|
||||||
firstMatch: function(regExp, input) {
|
|
||||||
regExp.lastIndex = 0;
|
|
||||||
return regExp.exec(input);
|
|
||||||
},
|
|
||||||
matcher: function (regExp, input) {
|
|
||||||
regExp.lastIndex = 0;
|
|
||||||
return { re: regExp, input: input };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var reflector = {
|
|
||||||
annotations: function (fn) {
|
|
||||||
//TODO: implement me
|
|
||||||
return fn.annotations || [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var MapWrapper = {
|
|
||||||
create: function() {
|
|
||||||
return new Map();
|
|
||||||
},
|
|
||||||
|
|
||||||
get: function(m, k) {
|
|
||||||
return m.get(k);
|
|
||||||
},
|
|
||||||
|
|
||||||
set: function(m, k, v) {
|
|
||||||
return m.set(k, v);
|
|
||||||
},
|
|
||||||
|
|
||||||
contains: function (m, k) {
|
|
||||||
return m.has(k);
|
|
||||||
},
|
|
||||||
|
|
||||||
forEach: function (m, fn) {
|
|
||||||
return m.forEach(fn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var StringMapWrapper = {
|
|
||||||
create: function () {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
|
|
||||||
set: function (m, k, v) {
|
|
||||||
return m[k] = v;
|
|
||||||
},
|
|
||||||
|
|
||||||
get: function (m, k) {
|
|
||||||
return m.hasOwnProperty(k) ? m[k] : undefined;
|
|
||||||
},
|
|
||||||
|
|
||||||
contains: function (m, k) {
|
|
||||||
return m.hasOwnProperty(k);
|
|
||||||
},
|
|
||||||
|
|
||||||
keys: function(map) {
|
|
||||||
return Object.keys(map);
|
|
||||||
},
|
|
||||||
|
|
||||||
isEmpty: function(map) {
|
|
||||||
for (var prop in map) {
|
|
||||||
if (map.hasOwnProperty(prop)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
delete: function(map, key) {
|
|
||||||
delete map[key];
|
|
||||||
},
|
|
||||||
|
|
||||||
forEach: function (m, fn) {
|
|
||||||
for (var prop in m) {
|
|
||||||
if (m.hasOwnProperty(prop)) {
|
|
||||||
fn(m[prop], prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
equals: function (m1, m2) {
|
|
||||||
var k1 = Object.keys(m1);
|
|
||||||
var k2 = Object.keys(m2);
|
|
||||||
if (k1.length != k2.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var key;
|
|
||||||
for (var i = 0; i < k1.length; i++) {
|
|
||||||
key = k1[i];
|
|
||||||
if (m1[key] !== m2[key]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
merge: function(m1, m2) {
|
|
||||||
var m = {};
|
|
||||||
for (var attr in m1) {
|
|
||||||
if (m1.hasOwnProperty(attr)) {
|
|
||||||
m[attr] = m1[attr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var attr in m2) {
|
|
||||||
if (m2.hasOwnProperty(attr)) {
|
|
||||||
m[attr] = m2[attr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var List = Array;
|
|
||||||
var ListWrapper = {
|
|
||||||
toJSON: function(l) {
|
|
||||||
return JSON.stringify(l);
|
|
||||||
},
|
|
||||||
|
|
||||||
clear: function (l) {
|
|
||||||
l.length = 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
create: function () {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
|
|
||||||
push: function (l, v) {
|
|
||||||
return l.push(v);
|
|
||||||
},
|
|
||||||
|
|
||||||
forEach: function (l, fn) {
|
|
||||||
return l.forEach(fn);
|
|
||||||
},
|
|
||||||
|
|
||||||
first: function(array) {
|
|
||||||
if (!array)
|
|
||||||
return null;
|
|
||||||
return array[0];
|
|
||||||
},
|
|
||||||
|
|
||||||
last: function(array) {
|
|
||||||
return (array && array.length) > 0 ? array[array.length - 1] : null;
|
|
||||||
},
|
|
||||||
|
|
||||||
map: function (l, fn) {
|
|
||||||
return l.map(fn);
|
|
||||||
},
|
|
||||||
|
|
||||||
join: function (l, str) {
|
|
||||||
return l.join(str);
|
|
||||||
},
|
|
||||||
|
|
||||||
reduce: function(list, fn, init) {
|
|
||||||
return list.reduce(fn, init);
|
|
||||||
},
|
|
||||||
|
|
||||||
filter: function(array, pred) {
|
|
||||||
return array.filter(pred);
|
|
||||||
},
|
|
||||||
|
|
||||||
concat: function(a, b) {
|
|
||||||
return a.concat(b);
|
|
||||||
},
|
|
||||||
|
|
||||||
slice: function(l) {
|
|
||||||
var from = arguments[1] !== (void 0) ? arguments[1] : 0;
|
|
||||||
var to = arguments[2] !== (void 0) ? arguments[2] : null;
|
|
||||||
return l.slice(from, to === null ? undefined : to);
|
|
||||||
},
|
|
||||||
|
|
||||||
maximum: function(list, predicate) {
|
|
||||||
if (list.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var solution = null;
|
|
||||||
var maxValue = -Infinity;
|
|
||||||
for (var index = 0; index < list.length; index++) {
|
|
||||||
var candidate = list[index];
|
|
||||||
if (isBlank(candidate)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var candidateValue = predicate(candidate);
|
|
||||||
if (candidateValue > maxValue) {
|
|
||||||
solution = candidate;
|
|
||||||
maxValue = candidateValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return solution;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var StringWrapper = {
|
|
||||||
charCodeAt: function(s, i) {
|
|
||||||
return s.charCodeAt(i);
|
|
||||||
},
|
|
||||||
|
|
||||||
equals: function (s1, s2) {
|
|
||||||
return s1 === s2;
|
|
||||||
},
|
|
||||||
|
|
||||||
split: function(s, re) {
|
|
||||||
return s.split(re);
|
|
||||||
},
|
|
||||||
|
|
||||||
replaceAll: function(s, from, replace) {
|
|
||||||
return s.replace(from, replace);
|
|
||||||
},
|
|
||||||
|
|
||||||
replaceAllMapped: function(s, from, cb) {
|
|
||||||
return s.replace(from, function(matches) {
|
|
||||||
// The callback receives match, p1, ..., pn
|
|
||||||
return cb.apply(null, matches);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
contains: function(s, substr) {
|
|
||||||
return s.indexOf(substr) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: implement?
|
|
||||||
// I think it's too heavy to ask 1.x users to bring in Rx for the router...
|
|
||||||
function EventEmitter() {}
|
|
||||||
|
|
||||||
var ObservableWrapper = {
|
|
||||||
callNext: function(ob, val) {
|
|
||||||
ob.fn(val);
|
|
||||||
},
|
|
||||||
callEmit: function(ob, val) {
|
|
||||||
ob.fn(val);
|
|
||||||
},
|
|
||||||
|
|
||||||
subscribe: function(ob, fn) {
|
|
||||||
ob.fn = fn;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: https://github.com/angular/angular.js/blob/master/src/ng/browser.js#L227-L265
|
|
||||||
var $__router_47_location__ = {
|
|
||||||
Location: Location
|
|
||||||
};
|
|
||||||
|
|
||||||
function Location(){}
|
|
||||||
Location.prototype.subscribe = function () {
|
|
||||||
//TODO: implement
|
|
||||||
};
|
|
||||||
Location.prototype.path = function () {
|
|
||||||
return $location.url();
|
|
||||||
};
|
|
||||||
Location.prototype.isCurrentPathEqualTo = function (path, query) {
|
|
||||||
if (query === void 0) { query = ''; }
|
|
||||||
return this.path() === (path + query);
|
|
||||||
};
|
|
||||||
Location.prototype.go = function (path, query) {
|
|
||||||
return $location.url(path + query);
|
|
||||||
};
|
|
||||||
Location.prototype.replaceState = function (path, query) {
|
|
||||||
if (query === void 0) { query = ''; }
|
|
||||||
$location.url(path + query);
|
|
||||||
$location.replace();
|
|
||||||
};
|
|
||||||
Location.prototype.prepareExternalUrl = function(url) {
|
|
||||||
if (url.length > 0 && !url.startsWith('/')) {
|
|
||||||
url = '/' + url;
|
|
||||||
}
|
|
||||||
return $location.$$html5 ? '.' + url : '#' + $locationHashPrefix + url;
|
|
||||||
};
|
|
|
@ -1,130 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
angular.module('ngComponentRouter').
|
|
||||||
value('$route', null). // can be overloaded with ngRouteShim
|
|
||||||
// Because AngularJS 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}}
|
|
||||||
|
|
||||||
var exports = {
|
|
||||||
Injectable: function () {},
|
|
||||||
InjectionToken: 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 Error('too many directives named "' + name + '"');
|
|
||||||
}
|
|
||||||
return definitions[0].controller;
|
|
||||||
} else {
|
|
||||||
throw new Error('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 () {};
|
|
||||||
|
|
||||||
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 (typeof component === 'string') {
|
|
||||||
// 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;
|
|
||||||
}
|
|
|
@ -1,275 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
///<reference path="../typings/angularjs/angular.d.ts"/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name ngOutlet
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* An ngOutlet is where resolved content goes.
|
|
||||||
*
|
|
||||||
* ## Use
|
|
||||||
*
|
|
||||||
* ```html
|
|
||||||
* <div ng-outlet="name"></div>
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* The value for the `ngOutlet` attribute is optional.
|
|
||||||
*/
|
|
||||||
function ngOutletDirective($animate, $q: ng.IQService, $rootRouter) {
|
|
||||||
const rootRouter = $rootRouter;
|
|
||||||
|
|
||||||
return {
|
|
||||||
restrict: 'AE',
|
|
||||||
transclude: 'element',
|
|
||||||
terminal: true,
|
|
||||||
priority: 400,
|
|
||||||
require: ['?^^ngOutlet', 'ngOutlet'],
|
|
||||||
link: outletLink,
|
|
||||||
controller: class {},
|
|
||||||
controllerAs: '$$ngOutlet'
|
|
||||||
};
|
|
||||||
|
|
||||||
function outletLink(scope, element, attrs, ctrls, $transclude) {
|
|
||||||
class Outlet {
|
|
||||||
constructor(private controller, private router) {}
|
|
||||||
|
|
||||||
private currentController;
|
|
||||||
private currentInstruction;
|
|
||||||
private currentScope;
|
|
||||||
private currentElement;
|
|
||||||
private previousLeaveAnimation;
|
|
||||||
|
|
||||||
private cleanupLastView() {
|
|
||||||
if (this.previousLeaveAnimation) {
|
|
||||||
$animate.cancel(this.previousLeaveAnimation);
|
|
||||||
this.previousLeaveAnimation = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.currentScope) {
|
|
||||||
this.currentScope.$destroy();
|
|
||||||
this.currentScope = null;
|
|
||||||
}
|
|
||||||
if (this.currentElement) {
|
|
||||||
this.previousLeaveAnimation = $animate.leave(this.currentElement);
|
|
||||||
this.previousLeaveAnimation.then(() => this.previousLeaveAnimation = null);
|
|
||||||
this.currentElement = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reuse(instruction) {
|
|
||||||
let next = $q.when(true);
|
|
||||||
const previousInstruction = this.currentInstruction;
|
|
||||||
this.currentInstruction = instruction;
|
|
||||||
if (this.currentController && this.currentController.$routerOnReuse) {
|
|
||||||
next = $q.when(
|
|
||||||
this.currentController.$routerOnReuse(this.currentInstruction, previousInstruction));
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
routerCanReuse(nextInstruction) {
|
|
||||||
let result;
|
|
||||||
if (!this.currentInstruction ||
|
|
||||||
this.currentInstruction.componentType !== nextInstruction.componentType) {
|
|
||||||
result = false;
|
|
||||||
} else if (this.currentController && this.currentController.$routerCanReuse) {
|
|
||||||
result = this.currentController.$routerCanReuse(nextInstruction, this.currentInstruction);
|
|
||||||
} else {
|
|
||||||
result = nextInstruction === this.currentInstruction ||
|
|
||||||
angular.equals(nextInstruction.params, this.currentInstruction.params);
|
|
||||||
}
|
|
||||||
return $q.when(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
routerCanDeactivate(instruction) {
|
|
||||||
if (this.currentController && this.currentController.$routerCanDeactivate) {
|
|
||||||
return $q.when(
|
|
||||||
this.currentController.$routerCanDeactivate(instruction, this.currentInstruction));
|
|
||||||
}
|
|
||||||
return $q.when(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
deactivate(instruction) {
|
|
||||||
if (this.currentController && this.currentController.$routerOnDeactivate) {
|
|
||||||
return $q.when(
|
|
||||||
this.currentController.$routerOnDeactivate(instruction, this.currentInstruction));
|
|
||||||
}
|
|
||||||
return $q.when();
|
|
||||||
}
|
|
||||||
|
|
||||||
activate(instruction) {
|
|
||||||
this.previousInstruction = this.currentInstruction;
|
|
||||||
this.currentInstruction = instruction;
|
|
||||||
|
|
||||||
const componentName = this.controller.$$componentName = instruction.componentType;
|
|
||||||
|
|
||||||
if (typeof componentName !== 'string') {
|
|
||||||
throw new Error('Component is not a string for ' + instruction.urlPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.controller.$$template = '<' + dashCase(componentName) + ' $router="::$$router"></' +
|
|
||||||
dashCase(componentName) + '>';
|
|
||||||
this.controller.$$router = this.router.childRouter(instruction.componentType);
|
|
||||||
this.controller.$$outlet = this;
|
|
||||||
|
|
||||||
const newScope = scope.$new();
|
|
||||||
newScope.$$router = this.controller.$$router;
|
|
||||||
this.deferredActivation = $q.defer();
|
|
||||||
|
|
||||||
const clone = $transclude(newScope, clone => {});
|
|
||||||
|
|
||||||
const activateView = () => {
|
|
||||||
$animate.enter(clone, null, this.currentElement || element);
|
|
||||||
this.cleanupLastView();
|
|
||||||
this.currentElement = clone;
|
|
||||||
this.currentScope = newScope;
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.deferredActivation.promise.then(activateView, activateView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentCtrl = ctrls[0], myCtrl = ctrls[1],
|
|
||||||
router = (parentCtrl && parentCtrl.$$router) || rootRouter;
|
|
||||||
|
|
||||||
myCtrl.$$currentComponent = null;
|
|
||||||
|
|
||||||
router.registerPrimaryOutlet(new Outlet(myCtrl, router));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* This directive is responsible for compiling the contents of ng-outlet
|
|
||||||
*/
|
|
||||||
function ngOutletFillContentDirective($compile) {
|
|
||||||
return {
|
|
||||||
restrict: 'EA',
|
|
||||||
priority: -400,
|
|
||||||
require: 'ngOutlet',
|
|
||||||
link: (scope, element, attrs, ctrl) => {
|
|
||||||
const template = ctrl.$$template;
|
|
||||||
element.html(template);
|
|
||||||
$compile(element.contents())(scope);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function routerTriggerDirective($q) {
|
|
||||||
return {
|
|
||||||
require: '^ngOutlet',
|
|
||||||
priority: -1000,
|
|
||||||
link: function(scope, element, attr, ngOutletCtrl) {
|
|
||||||
let promise = $q.when();
|
|
||||||
const outlet = ngOutletCtrl.$$outlet;
|
|
||||||
const currentComponent = outlet.currentController =
|
|
||||||
element.controller(ngOutletCtrl.$$componentName);
|
|
||||||
if (currentComponent.$routerOnActivate) {
|
|
||||||
promise = $q.when(currentComponent.$routerOnActivate(outlet.currentInstruction,
|
|
||||||
outlet.previousInstruction));
|
|
||||||
}
|
|
||||||
promise.then(outlet.deferredActivation.resolve, outlet.deferredActivation.reject);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @name ngLink
|
|
||||||
* @description
|
|
||||||
* Lets you link to different parts of the app, and automatically generates hrefs.
|
|
||||||
*
|
|
||||||
* ## Use
|
|
||||||
* The directive uses a simple syntax: `ng-link="componentName({ param: paramValue })"`
|
|
||||||
*
|
|
||||||
* ### Example
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* angular.module('myApp', ['ngComponentRouter'])
|
|
||||||
* .controller('AppController', ['$rootRouter', function($rootRouter) {
|
|
||||||
* $rootRouter.config({ path: '/user/:id', component: 'user' });
|
|
||||||
* this.user = { name: 'Brian', id: 123 };
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* ```html
|
|
||||||
* <div ng-controller="AppController as app">
|
|
||||||
* <a ng-link="user({id: app.user.id})">{{app.user.name}}</a>
|
|
||||||
* </div>
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
function ngLinkDirective($rootRouter, $parse) {
|
|
||||||
return {require: '?^^ngOutlet', restrict: 'A', link: ngLinkDirectiveLinkFn};
|
|
||||||
|
|
||||||
function ngLinkDirectiveLinkFn(scope, element, attrs, ctrl) {
|
|
||||||
const router = (ctrl && ctrl.$$router) || $rootRouter;
|
|
||||||
if (!router) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let navigationInstruction = null;
|
|
||||||
const link = attrs.ngLink || '';
|
|
||||||
|
|
||||||
function getLink(params) {
|
|
||||||
if (!params) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
navigationInstruction = router.generate(params);
|
|
||||||
|
|
||||||
scope.$watch(function() { return router.isRouteActive(navigationInstruction); },
|
|
||||||
function(active) {
|
|
||||||
if (active) {
|
|
||||||
element.addClass('ng-link-active');
|
|
||||||
} else {
|
|
||||||
element.removeClass('ng-link-active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const navigationHref = navigationInstruction.toLinkUrl();
|
|
||||||
return $rootRouter._location.prepareExternalUrl(navigationHref);
|
|
||||||
}
|
|
||||||
|
|
||||||
const routeParamsGetter = $parse(link);
|
|
||||||
// we can avoid adding a watcher if it's a literal
|
|
||||||
if (routeParamsGetter.constant) {
|
|
||||||
const params = routeParamsGetter();
|
|
||||||
element.attr('href', getLink(params));
|
|
||||||
} else {
|
|
||||||
scope.$watch(() => routeParamsGetter(scope), params => element.attr('href', getLink(params)),
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
element.on('click', event => {
|
|
||||||
if (event.which !== 1 || !navigationInstruction) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rootRouter.navigateByInstruction(navigationInstruction);
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dashCase(str: string): string {
|
|
||||||
return str.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A module for adding new a routing system AngularJS.
|
|
||||||
*/
|
|
||||||
angular.module('ngComponentRouter', [])
|
|
||||||
.directive('ngOutlet', ['$animate', '$q', '$rootRouter', ngOutletDirective])
|
|
||||||
.directive('ngOutlet', ['$compile', ngOutletFillContentDirective])
|
|
||||||
.directive('ngLink', ['$rootRouter', '$parse', ngLinkDirective])
|
|
||||||
.directive('$router', ['$q', routerTriggerDirective]);
|
|
|
@ -1,347 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
// keep a reference to compileProvider so we can register new component-directives
|
|
||||||
// on-the-fly based on $routeProvider configuration
|
|
||||||
// TODO: remove this– right now you can only bootstrap one Angular app with this hack
|
|
||||||
var $compileProvider, $q, $injector;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module loads services that mimic ngRoute's configuration, and includes
|
|
||||||
* an anchor link directive that intercepts clicks to routing.
|
|
||||||
*
|
|
||||||
* This module is intended to be used as a stop-gap solution for projects upgrading from ngRoute.
|
|
||||||
* It intentionally does not implement all features of ngRoute.
|
|
||||||
*/
|
|
||||||
angular.module('ngRouteShim', [])
|
|
||||||
.provider('$route', $RouteProvider)
|
|
||||||
.config(['$compileProvider', function (compileProvider) {
|
|
||||||
$compileProvider = compileProvider;
|
|
||||||
}])
|
|
||||||
.factory('$routeParams', $routeParamsFactory)
|
|
||||||
.directive('a', anchorLinkDirective)
|
|
||||||
|
|
||||||
// Connects the legacy $routeProvider config shim to Component Router's config.
|
|
||||||
.run(['$route', '$rootRouter', function ($route, $rootRouter) {
|
|
||||||
$route.$$subscribe(function (routeDefinition) {
|
|
||||||
if (!angular.isArray(routeDefinition)) {
|
|
||||||
routeDefinition = [routeDefinition];
|
|
||||||
}
|
|
||||||
$rootRouter.config(routeDefinition);
|
|
||||||
});
|
|
||||||
}]);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A shimmed out provider that provides the same API as ngRoute's $routeProvider, but uses these calls
|
|
||||||
* to configure Component Router.
|
|
||||||
*/
|
|
||||||
function $RouteProvider() {
|
|
||||||
|
|
||||||
var routes = [];
|
|
||||||
var subscriptionFn = null;
|
|
||||||
|
|
||||||
var routeMap = {};
|
|
||||||
|
|
||||||
// Stats for which routes are skipped
|
|
||||||
var skipCount = 0;
|
|
||||||
var successCount = 0;
|
|
||||||
var allCount = 0;
|
|
||||||
|
|
||||||
function consoleMetrics() {
|
|
||||||
return '(' + skipCount + ' skipped / ' + successCount + ' success / ' + allCount + ' total)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $routeProvider#when
|
|
||||||
*
|
|
||||||
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
|
||||||
* contains redundant trailing slash or is missing one, the route will still match and the
|
|
||||||
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
|
||||||
* route definition.
|
|
||||||
*
|
|
||||||
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
|
||||||
* match.
|
|
||||||
*/
|
|
||||||
this.when = function(path, route) {
|
|
||||||
//copy original route object to preserve params inherited from proto chain
|
|
||||||
var routeCopy = angular.copy(route);
|
|
||||||
|
|
||||||
allCount++;
|
|
||||||
|
|
||||||
if (angular.isDefined(routeCopy.reloadOnSearch)) {
|
|
||||||
console.warn('Route for "' + path + '" uses "reloadOnSearch" which is not implemented.');
|
|
||||||
}
|
|
||||||
if (angular.isDefined(routeCopy.caseInsensitiveMatch)) {
|
|
||||||
console.warn('Route for "' + path + '" uses "caseInsensitiveMatch" which is not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// use new wildcard format
|
|
||||||
path = reformatWildcardParams(path);
|
|
||||||
|
|
||||||
if (path[path.length - 1] == '*') {
|
|
||||||
skipCount++;
|
|
||||||
console.warn('Route for "' + path + '" ignored because it ends with *. Skipping.', consoleMetrics());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path.indexOf('?') > -1) {
|
|
||||||
skipCount++;
|
|
||||||
console.warn('Route for "' + path + '" ignored because it has optional parameters. Skipping.', consoleMetrics());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof route.redirectTo == 'function') {
|
|
||||||
skipCount++;
|
|
||||||
console.warn('Route for "' + path + '" ignored because lazy redirecting to a function is not yet implemented. Skipping.', consoleMetrics());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var routeDefinition = {
|
|
||||||
path: path,
|
|
||||||
data: routeCopy
|
|
||||||
};
|
|
||||||
|
|
||||||
routeMap[path] = routeCopy;
|
|
||||||
|
|
||||||
if (route.redirectTo) {
|
|
||||||
routeDefinition.redirectTo = [routeMap[route.redirectTo].name];
|
|
||||||
} else {
|
|
||||||
if (routeCopy.controller && !routeCopy.controllerAs) {
|
|
||||||
console.warn('Route for "' + path + '" should use "controllerAs".');
|
|
||||||
}
|
|
||||||
|
|
||||||
var componentName = routeObjToRouteName(routeCopy, path);
|
|
||||||
|
|
||||||
if (!componentName) {
|
|
||||||
throw new Error('Could not determine a name for route "' + path + '".');
|
|
||||||
}
|
|
||||||
|
|
||||||
routeDefinition.component = componentName;
|
|
||||||
routeDefinition.name = route.name || upperCase(componentName);
|
|
||||||
|
|
||||||
var directiveController = routeCopy.controller;
|
|
||||||
|
|
||||||
var componentDefinition = {
|
|
||||||
controller: directiveController,
|
|
||||||
controllerAs: routeCopy.controllerAs
|
|
||||||
|
|
||||||
};
|
|
||||||
if (routeCopy.templateUrl) componentDefinition.templateUrl = routeCopy.templateUrl;
|
|
||||||
if (routeCopy.template) componentDefinition.template = routeCopy.template;
|
|
||||||
|
|
||||||
|
|
||||||
// if we have route resolve options, prepare a wrapper controller
|
|
||||||
if (directiveController && routeCopy.resolve) {
|
|
||||||
var originalController = directiveController;
|
|
||||||
var resolvedLocals = {};
|
|
||||||
|
|
||||||
componentDefinition.controller = ['$injector', '$scope', function ($injector, $scope) {
|
|
||||||
var locals = angular.extend({
|
|
||||||
$scope: $scope
|
|
||||||
}, resolvedLocals);
|
|
||||||
|
|
||||||
return $injector.instantiate(originalController, locals);
|
|
||||||
}];
|
|
||||||
|
|
||||||
// we resolve the locals in a canActivate block
|
|
||||||
componentDefinition.controller.$canActivate = function() {
|
|
||||||
var locals = angular.extend({}, routeCopy.resolve);
|
|
||||||
|
|
||||||
angular.forEach(locals, function(value, key) {
|
|
||||||
locals[key] = angular.isString(value) ?
|
|
||||||
$injector.get(value) : $injector.invoke(value, null, null, key);
|
|
||||||
});
|
|
||||||
|
|
||||||
return $q.all(locals).then(function (locals) {
|
|
||||||
resolvedLocals = locals;
|
|
||||||
}).then(function () {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// register the dynamically created directive
|
|
||||||
$compileProvider.component(componentName, componentDefinition);
|
|
||||||
}
|
|
||||||
if (subscriptionFn) {
|
|
||||||
subscriptionFn(routeDefinition);
|
|
||||||
} else {
|
|
||||||
routes.push(routeDefinition);
|
|
||||||
}
|
|
||||||
successCount++;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.otherwise = function(params) {
|
|
||||||
if (typeof params === 'string') {
|
|
||||||
params = {redirectTo: params};
|
|
||||||
}
|
|
||||||
this.when('/*rest', params);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
this.$get = ['$q', '$injector', function (q, injector) {
|
|
||||||
$q = q;
|
|
||||||
$injector = injector;
|
|
||||||
|
|
||||||
var $route = {
|
|
||||||
routes: routeMap,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $route#reload
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Causes `$route` service to reload the current route even if
|
|
||||||
* {@link ng.$location $location} hasn't changed.
|
|
||||||
*/
|
|
||||||
reload: function() {
|
|
||||||
throw new Error('Not implemented: $route.reload');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name $route#updateParams
|
|
||||||
*/
|
|
||||||
updateParams: function(newParams) {
|
|
||||||
throw new Error('Not implemented: $route.updateParams');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the given `fn` whenever new configs are added.
|
|
||||||
* Only one subscription is allowed.
|
|
||||||
* Passed `fn` is called synchronously.
|
|
||||||
*/
|
|
||||||
$$subscribe: function(fn) {
|
|
||||||
if (subscriptionFn) {
|
|
||||||
throw new Error('only one subscription allowed');
|
|
||||||
}
|
|
||||||
subscriptionFn = fn;
|
|
||||||
subscriptionFn(routes);
|
|
||||||
routes = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs a string with stats about many route configs were adapted, and how many were
|
|
||||||
* dropped because they are incompatible.
|
|
||||||
*/
|
|
||||||
$$getStats: consoleMetrics
|
|
||||||
};
|
|
||||||
|
|
||||||
return $route;
|
|
||||||
}];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function $routeParamsFactory($rootRouter, $rootScope) {
|
|
||||||
// the identity of this object cannot change
|
|
||||||
var paramsObj = {};
|
|
||||||
|
|
||||||
$rootScope.$on('$routeChangeSuccess', function () {
|
|
||||||
var newParams = $rootRouter.currentInstruction && $rootRouter.currentInstruction.component.params;
|
|
||||||
|
|
||||||
angular.forEach(paramsObj, function (val, name) {
|
|
||||||
delete paramsObj[name];
|
|
||||||
});
|
|
||||||
angular.forEach(newParams, function (val, name) {
|
|
||||||
paramsObj[name] = val;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return paramsObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows normal anchor links to kick off routing.
|
|
||||||
*/
|
|
||||||
function anchorLinkDirective($rootRouter) {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
link: function (scope, element) {
|
|
||||||
// If the linked element is not an anchor tag anymore, do nothing
|
|
||||||
if (element[0].nodeName.toLowerCase() !== 'a') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
|
||||||
var hrefAttrName = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
|
||||||
'xlink:href' : 'href';
|
|
||||||
|
|
||||||
element.on('click', function (event) {
|
|
||||||
if (event.which !== 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var href = element.attr(hrefAttrName);
|
|
||||||
var target = element.attr('target');
|
|
||||||
var isExternal = (['_blank', '_parent', '_self', '_top'].indexOf(target) > -1);
|
|
||||||
|
|
||||||
if (href && $rootRouter.recognize(href) && !isExternal) {
|
|
||||||
$rootRouter.navigateByUrl(href);
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a route object, attempts to find a unique directive name.
|
|
||||||
*
|
|
||||||
* @param route – route config object passed to $routeProvider.when
|
|
||||||
* @param path – route configuration path
|
|
||||||
* @returns {string|name} – a normalized (camelCase) directive name
|
|
||||||
*/
|
|
||||||
function routeObjToRouteName(route, path) {
|
|
||||||
var name = route.controllerAs;
|
|
||||||
|
|
||||||
var controller = route.controller;
|
|
||||||
if (!name && controller) {
|
|
||||||
if (angular.isArray(controller)) {
|
|
||||||
controller = controller[controller.length - 1];
|
|
||||||
}
|
|
||||||
name = controller.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
var segments = path.split('/');
|
|
||||||
name = segments[segments.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
name = name + 'AutoCmp';
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
function upperCase(str) {
|
|
||||||
return str.charAt(0).toUpperCase() + str.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Changes "/:foo*" to "/*foo"
|
|
||||||
*/
|
|
||||||
var WILDCARD_PARAM_RE = new RegExp('\\/:([a-z0-9]+)\\*', 'gi');
|
|
||||||
function reformatWildcardParams(path) {
|
|
||||||
return path.replace(WILDCARD_PARAM_RE, function (m, m1) {
|
|
||||||
return '/*' + m1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}());
|
|
|
@ -1,113 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('ngOutlet animations', function () {
|
|
||||||
var elt,
|
|
||||||
$animate,
|
|
||||||
$compile,
|
|
||||||
$rootScope,
|
|
||||||
$rootRouter,
|
|
||||||
$compileProvider;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
module('ng');
|
|
||||||
module('ngAnimate');
|
|
||||||
module('ngAnimateMock');
|
|
||||||
module('ngComponentRouter');
|
|
||||||
module(function (_$compileProvider_) {
|
|
||||||
$compileProvider = _$compileProvider_;
|
|
||||||
});
|
|
||||||
|
|
||||||
inject(function (_$animate_, _$compile_, _$rootScope_, _$rootRouter_) {
|
|
||||||
$animate = _$animate_;
|
|
||||||
$compile = _$compile_;
|
|
||||||
$rootScope = _$rootScope_;
|
|
||||||
$rootRouter = _$rootRouter_;
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('userCmp', {
|
|
||||||
template: '<div>hello {{userCmp.$routeParams.name}}</div>',
|
|
||||||
$routerOnActivate: function(next) {
|
|
||||||
this.$routeParams = next.params;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
expect($animate.queue).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work in a simple case', function () {
|
|
||||||
var item;
|
|
||||||
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'userCmp' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hello brian');
|
|
||||||
|
|
||||||
// "user" component enters
|
|
||||||
item = $animate.queue.shift();
|
|
||||||
expect(item.event).toBe('enter');
|
|
||||||
|
|
||||||
// navigate to pete
|
|
||||||
$rootRouter.navigateByUrl('/user/pete');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hello pete');
|
|
||||||
|
|
||||||
// "user pete" component enters
|
|
||||||
item = $animate.queue.shift();
|
|
||||||
expect(item.event).toBe('enter');
|
|
||||||
expect(item.element.text()).toBe('hello pete');
|
|
||||||
|
|
||||||
// "user brian" component leaves
|
|
||||||
item = $animate.queue.shift();
|
|
||||||
expect(item.event).toBe('leave');
|
|
||||||
expect(item.element.text()).toBe('hello brian');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function registerComponent(name, options) {
|
|
||||||
var controller = options.controller || function () {};
|
|
||||||
|
|
||||||
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
|
|
||||||
if (options[hookName]) {
|
|
||||||
controller.prototype[hookName] = options[hookName];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function factory() {
|
|
||||||
return {
|
|
||||||
template: options.template || '',
|
|
||||||
controllerAs: name,
|
|
||||||
controller: controller
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.$canActivate) {
|
|
||||||
factory.$canActivate = options.$canActivate;
|
|
||||||
}
|
|
||||||
if (options.$routeConfig) {
|
|
||||||
factory.$routeConfig = options.$routeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
$compileProvider.directive(name, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(template) {
|
|
||||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,537 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('Navigation lifecycle', function () {
|
|
||||||
var elt,
|
|
||||||
$compile,
|
|
||||||
$q,
|
|
||||||
$rootScope,
|
|
||||||
$rootRouter,
|
|
||||||
$compileProvider;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
module('ng');
|
|
||||||
module('ngComponentRouter');
|
|
||||||
module(function (_$compileProvider_) {
|
|
||||||
$compileProvider = _$compileProvider_;
|
|
||||||
});
|
|
||||||
|
|
||||||
inject(function (_$compile_, _$q_, _$rootScope_, _$rootRouter_) {
|
|
||||||
$compile = _$compile_;
|
|
||||||
$q = _$q_;
|
|
||||||
$rootScope = _$rootScope_;
|
|
||||||
$rootRouter = _$rootRouter_;
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('oneCmp', {
|
|
||||||
template: '<div>{{oneCmp.number}}</div>',
|
|
||||||
controller: function () {this.number = 'one';}
|
|
||||||
});
|
|
||||||
registerComponent('twoCmp', {
|
|
||||||
template: '<div><a ng-link="[\'/Two\']">{{twoCmp.number}}</a></div>',
|
|
||||||
controller: function () {this.number = 'two';}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should run the activate hook of controllers', function () {
|
|
||||||
var spy = jasmine.createSpy('activate');
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
template: '<p>hello</p>',
|
|
||||||
$routerOnActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should pass instruction into the activate hook of a controller', function () {
|
|
||||||
var spy = jasmine.createSpy('activate');
|
|
||||||
registerComponent('userCmp', {
|
|
||||||
$routerOnActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'userCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalledWith(instructionFor('userCmp'), undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should pass previous instruction into the activate hook of a controller', function () {
|
|
||||||
var spy = jasmine.createSpy('activate');
|
|
||||||
var activate = registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$routerOnActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'oneCmp' },
|
|
||||||
{ path: '/post/:id', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$rootRouter.navigateByUrl('/post/123');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(spy).toHaveBeenCalledWith(instructionFor('activateCmp'),
|
|
||||||
instructionFor('oneCmp'));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('activate hook with promise', () => {
|
|
||||||
var activateDeferred;
|
|
||||||
beforeEach(() => {
|
|
||||||
activateDeferred = $q.defer();
|
|
||||||
var activate = registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$routerOnActivate: function() {
|
|
||||||
return activateDeferred.promise;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'oneCmp' },
|
|
||||||
{ path: '/post', component: 'activateCmp' },
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/fabian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$rootRouter.navigateByUrl('/post');
|
|
||||||
$rootScope.$digest();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the view once the promise gets resolved', () => {
|
|
||||||
expect(elt.text()).toBe('one');
|
|
||||||
|
|
||||||
activateDeferred.resolve();
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hi');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the view once the promise gets rejected', () => {
|
|
||||||
expect(elt.text()).toBe('one');
|
|
||||||
|
|
||||||
activateDeferred.reject();
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hi');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inject $scope into the controller constructor', function () {
|
|
||||||
var injectedScope;
|
|
||||||
registerComponent('userCmp', {
|
|
||||||
template: '',
|
|
||||||
controller: function ($scope) {
|
|
||||||
injectedScope = $scope;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user', component: 'userCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(injectedScope).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should run the deactivate hook of controllers', function () {
|
|
||||||
var spy = jasmine.createSpy('deactivate');
|
|
||||||
registerComponent('deactivateCmp', {
|
|
||||||
$routerOnDeactivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'deactivateCmp' },
|
|
||||||
{ path: '/b', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$rootRouter.navigateByUrl('/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(spy).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should pass instructions into the deactivate hook of controllers', function () {
|
|
||||||
var spy = jasmine.createSpy('deactivate');
|
|
||||||
registerComponent('deactivateCmp', {
|
|
||||||
$routerOnDeactivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'deactivateCmp' },
|
|
||||||
{ path: '/post/:id', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$rootRouter.navigateByUrl('/post/123');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(spy).toHaveBeenCalledWith(instructionFor('oneCmp'),
|
|
||||||
instructionFor('deactivateCmp'));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should run the deactivate hook before the activate hook', function () {
|
|
||||||
var log = [];
|
|
||||||
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
$routerOnActivate: function () {
|
|
||||||
log.push('activate');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('deactivateCmp', {
|
|
||||||
$routerOnDeactivate: function () {
|
|
||||||
log.push('deactivate');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'deactivateCmp' },
|
|
||||||
{ path: '/b', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('outer { <div ng-outlet></div> }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$rootRouter.navigateByUrl('/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(log).toEqual(['deactivate', 'activate']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reuse a component when the routerCanReuse hook returns true', function () {
|
|
||||||
var log = [];
|
|
||||||
var cmpInstanceCount = 0;
|
|
||||||
|
|
||||||
function ReuseCmp() {
|
|
||||||
cmpInstanceCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerComponent('reuseCmp', {
|
|
||||||
template: 'reuse {<ng-outlet></ng-outlet>}',
|
|
||||||
$routeConfig: [
|
|
||||||
{path: '/a', component: 'oneCmp'},
|
|
||||||
{path: '/b', component: 'twoCmp'}
|
|
||||||
],
|
|
||||||
controller: ReuseCmp,
|
|
||||||
$routerCanReuse: function () {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
$routerOnReuse: function (next, prev) {
|
|
||||||
log.push('reuse: ' + prev.urlPath + ' -> ' + next.urlPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/on-reuse/:number/...', component: 'reuseCmp' },
|
|
||||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
|
||||||
]);
|
|
||||||
compile('outer { <div ng-outlet></div> }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/on-reuse/1/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(log).toEqual([]);
|
|
||||||
expect(cmpInstanceCount).toBe(1);
|
|
||||||
expect(elt.text()).toBe('outer { reuse {one} }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/on-reuse/2/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(log).toEqual(['reuse: on-reuse/1 -> on-reuse/2']);
|
|
||||||
expect(cmpInstanceCount).toBe(1);
|
|
||||||
expect(elt.text()).toBe('outer { reuse {two} }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should not reuse a component when the routerCanReuse hook returns false', function () {
|
|
||||||
var log = [];
|
|
||||||
var cmpInstanceCount = 0;
|
|
||||||
|
|
||||||
function NeverReuseCmp() {
|
|
||||||
cmpInstanceCount++;
|
|
||||||
}
|
|
||||||
registerComponent('reuseCmp', {
|
|
||||||
template: 'reuse {<ng-outlet></ng-outlet>}',
|
|
||||||
$routeConfig: [
|
|
||||||
{path: '/a', component: 'oneCmp'},
|
|
||||||
{path: '/b', component: 'twoCmp'}
|
|
||||||
],
|
|
||||||
controller: NeverReuseCmp,
|
|
||||||
$routerCanReuse: function () {
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
$routerOnReuse: function (next, prev) {
|
|
||||||
log.push('reuse: ' + prev.urlPath + ' -> ' + next.urlPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/never-reuse/:number/...', component: 'reuseCmp' },
|
|
||||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
|
||||||
]);
|
|
||||||
compile('outer { <div ng-outlet></div> }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/never-reuse/1/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(log).toEqual([]);
|
|
||||||
expect(cmpInstanceCount).toBe(1);
|
|
||||||
expect(elt.text()).toBe('outer { reuse {one} }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/never-reuse/2/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(log).toEqual([]);
|
|
||||||
expect(cmpInstanceCount).toBe(2);
|
|
||||||
expect(elt.text()).toBe('outer { reuse {two} }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: need to solve getting ahold of canActivate hook
|
|
||||||
it('should not activate a component when canActivate returns false', function () {
|
|
||||||
var canActivateSpy = jasmine.createSpy('canActivate').and.returnValue(false);
|
|
||||||
var spy = jasmine.createSpy('activate');
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
$canActivate: canActivateSpy,
|
|
||||||
$routerOnActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('outer { <div ng-outlet></div> }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(spy).not.toHaveBeenCalled();
|
|
||||||
expect(elt.text()).toBe('outer { }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should activate a component when canActivate returns true', function () {
|
|
||||||
var activateSpy = jasmine.createSpy('activate');
|
|
||||||
var canActivateSpy = jasmine.createSpy('canActivate').and.returnValue(true);
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$canActivate: canActivateSpy,
|
|
||||||
$routerOnActivate: activateSpy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(canActivateSpy).toHaveBeenCalled();
|
|
||||||
expect(activateSpy).toHaveBeenCalled();
|
|
||||||
expect(elt.text()).toBe('hi');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should activate a component when canActivate returns a resolved promise', inject(function ($q) {
|
|
||||||
var spy = jasmine.createSpy('activate');
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$canActivate: function () {
|
|
||||||
return $q.when(true);
|
|
||||||
},
|
|
||||||
$routerOnActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
|
||||||
expect(elt.text()).toBe('hi');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should inject into the canActivate hook of controllers', inject(function ($http) {
|
|
||||||
var spy = jasmine.createSpy('canActivate').and.returnValue(true);
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
$canActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
spy.$inject = ['$nextInstruction', '$http'];
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
|
||||||
var args = spy.calls.mostRecent().args;
|
|
||||||
expect(args[0].params).toEqual(jasmine.objectContaining({name: 'brian'}));
|
|
||||||
expect(args[1]).toBe($http);
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should not navigate when routerCanDeactivate returns false', function () {
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$routerCanDeactivate: function () {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' },
|
|
||||||
{ path: '/b', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
compile('outer { <div ng-outlet></div> }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('outer { hi }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('outer { hi }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should navigate when routerCanDeactivate returns true', function () {
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$routerCanDeactivate: function () {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' },
|
|
||||||
{ path: '/b', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
compile('outer { <div ng-outlet></div> }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('outer { hi }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('outer { one }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should activate a component when canActivate returns true', function () {
|
|
||||||
var spy = jasmine.createSpy('activate');
|
|
||||||
registerComponent('activateCmp', {
|
|
||||||
template: 'hi',
|
|
||||||
$canActivate: function () {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
$routerOnActivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a', component: 'activateCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(spy).toHaveBeenCalled();
|
|
||||||
expect(elt.text()).toBe('hi');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should pass instructions into the routerCanDeactivate hook of controllers', function () {
|
|
||||||
var spy = jasmine.createSpy('routerCanDeactivate').and.returnValue(true);
|
|
||||||
registerComponent('deactivateCmp', {
|
|
||||||
$routerCanDeactivate: spy
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'deactivateCmp' },
|
|
||||||
{ path: '/post/:id', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$rootRouter.navigateByUrl('/post/123');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(spy).toHaveBeenCalledWith(instructionFor('oneCmp'),
|
|
||||||
instructionFor('deactivateCmp'));
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function registerComponent(name, options) {
|
|
||||||
var controller = options.controller || function () {};
|
|
||||||
|
|
||||||
['$routerOnActivate', '$routerOnDeactivate', '$routerOnReuse', '$routerCanReuse', '$routerCanDeactivate'].forEach(function (hookName) {
|
|
||||||
if (options[hookName]) {
|
|
||||||
controller.prototype[hookName] = options[hookName];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function factory() {
|
|
||||||
return {
|
|
||||||
template: options.template || '',
|
|
||||||
controllerAs: name,
|
|
||||||
controller: controller
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.$canActivate) {
|
|
||||||
controller.$canActivate = options.$canActivate;
|
|
||||||
}
|
|
||||||
if (options.$routeConfig) {
|
|
||||||
controller.$routeConfig = options.$routeConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
$compileProvider.directive(name, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(template) {
|
|
||||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
|
|
||||||
function instructionFor(componentType) {
|
|
||||||
return jasmine.objectContaining({componentType: componentType});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,367 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('navigation', function () {
|
|
||||||
|
|
||||||
var elt,
|
|
||||||
$compile,
|
|
||||||
$rootScope,
|
|
||||||
$rootRouter,
|
|
||||||
$compileProvider;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
module('ng');
|
|
||||||
module('ngComponentRouter');
|
|
||||||
module(function (_$compileProvider_) {
|
|
||||||
$compileProvider = _$compileProvider_;
|
|
||||||
});
|
|
||||||
|
|
||||||
inject(function (_$compile_, _$rootScope_, _$rootRouter_) {
|
|
||||||
$compile = _$compile_;
|
|
||||||
$rootScope = _$rootScope_;
|
|
||||||
$rootRouter = _$rootRouter_;
|
|
||||||
});
|
|
||||||
|
|
||||||
registerDirective('userCmp', {
|
|
||||||
template: '<div>hello {{userCmp.$routeParams.name}}</div>',
|
|
||||||
$routerOnActivate: function(next) {
|
|
||||||
this.$routeParams = next.params;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
registerDirective('oneCmp', {
|
|
||||||
template: '<div>{{oneCmp.number}}</div>',
|
|
||||||
controller: function () {this.number = 'one';}
|
|
||||||
});
|
|
||||||
registerDirective('twoCmp', {
|
|
||||||
template: '<div>{{twoCmp.number}}</div>',
|
|
||||||
controller: function () {this.number = 'two';}
|
|
||||||
});
|
|
||||||
registerComponent('threeCmp', {
|
|
||||||
template: '<div>{{$ctrl.number}}</div>',
|
|
||||||
controller: function () {this.number = 'three';}
|
|
||||||
});
|
|
||||||
registerComponent('getParams', {
|
|
||||||
template: '<div>{{$ctrl.params.x}}</div>',
|
|
||||||
controller: function () {
|
|
||||||
this.$routerOnActivate = function(next) {
|
|
||||||
this.params = next.params;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work in a simple case', function () {
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('one');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should work with components created by the `mod.component()` helper', function () {
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/', component: 'threeCmp' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('three');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should navigate between components with different parameters', function () {
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user/:name', component: 'userCmp' }
|
|
||||||
]);
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hello brian');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/igor');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hello igor');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should reuse a parent when navigating between child components with different parameters', function () {
|
|
||||||
var instanceCount = 0;
|
|
||||||
function ParentController() {
|
|
||||||
instanceCount += 1;
|
|
||||||
}
|
|
||||||
registerDirective('parentCmp', {
|
|
||||||
template: 'parent { <ng-outlet></ng-outlet> }',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/user/:name', component: 'userCmp' }
|
|
||||||
],
|
|
||||||
controller: ParentController
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/parent/...', component: 'parentCmp' }
|
|
||||||
]);
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/parent/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(instanceCount).toBe(1);
|
|
||||||
expect(elt.text()).toBe('parent { hello brian }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/parent/user/igor');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(instanceCount).toBe(1);
|
|
||||||
expect(elt.text()).toBe('parent { hello igor }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should work with nested outlets', function () {
|
|
||||||
registerDirective('childCmp', {
|
|
||||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/b', component: 'oneCmp' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/a/...', component: 'childCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/a/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('outer { inner { one } }');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work when parent route has empty path', inject(function ($location) {
|
|
||||||
registerComponent('childCmp', {
|
|
||||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/b', component: 'oneCmp' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/...', component: 'childCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/b');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('outer { inner { one } }');
|
|
||||||
expect($location.path()).toBe('/b');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should work with recursive nested outlets', function () {
|
|
||||||
registerDirective('recurCmp', {
|
|
||||||
template: '<div>recur { <div ng-outlet></div> }</div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/recur', component: 'recurCmp' },
|
|
||||||
{ path: '/end', component: 'oneCmp' }
|
|
||||||
]});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/recur', component: 'recurCmp' },
|
|
||||||
{ path: '/', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
compile('<div>root { <div ng-outlet></div> }</div>');
|
|
||||||
$rootRouter.navigateByUrl('/recur/recur/end');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('root { one }');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should change location path', inject(function ($location) {
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user', component: 'userCmp' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect($location.path()).toBe('/user');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should pass through query terms to the location', inject(function ($location) {
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/user', component: 'userCmp' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user?x=y');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect($location.path()).toBe('/user');
|
|
||||||
expect($location.search()).toEqual({ x: 'y'});
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should change location to the canonical route', inject(function ($location) {
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/', redirectTo: ['/User'] },
|
|
||||||
{ path: '/user', component: 'userCmp', name: 'User' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect($location.path()).toBe('/user');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should change location to the canonical route with nested components', inject(function ($location) {
|
|
||||||
registerDirective('childRouter', {
|
|
||||||
template: '<div>inner { <div ng-outlet></div> }</div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/new-child', component: 'oneCmp', name: 'NewChild'},
|
|
||||||
{ path: '/new-child-two', component: 'twoCmp', name: 'NewChildTwo'}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/old-parent/old-child', redirectTo: ['/NewParent', 'NewChild'] },
|
|
||||||
{ path: '/old-parent/old-child-two', redirectTo: ['/NewParent', 'NewChildTwo'] },
|
|
||||||
{ path: '/new-parent/...', component: 'childRouter', name: 'NewParent' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/old-parent/old-child');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect($location.path()).toBe('/new-parent/new-child');
|
|
||||||
expect(elt.text()).toBe('inner { one }');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/old-parent/old-child-two');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect($location.path()).toBe('/new-parent/new-child-two');
|
|
||||||
expect(elt.text()).toBe('inner { two }');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should navigate when the location path changes', inject(function ($location) {
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/one', component: 'oneCmp' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$location.path('/one');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('one');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should navigate when the location query changes', inject(function ($location) {
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/get/params', component: 'getParams' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$location.url('/get/params?x=y');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('y');
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
it('should expose a "navigating" property on $rootRouter', inject(function ($q) {
|
|
||||||
var defer;
|
|
||||||
registerDirective('pendingActivate', {
|
|
||||||
$canActivate: function () {
|
|
||||||
defer = $q.defer();
|
|
||||||
return defer.promise;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$rootRouter.config([
|
|
||||||
{ path: '/pending-activate', component: 'pendingActivate' }
|
|
||||||
]);
|
|
||||||
compile('<div ng-outlet></div>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/pending-activate');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect($rootRouter.navigating).toBe(true);
|
|
||||||
defer.resolve();
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect($rootRouter.navigating).toBe(false);
|
|
||||||
}));
|
|
||||||
|
|
||||||
function registerDirective(name, options) {
|
|
||||||
var controller = getController(options);
|
|
||||||
function factory() {
|
|
||||||
return {
|
|
||||||
template: options.template || '',
|
|
||||||
controllerAs: name,
|
|
||||||
controller: controller
|
|
||||||
};
|
|
||||||
}
|
|
||||||
applyStaticProperties(controller, options);
|
|
||||||
$compileProvider.directive(name, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerComponent(name, options) {
|
|
||||||
|
|
||||||
var definition = {
|
|
||||||
template: options.template || '',
|
|
||||||
controller: getController(options),
|
|
||||||
};
|
|
||||||
applyStaticProperties(definition.controller, options);
|
|
||||||
$compileProvider.component(name, definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(template) {
|
|
||||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getController(options) {
|
|
||||||
var controller = options.controller || function () {};
|
|
||||||
[
|
|
||||||
'$routerOnActivate', '$routerOnDeactivate',
|
|
||||||
'$routerOnReuse', '$routerCanReuse',
|
|
||||||
'$routerCanDeactivate'
|
|
||||||
].forEach(function (hookName) {
|
|
||||||
if (options[hookName]) {
|
|
||||||
controller.prototype[hookName] = options[hookName];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyStaticProperties(target, options) {
|
|
||||||
['$canActivate', '$routeConfig'].forEach(function(property) {
|
|
||||||
if (options[property]) {
|
|
||||||
target[property] = options[property];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,225 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('router', function () {
|
|
||||||
|
|
||||||
var elt, testMod;
|
|
||||||
beforeEach(function () {
|
|
||||||
testMod = angular.module('testMod', ['ngComponentRouter'])
|
|
||||||
.value('$routerRootComponent', 'app');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work with a provided root component', function() {
|
|
||||||
|
|
||||||
registerComponent('homeCmp', {
|
|
||||||
template: 'Home'
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('app', {
|
|
||||||
template: '<div ng-outlet></div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/', component: 'homeCmp' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
module('testMod');
|
|
||||||
compileApp();
|
|
||||||
|
|
||||||
inject(function($location, $rootScope) {
|
|
||||||
$location.path('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('Home');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should bind the component to the current router', function() {
|
|
||||||
var router;
|
|
||||||
registerComponent('homeCmp', {
|
|
||||||
providers: { $router: '=' },
|
|
||||||
controller: function($scope, $element) {
|
|
||||||
this.$routerOnActivate = function() {
|
|
||||||
router = this.$router;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
template: 'Home'
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('app', {
|
|
||||||
template: '<div ng-outlet></div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/', component: 'homeCmp' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
module('testMod');
|
|
||||||
compileApp();
|
|
||||||
|
|
||||||
inject(function($location, $rootScope) {
|
|
||||||
$location.path('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
var homeElement = elt.find('home-cmp');
|
|
||||||
expect(homeElement.text()).toBe('Home');
|
|
||||||
expect(homeElement.isolateScope().$ctrl.$router).toBeDefined();
|
|
||||||
expect(router).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work when an async route is provided route data', function() {
|
|
||||||
registerComponent('homeCmp', {
|
|
||||||
template: 'Home ({{$ctrl.isAdmin}})',
|
|
||||||
$routerOnActivate: function(next, prev) {
|
|
||||||
this.isAdmin = next.routeData.data.isAdmin;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('app', {
|
|
||||||
template: '<div ng-outlet></div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/', loader: function($q) { return $q.when('homeCmp'); }, data: { isAdmin: true } }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
module('testMod');
|
|
||||||
compileApp();
|
|
||||||
|
|
||||||
inject(function($location, $rootScope) {
|
|
||||||
$location.path('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('Home (true)');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work with a templateUrl component', function() {
|
|
||||||
|
|
||||||
var $routerOnActivate = jasmine.createSpy('$routerOnActivate');
|
|
||||||
|
|
||||||
registerComponent('homeCmp', {
|
|
||||||
templateUrl: 'homeCmp.html',
|
|
||||||
$routerOnActivate: $routerOnActivate
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('app', {
|
|
||||||
template: '<div ng-outlet></div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/', component: 'homeCmp' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
module('testMod');
|
|
||||||
|
|
||||||
inject(function($location, $rootScope, $httpBackend) {
|
|
||||||
|
|
||||||
$httpBackend.expectGET('homeCmp.html').respond('Home');
|
|
||||||
|
|
||||||
compileApp();
|
|
||||||
|
|
||||||
$location.path('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
$httpBackend.flush();
|
|
||||||
var homeElement = elt.find('home-cmp');
|
|
||||||
expect(homeElement.text()).toBe('Home');
|
|
||||||
expect($routerOnActivate).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should provide the current instruction', function() {
|
|
||||||
registerComponent('homeCmp', {
|
|
||||||
template: 'Home ({{homeCmp.isAdmin}})'
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('app', {
|
|
||||||
template: '<div ng-outlet></div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/', component: 'homeCmp', name: 'Home' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
module('testMod');
|
|
||||||
|
|
||||||
inject(function($rootScope, $rootRouter, $location) {
|
|
||||||
compileApp();
|
|
||||||
|
|
||||||
$location.path('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
var instruction = $rootRouter.generate(['/Home']);
|
|
||||||
expect($rootRouter.currentInstruction).toEqual(instruction);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should provide the root level router', function() {
|
|
||||||
registerComponent('homeCmp', {
|
|
||||||
template: 'Home ({{homeCmp.isAdmin}})',
|
|
||||||
providers: {
|
|
||||||
$router: '<'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerComponent('app', {
|
|
||||||
template: '<div ng-outlet></div>',
|
|
||||||
$routeConfig: [
|
|
||||||
{ path: '/', component: 'homeCmp', name: 'Home' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
module('testMod');
|
|
||||||
|
|
||||||
inject(function($rootScope, $rootRouter, $location) {
|
|
||||||
compileApp();
|
|
||||||
|
|
||||||
$location.path('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
var homeElement = elt.find('home-cmp');
|
|
||||||
expect(homeElement.isolateScope().$ctrl.$router.root).toEqual($rootRouter);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function registerComponent(name, options) {
|
|
||||||
|
|
||||||
var definition = {
|
|
||||||
providers: options.providers,
|
|
||||||
controller: getController(options)
|
|
||||||
};
|
|
||||||
if (options.template) definition.template = options.template;
|
|
||||||
if (options.templateUrl) definition.templateUrl = options.templateUrl;
|
|
||||||
|
|
||||||
applyStaticProperties(definition.controller, options);
|
|
||||||
angular.module('testMod').component(name, definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
function compileApp() {
|
|
||||||
inject(function($compile, $rootScope) {
|
|
||||||
elt = $compile('<div><app></app</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
});
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getController(options) {
|
|
||||||
var controller = options.controller || function () {};
|
|
||||||
[
|
|
||||||
'$routerOnActivate', '$routerOnDeactivate',
|
|
||||||
'$routerOnReuse', '$routerCanReuse',
|
|
||||||
'$routerCanDeactivate'
|
|
||||||
].forEach(function (hookName) {
|
|
||||||
if (options[hookName]) {
|
|
||||||
controller.prototype[hookName] = options[hookName];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyStaticProperties(target, options) {
|
|
||||||
['$canActivate', '$routeConfig'].forEach(function(property) {
|
|
||||||
if (options[property]) {
|
|
||||||
target[property] = options[property];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,191 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('ngRoute shim', function () {
|
|
||||||
|
|
||||||
var elt,
|
|
||||||
$compile,
|
|
||||||
$rootScope,
|
|
||||||
$rootRouter,
|
|
||||||
$compileProvider,
|
|
||||||
$routeProvider;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
module('ng');
|
|
||||||
module('ngComponentRouter');
|
|
||||||
module('ngRouteShim');
|
|
||||||
module(function (_$compileProvider_, _$routeProvider_) {
|
|
||||||
$compileProvider = _$compileProvider_;
|
|
||||||
$routeProvider = _$routeProvider_;
|
|
||||||
});
|
|
||||||
|
|
||||||
inject(function (_$compile_, _$rootScope_, _$rootRouter_) {
|
|
||||||
$compile = _$compile_;
|
|
||||||
$rootScope = _$rootScope_;
|
|
||||||
$rootRouter = _$rootRouter_;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work in a simple case', function () {
|
|
||||||
$routeProvider.when('/', {
|
|
||||||
controller: function OneController() {
|
|
||||||
this.number = 'one';
|
|
||||||
},
|
|
||||||
controllerAs: 'oneCmp',
|
|
||||||
template: '{{oneCmp.number}}'
|
|
||||||
});
|
|
||||||
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('one');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should adapt routes with templateUrl', inject(function ($templateCache) {
|
|
||||||
$routeProvider.when('/', {
|
|
||||||
controller: function OneController() {
|
|
||||||
this.number = 'one';
|
|
||||||
},
|
|
||||||
controllerAs: 'oneCmp',
|
|
||||||
templateUrl: '/foo'
|
|
||||||
});
|
|
||||||
|
|
||||||
$templateCache.put('/foo', [200, '{{oneCmp.number}}', {}]);
|
|
||||||
|
|
||||||
compile('root {<ng-outlet></ng-outlet>}');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('root {one}');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should adapt routes using the "resolve" option', inject(function ($q) {
|
|
||||||
$routeProvider.when('/', {
|
|
||||||
controller: function TestController(resolvedService) {
|
|
||||||
this.resolvedValue = resolvedService;
|
|
||||||
},
|
|
||||||
controllerAs: 'testCmp',
|
|
||||||
resolve: {
|
|
||||||
resolvedService: function () {
|
|
||||||
return $q.when(42);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: 'value: {{testCmp.resolvedValue}}'
|
|
||||||
});
|
|
||||||
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect(elt.text()).toBe('value: 42');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should adapt routes with params', function () {
|
|
||||||
$routeProvider.when('/user/:name', {
|
|
||||||
controller: function UserController($routeParams) {
|
|
||||||
this.$routeParams = $routeParams;
|
|
||||||
},
|
|
||||||
controllerAs: 'userCmp',
|
|
||||||
template: 'hello {{userCmp.$routeParams.name}}'
|
|
||||||
});
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/brian');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hello brian');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/user/igor');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('hello igor');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should adapt routes with wildcard params', function () {
|
|
||||||
$routeProvider.when('/home/:params*', {
|
|
||||||
controller: function UserController($routeParams) {
|
|
||||||
this.$routeParams = $routeParams;
|
|
||||||
},
|
|
||||||
controllerAs: 'homeCmp',
|
|
||||||
template: 'rest: {{homeCmp.$routeParams.params}}'
|
|
||||||
});
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
compile('<ng-outlet></ng-outlet>');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/home/foo/bar/123');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('rest: foo/bar/123');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should warn about and ignore routes with optional params', function () {
|
|
||||||
spyOn(console, 'warn');
|
|
||||||
$routeProvider.when('/home/:params?', {
|
|
||||||
template: 'home'
|
|
||||||
});
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
compile('root {<ng-outlet></ng-outlet>}');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/home/test');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('root {}');
|
|
||||||
expect(console.warn)
|
|
||||||
.toHaveBeenCalledWith('Route for "/home/:params?" ignored because it has optional parameters. Skipping.',
|
|
||||||
'(1 skipped / 0 success / 1 total)');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should adapt routes with redirects', inject(function ($location) {
|
|
||||||
$routeProvider
|
|
||||||
.when('/home', {
|
|
||||||
template: 'welcome home!',
|
|
||||||
name: 'Home'
|
|
||||||
})
|
|
||||||
.when('/', {
|
|
||||||
redirectTo: '/home'
|
|
||||||
});
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
compile('root {<ng-outlet></ng-outlet>}');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('root {welcome home!}');
|
|
||||||
expect($location.path()).toBe('/home');
|
|
||||||
}));
|
|
||||||
|
|
||||||
//TODO: this is broken in recognition. un-xit this when https://github.com/angular/angular/issues/4133 is fixed
|
|
||||||
xit('should adapt "otherwise" routes', inject(function ($location) {
|
|
||||||
$routeProvider
|
|
||||||
.when('/home', {
|
|
||||||
template: 'welcome home!'
|
|
||||||
})
|
|
||||||
.otherwise({
|
|
||||||
redirectTo: '/home'
|
|
||||||
});
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
compile('root {<ng-outlet></ng-outlet>}');
|
|
||||||
|
|
||||||
$rootRouter.navigateByUrl('/somewhere');
|
|
||||||
$rootScope.$digest();
|
|
||||||
expect(elt.text()).toBe('root {welcome home!}');
|
|
||||||
expect($location.path()).toBe('/home');
|
|
||||||
}));
|
|
||||||
|
|
||||||
function compile(template) {
|
|
||||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,212 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
describe('ngLink', function () {
|
|
||||||
|
|
||||||
describe('html5Mode enabled', function () {
|
|
||||||
runHrefTestsAndExpectPrefix('/', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('html5Mode disabled', function () {
|
|
||||||
runHrefTestsAndExpectPrefix('', false, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('html5Mode disabled, with hash prefix', function () {
|
|
||||||
runHrefTestsAndExpectPrefix('', false, '!');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('html5Mode enabled', function () {
|
|
||||||
runHrefTestsAndExpectPrefix('/moo', true);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('html5Mode disabled', function () {
|
|
||||||
runHrefTestsAndExpectPrefix('/moo', false, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('html5Mode disabled, with hash prefix', function () {
|
|
||||||
runHrefTestsAndExpectPrefix('/moo', false, '!');
|
|
||||||
});
|
|
||||||
|
|
||||||
function runHrefTestsAndExpectPrefix(baseHref, html5Mode, hashPrefix) {
|
|
||||||
var prefix = html5Mode ? '.' : '#' + hashPrefix;
|
|
||||||
|
|
||||||
it('should allow linking from the parent to the child', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'oneCmp' },
|
|
||||||
{ path: '/b', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<a ng-link="[\'/Two\']">link</a> | outer { <div ng-outlet></div> }');
|
|
||||||
navigateTo('/a');
|
|
||||||
expect(elt.find('a').attr('href')).toBe(prefix + '/b');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow linking from the child and the parent', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'oneCmp' },
|
|
||||||
{ path: '/b', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('outer { <div ng-outlet></div> }');
|
|
||||||
navigateTo('/b');
|
|
||||||
expect(elt.find('a').attr('href')).toBe(prefix + '/b');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should allow params in routerLink directive', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: \'lol\'}]">{{twoLinkCmp.number}}</a></div>', function () {this.number = 'two';});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'twoLinkCmp' },
|
|
||||||
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<div ng-outlet></div>');
|
|
||||||
navigateTo('/a');
|
|
||||||
expect(elt.find('a').attr('href')).toBe(prefix + '/b/lol');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should update the href of links with bound params', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
registerComponent('twoLinkCmp', '<div><a ng-link="[\'/Two\', {param: $ctrl.number}]">{{$ctrl.number}}</a></div>', function () {this.number = 43;});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'twoLinkCmp' },
|
|
||||||
{ path: '/b/:param', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<div ng-outlet></div>');
|
|
||||||
navigateTo('/a');
|
|
||||||
expect(elt.find('a').text()).toBe('43');
|
|
||||||
expect(elt.find('a').attr('href')).toBe(prefix + '/b/43');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should navigate on left-mouse click when a link url matches a route', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/', component: 'oneCmp' },
|
|
||||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
|
||||||
expect(elt.text()).toBe('link | one');
|
|
||||||
expect(elt.find('a').attr('href')).toBe(prefix + '/two');
|
|
||||||
|
|
||||||
elt.find('a')[0].click();
|
|
||||||
inject(function($rootScope) { $rootScope.$digest(); });
|
|
||||||
expect(elt.text()).toBe('link | two');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should not navigate on non-left mouse click when a link url matches a route', function() {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/', component: 'oneCmp' },
|
|
||||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<a ng-link="[\'/Two\']">link</a> | <div ng-outlet></div>');
|
|
||||||
expect(elt.text()).toBe('link | one');
|
|
||||||
elt.find('a').triggerHandler({ type: 'click', which: 3 });
|
|
||||||
inject(function($rootScope) { $rootScope.$digest(); });
|
|
||||||
expect(elt.text()).toBe('link | one');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// See https://github.com/angular/router/issues/206
|
|
||||||
it('should not navigate a link without an href', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/', component: 'oneCmp' },
|
|
||||||
{ path: '/two', component: 'twoCmp', name: 'Two'}
|
|
||||||
]);
|
|
||||||
expect(function () {
|
|
||||||
var elt = compile('<a>link</a>');
|
|
||||||
expect(elt.text()).toBe('link');
|
|
||||||
elt.find('a')[0].click();
|
|
||||||
inject(function($rootScope) { $rootScope.$digest(); });
|
|
||||||
}).not.toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add an ng-link-active class on the current link', function() {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/', component: 'oneCmp', name: 'One' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<a ng-link="[\'/One\']">one</a> | <div ng-outlet></div>');
|
|
||||||
navigateTo('/');
|
|
||||||
expect(elt.find('a').attr('class')).toBe('ng-link-active');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not add a href if link attributes are undefined', function () {
|
|
||||||
setup({baseHref: baseHref, html5Mode: html5Mode, hashPrefix: hashPrefix});
|
|
||||||
configureRouter([
|
|
||||||
{ path: '/a', component: 'oneCmp' },
|
|
||||||
{ path: '/b', component: 'twoCmp', name: 'Two' }
|
|
||||||
]);
|
|
||||||
|
|
||||||
var elt = compile('<a ng-link="something.undefined">link</a> | outer { <div ng-outlet></div> }');
|
|
||||||
navigateTo('/a');
|
|
||||||
expect(elt.find('a').hasAttr('href')).toBeFalsy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function registerComponent(name, template, controller) {
|
|
||||||
module(function($compileProvider) {
|
|
||||||
$compileProvider.component(name, {
|
|
||||||
template: template,
|
|
||||||
controller: controller
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup(config) {
|
|
||||||
module(function($provide) {
|
|
||||||
$provide.decorator('$browser', function($delegate) {
|
|
||||||
$delegate.baseHref = function() { return config.baseHref; };
|
|
||||||
return $delegate;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
module('ngComponentRouter');
|
|
||||||
module(function($locationProvider) {
|
|
||||||
$locationProvider.html5Mode(config.html5Mode);
|
|
||||||
$locationProvider.hashPrefix(config.hashPrefix);
|
|
||||||
});
|
|
||||||
registerComponent('userCmp', '<div>hello {{$ctrl.$routeParams.name}}</div>', function () {});
|
|
||||||
registerComponent('oneCmp', '<div>{{$ctrl.number}}</div>', function () {this.number = 'one';});
|
|
||||||
registerComponent('twoCmp', '<div><a ng-link="[\'/Two\']">{{$ctrl.number}}</a></div>', function () {this.number = 'two';});
|
|
||||||
}
|
|
||||||
|
|
||||||
function configureRouter(routeConfig) {
|
|
||||||
inject(function($rootRouter) {
|
|
||||||
$rootRouter.config(routeConfig);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(template) {
|
|
||||||
var elt;
|
|
||||||
inject(function($compile, $rootScope) {
|
|
||||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
});
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateTo(url) {
|
|
||||||
inject(function($rootRouter, $rootScope) {
|
|
||||||
$rootRouter.navigateByUrl(url);
|
|
||||||
$rootScope.$digest();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,88 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helpers to keep tests DRY
|
|
||||||
*/
|
|
||||||
|
|
||||||
function componentTemplatePath(name) {
|
|
||||||
return './components/' + dashCase(name) + '/' + dashCase(name) + '.html';
|
|
||||||
}
|
|
||||||
|
|
||||||
function componentControllerName(name) {
|
|
||||||
return name[0].toUpperCase() + name.substr(1) + 'Controller';
|
|
||||||
}
|
|
||||||
|
|
||||||
function dashCase(str) {
|
|
||||||
return str.replace(/([A-Z])/g, function ($1) {
|
|
||||||
return '-' + $1.toLowerCase();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function provideHelpers(fn, preInject) {
|
|
||||||
return function () {
|
|
||||||
var elt,
|
|
||||||
$compile,
|
|
||||||
$rootScope,
|
|
||||||
$rootRouter,
|
|
||||||
$templateCache,
|
|
||||||
$controllerProvider;
|
|
||||||
|
|
||||||
module('ng');
|
|
||||||
module('ngNewRouter');
|
|
||||||
module(function(_$controllerProvider_) {
|
|
||||||
$controllerProvider = _$controllerProvider_;
|
|
||||||
});
|
|
||||||
|
|
||||||
inject(function(_$compile_, _$rootScope_, _$rootRouter_, _$templateCache_) {
|
|
||||||
$compile = _$compile_;
|
|
||||||
$rootScope = _$rootScope_;
|
|
||||||
$rootRouter = _$rootRouter_;
|
|
||||||
$templateCache = _$templateCache_;
|
|
||||||
});
|
|
||||||
|
|
||||||
function registerComponent(name, template, config) {
|
|
||||||
if (!template) {
|
|
||||||
template = '';
|
|
||||||
}
|
|
||||||
var ctrl;
|
|
||||||
if (!config) {
|
|
||||||
ctrl = function () {};
|
|
||||||
} else if (angular.isArray(config)) {
|
|
||||||
ctrl = function () {};
|
|
||||||
ctrl.$routeConfig = config;
|
|
||||||
} else if (typeof config === 'function') {
|
|
||||||
ctrl = config;
|
|
||||||
} else {
|
|
||||||
ctrl = function () {};
|
|
||||||
ctrl.prototype = config;
|
|
||||||
}
|
|
||||||
$controllerProvider.register(componentControllerName(name), ctrl);
|
|
||||||
put(name, template);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function put (name, template) {
|
|
||||||
$templateCache.put(componentTemplatePath(name), [200, template, {}]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(template) {
|
|
||||||
var elt = $compile('<div>' + template + '</div>')($rootScope);
|
|
||||||
$rootScope.$digest();
|
|
||||||
return elt;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn({
|
|
||||||
registerComponent: registerComponent,
|
|
||||||
$rootRouter: $rootRouter,
|
|
||||||
put: put,
|
|
||||||
compile: compile
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -23,7 +23,6 @@
|
||||||
"types": ["angular"]
|
"types": ["angular"]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"angular1_router",
|
|
||||||
"benchmarks_external",
|
"benchmarks_external",
|
||||||
"payload_tests",
|
"payload_tests",
|
||||||
"playground/",
|
"playground/",
|
||||||
|
|
Loading…
Reference in New Issue