feat(router): add angular 1.x router
This commit is contained in:
parent
78a8ba2307
commit
fde026a9e4
|
@ -36,6 +36,7 @@ env:
|
|||
- MODE=saucelabs DART_CHANNEL=dev
|
||||
- MODE=dart_experimental DART_CHANNEL=dev
|
||||
- MODE=js DART_CHANNEL=dev
|
||||
- MODE=router DART_CHANNEL=dev
|
||||
- MODE=lint DART_CHANNEL=dev
|
||||
|
||||
matrix:
|
||||
|
|
35
gulpfile.js
35
gulpfile.js
|
@ -37,6 +37,7 @@ var util = require('./tools/build/util');
|
|||
var bundler = require('./tools/build/bundle');
|
||||
var replace = require('gulp-replace');
|
||||
var insert = require('gulp-insert');
|
||||
var buildRouter = require('./modules/angular1_router/build');
|
||||
var uglify = require('gulp-uglify');
|
||||
var shouldLog = require('./tools/build/logging');
|
||||
var tslint = require('gulp-tslint');
|
||||
|
@ -604,6 +605,34 @@ gulp.task('!test.unit.js/karma-run', function(done) {
|
|||
runKarma('karma-js.conf.js', done);
|
||||
});
|
||||
|
||||
gulp.task('test.unit.router', function (done) {
|
||||
runSequence(
|
||||
'!test.unit.router/karma-server',
|
||||
function() {
|
||||
watch('modules/**', [
|
||||
'buildRouter.dev',
|
||||
'!test.unit.router/karma-run'
|
||||
]);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task('!test.unit.router/karma-server', function() {
|
||||
karma.server.start({configFile: __dirname + '/modules/angular1_router/karma-router.conf.js'});
|
||||
});
|
||||
|
||||
|
||||
gulp.task('!test.unit.router/karma-run', function(done) {
|
||||
karma.runner.run({configFile: __dirname + '/modules/angular1_router/karma-router.conf.js'}, function(exitCode) {
|
||||
// ignore exitCode, we don't want to fail the build in the interactive (non-ci) mode
|
||||
// karma will print all test failures
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('buildRouter.dev', function () {
|
||||
buildRouter();
|
||||
});
|
||||
|
||||
gulp.task('test.unit.dart', function (done) {
|
||||
runSequence(
|
||||
|
@ -641,6 +670,12 @@ gulp.task('!test.unit.dart/karma-server', function() {
|
|||
});
|
||||
|
||||
|
||||
gulp.task('test.unit.router/ci', function (done) {
|
||||
var browserConf = getBrowsersFromCLI();
|
||||
karma.server.start({configFile: __dirname + '/modules/angular1_router/karma-router.conf.js',
|
||||
singleRun: true, reporters: ['dots'], browsers: browserConf.browsersToRun}, done);
|
||||
});
|
||||
|
||||
gulp.task('test.unit.js/ci', function (done) {
|
||||
var browserConf = getBrowsersFromCLI();
|
||||
karma.server.start({configFile: __dirname + '/karma-js.conf.js',
|
||||
|
|
|
@ -27,6 +27,7 @@ module.exports = function(config) {
|
|||
|
||||
exclude: [
|
||||
'dist/dart/**/packages/**',
|
||||
'modules/angular1_router/**'
|
||||
],
|
||||
|
||||
karmaDartImports: {
|
||||
|
|
|
@ -31,6 +31,7 @@ module.exports = function(config) {
|
|||
|
||||
exclude: [
|
||||
'dist/js/dev/es5/**/e2e_test/**',
|
||||
'dist/angular1_router.js'
|
||||
],
|
||||
|
||||
customLaunchers: sauceConf.customLaunchers,
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
var fs = require('fs');
|
||||
var ts = require('typescript');
|
||||
|
||||
var files = [
|
||||
'lifecycle_annotations_impl.ts',
|
||||
'url_parser.ts',
|
||||
'path_recognizer.ts',
|
||||
'route_config_impl.ts',
|
||||
'async_route_handler.ts',
|
||||
'sync_route_handler.ts',
|
||||
'route_recognizer.ts',
|
||||
'instruction.ts',
|
||||
'route_config_nomalizer.ts',
|
||||
'route_lifecycle_reflector.ts',
|
||||
'route_registry.ts',
|
||||
'router.ts'
|
||||
];
|
||||
|
||||
var PRELUDE = '(function(){\n';
|
||||
var POSTLUDE = '\n}());\n';
|
||||
var FACADES = fs.readFileSync(__dirname + '/lib/facades.es5', 'utf8');
|
||||
var TRACEUR_RUNTIME = fs.readFileSync(__dirname + '/../../node_modules/traceur/bin/traceur-runtime.js', 'utf8');
|
||||
var DIRECTIVES = fs.readFileSync(__dirname + '/src/ng_outlet.js', 'utf8');
|
||||
function main() {
|
||||
var dir = __dirname + '/../angular2/src/router/';
|
||||
|
||||
var out = '';
|
||||
|
||||
var sharedCode = '';
|
||||
files.forEach(function (file) {
|
||||
var moduleName = 'router/' + file.replace(/\.ts$/, '');
|
||||
|
||||
sharedCode += transform(moduleName, fs.readFileSync(dir + file, 'utf8'));
|
||||
});
|
||||
|
||||
out += "angular.module('ngComponentRouter')";
|
||||
out += angularFactory('$router', ['$q', '$location', '$$controllerIntrospector',
|
||||
'$browser', '$rootScope', '$injector'], [
|
||||
FACADES,
|
||||
"var exports = {Injectable: function () {}};",
|
||||
"var require = function () {return exports;};",
|
||||
sharedCode,
|
||||
"var RouteConfig = exports.RouteConfig;",
|
||||
"angular.annotations = {RouteConfig: RouteConfig, CanActivate: exports.CanActivate};",
|
||||
"angular.stringifyInstruction = exports.stringifyInstruction;",
|
||||
"var RouteRegistry = exports.RouteRegistry;",
|
||||
"var RootRouter = exports.RootRouter;",
|
||||
//TODO: move this code into a templated JS file
|
||||
"var registry = new RouteRegistry();",
|
||||
"var location = new Location();",
|
||||
|
||||
"$$controllerIntrospector(function (name, constructor) {",
|
||||
"if (constructor.$canActivate) {",
|
||||
"constructor.annotations = constructor.annotations || [];",
|
||||
"constructor.annotations.push(new angular.annotations.CanActivate(function (instruction) {",
|
||||
"return $injector.invoke(constructor.$canActivate, constructor, {",
|
||||
"$routeParams: instruction.component ? instruction.component.params : instruction.params",
|
||||
"});",
|
||||
"}));",
|
||||
"}",
|
||||
"if (constructor.annotations) {",
|
||||
"constructor.annotations.forEach(function(annotation) {",
|
||||
"if (annotation instanceof RouteConfig) {",
|
||||
"annotation.configs.forEach(function (config) {",
|
||||
"registry.config(constructor, config);",
|
||||
"});",
|
||||
"}",
|
||||
"});",
|
||||
"}",
|
||||
"});",
|
||||
|
||||
"var router = new RootRouter(registry, undefined, location, new Object());",
|
||||
"$rootScope.$watch(function () { return $location.path(); }, function (path) { router.navigate(path); });",
|
||||
|
||||
"return router;"
|
||||
].join('\n'));
|
||||
|
||||
return PRELUDE + TRACEUR_RUNTIME + DIRECTIVES + out + POSTLUDE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a directory name and a file's TypeScript content, return an object with the ES5 code,
|
||||
* sourcemap, anf exported variable identifier name for the content.
|
||||
*/
|
||||
var IMPORT_RE = new RegExp("import \\{?([\\w\\n_, ]+)\\}? from '(.+)';?", 'g');
|
||||
function transform(dir, contents) {
|
||||
contents = contents.replace(IMPORT_RE, function (match, imports, includePath) {
|
||||
//TODO: remove special-case
|
||||
if (isFacadeModule(includePath) || includePath === './router_outlet') {
|
||||
return '';
|
||||
}
|
||||
return match;
|
||||
});
|
||||
return ts.transpile(contents, {
|
||||
target: ts.ScriptTarget.ES5,
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
sourceRoot: dir
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function angularFactory(name, deps, body) {
|
||||
return ".factory('" + name + "', [" +
|
||||
deps.map(function (service) {
|
||||
return "'" + service + "', ";
|
||||
}).join('') +
|
||||
"function (" + deps.join(', ') + ") {\n" + body + "\n}])";
|
||||
}
|
||||
|
||||
|
||||
function isFacadeModule(modulePath) {
|
||||
return modulePath.indexOf('facade') > -1 ||
|
||||
modulePath === 'angular2/src/reflection/reflection';
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
var dist = __dirname + '/../../dist';
|
||||
if (!fs.existsSync(dist)) {
|
||||
fs.mkdirSync(dist);
|
||||
}
|
||||
fs.writeFileSync(dist + '/angular_1_router.js', main(files));
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
<!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', ['$router', function ($router) {
|
||||
console.log($router);
|
||||
$router.navigate('/')
|
||||
.then(console.log.bind(console, 'resolve'), console.log.bind(console, 'reject'));
|
||||
}]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
var sauceConf = require('../../sauce.conf');
|
||||
|
||||
// This runs the tests for the router in Angular 1.x
|
||||
|
||||
module.exports = function (config) {
|
||||
var options = {
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
files: [
|
||||
'../../node_modules/angular/angular.js',
|
||||
'../../node_modules/angular-animate/angular-animate.js',
|
||||
'../../node_modules/angular-mocks/angular-mocks.js',
|
||||
|
||||
'../../dist/angular_1_router.js',
|
||||
|
||||
'test/*.es5.js',
|
||||
'test/*_spec.js'
|
||||
],
|
||||
|
||||
customLaunchers: sauceConf.customLaunchers,
|
||||
|
||||
browsers: ['ChromeCanary']
|
||||
};
|
||||
|
||||
config.set(options);
|
||||
};
|
|
@ -0,0 +1,305 @@
|
|||
function CONST() {
|
||||
return (function(target) {
|
||||
return target;
|
||||
});
|
||||
}
|
||||
|
||||
function IMPLEMENTS(_) {
|
||||
return (function(t) {
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 (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 = {
|
||||
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];
|
||||
},
|
||||
|
||||
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 = {
|
||||
equals: function (s1, s2) {
|
||||
return s1 === s2;
|
||||
},
|
||||
|
||||
split: function(s, re) {
|
||||
return s.split(re);
|
||||
},
|
||||
|
||||
substring: function(s, start, end) {
|
||||
return s.substr(start, end);
|
||||
},
|
||||
|
||||
replaceAll: function(s, from, replace) {
|
||||
return s.replace(from, replace);
|
||||
},
|
||||
|
||||
startsWith: function(s, start) {
|
||||
return s.startsWith(start);
|
||||
},
|
||||
|
||||
replaceAllMapped: function(s, from, cb) {
|
||||
return s.replace(from, function(matches) {
|
||||
// Remove offset & string from the result array
|
||||
matches.splice(-2, 2);
|
||||
// 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 BaseException = Error;
|
||||
|
||||
var ObservableWrapper = {
|
||||
callNext: function(){}
|
||||
};
|
||||
|
||||
// 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.path();
|
||||
};
|
||||
Location.prototype.go = function (url) {
|
||||
return $location.path(url);
|
||||
};
|
|
@ -0,0 +1,432 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
* A module for adding new a routing system Angular 1.
|
||||
*/
|
||||
angular.module('ngComponentRouter', [])
|
||||
.factory('$componentMapper', $componentMapperFactory)
|
||||
.directive('ngOutlet', ngOutletDirective)
|
||||
.directive('ngOutlet', ngOutletFillContentDirective)
|
||||
.directive('ngLink', ngLinkDirective)
|
||||
.directive('a', anchorLinkDirective); // TODO: make the anchor link feature configurable
|
||||
|
||||
/*
|
||||
* A module for inspecting controller constructors
|
||||
*/
|
||||
angular.module('ng')
|
||||
.provider('$$controllerIntrospector', $$controllerIntrospectorProvider)
|
||||
.config(controllerProviderDecorator);
|
||||
|
||||
/*
|
||||
* decorates with routing info
|
||||
*/
|
||||
function controllerProviderDecorator($controllerProvider, $$controllerIntrospectorProvider) {
|
||||
var register = $controllerProvider.register;
|
||||
$controllerProvider.register = function (name, ctrl) {
|
||||
$$controllerIntrospectorProvider.register(name, ctrl);
|
||||
return register.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: decorate $controller ?
|
||||
/*
|
||||
* private service that holds route mappings for each controller
|
||||
*/
|
||||
function $$controllerIntrospectorProvider() {
|
||||
var controllers = [];
|
||||
var controllersByName = {};
|
||||
var onControllerRegistered = null;
|
||||
return {
|
||||
register: function (name, constructor) {
|
||||
if (angular.isArray(constructor)) {
|
||||
constructor = constructor[constructor.length - 1];
|
||||
}
|
||||
controllersByName[name] = constructor;
|
||||
constructor.$$controllerName = name;
|
||||
if (onControllerRegistered) {
|
||||
onControllerRegistered(name, constructor);
|
||||
} else {
|
||||
controllers.push({name: name, constructor: constructor});
|
||||
}
|
||||
},
|
||||
$get: ['$componentMapper', function ($componentMapper) {
|
||||
var fn = function (newOnControllerRegistered) {
|
||||
onControllerRegistered = function (name, constructor) {
|
||||
name = $componentMapper.component(name);
|
||||
return newOnControllerRegistered(name, constructor);
|
||||
};
|
||||
while (controllers.length > 0) {
|
||||
var rule = controllers.pop();
|
||||
onControllerRegistered(rule.name, rule.constructor);
|
||||
}
|
||||
};
|
||||
|
||||
fn.getTypeByName = function (name) {
|
||||
return controllersByName[name];
|
||||
};
|
||||
|
||||
return fn;
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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, $injector, $q, $router, $componentMapper, $controller,
|
||||
$$controllerIntrospector, $templateRequest) {
|
||||
var rootRouter = $router;
|
||||
|
||||
return {
|
||||
restrict: 'AE',
|
||||
transclude: 'element',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
require: ['?^^ngOutlet', 'ngOutlet'],
|
||||
link: outletLink,
|
||||
controller: function () {},
|
||||
controllerAs: '$$ngOutlet'
|
||||
};
|
||||
|
||||
function outletLink(scope, $element, attrs, ctrls, $transclude) {
|
||||
var outletName = attrs.ngOutlet || 'default',
|
||||
parentCtrl = ctrls[0],
|
||||
myCtrl = ctrls[1],
|
||||
router = (parentCtrl && parentCtrl.$$router) || rootRouter;
|
||||
|
||||
var childRouter,
|
||||
currentInstruction,
|
||||
currentScope,
|
||||
currentController,
|
||||
currentElement,
|
||||
previousLeaveAnimation;
|
||||
|
||||
function cleanupLastView() {
|
||||
if (previousLeaveAnimation) {
|
||||
$animate.cancel(previousLeaveAnimation);
|
||||
previousLeaveAnimation = null;
|
||||
}
|
||||
|
||||
if (currentScope) {
|
||||
currentScope.$destroy();
|
||||
currentScope = null;
|
||||
}
|
||||
if (currentElement) {
|
||||
previousLeaveAnimation = $animate.leave(currentElement);
|
||||
previousLeaveAnimation.then(function () {
|
||||
previousLeaveAnimation = null;
|
||||
});
|
||||
currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
router.registerOutlet({
|
||||
commit: function (instruction) {
|
||||
var next;
|
||||
var componentInstruction = instruction.component;
|
||||
if (componentInstruction.reuse) {
|
||||
// todo(shahata): lifecycle - onReuse
|
||||
next = $q.when(true);
|
||||
} else {
|
||||
var self = this;
|
||||
next = this.deactivate(instruction).then(function () {
|
||||
return self.activate(componentInstruction);
|
||||
});
|
||||
}
|
||||
return next.then(function () {
|
||||
if (childRouter) {
|
||||
return childRouter.commit(instruction.child);
|
||||
} else {
|
||||
return $q.when(true);
|
||||
}
|
||||
});
|
||||
},
|
||||
canReuse: function (nextInstruction) {
|
||||
var result;
|
||||
var componentInstruction = nextInstruction.component;
|
||||
if (!currentInstruction ||
|
||||
currentInstruction.componentType !== componentInstruction.componentType) {
|
||||
result = false;
|
||||
} else {
|
||||
// todo(shahata): lifecycle - canReuse
|
||||
result = componentInstruction === currentInstruction ||
|
||||
angular.equals(componentInstruction.params, currentInstruction.params);
|
||||
}
|
||||
return $q.when(result).then(function (result) {
|
||||
// TODO: this is a hack
|
||||
componentInstruction.reuse = result;
|
||||
return result;
|
||||
});
|
||||
},
|
||||
canDeactivate: function (instruction) {
|
||||
if (currentInstruction && currentController && currentController.canDeactivate) {
|
||||
return $q.when(currentController.canDeactivate(instruction && instruction.component, currentInstruction));
|
||||
}
|
||||
return $q.when(true);
|
||||
},
|
||||
deactivate: function (instruction) {
|
||||
// todo(shahata): childRouter.dectivate, dispose component?
|
||||
var result = $q.when();
|
||||
return result.then(function () {
|
||||
if (currentController && currentController.onDeactivate) {
|
||||
return currentController.onDeactivate(instruction && instruction.component, currentInstruction);
|
||||
}
|
||||
});
|
||||
},
|
||||
activate: function (instruction) {
|
||||
var previousInstruction = currentInstruction;
|
||||
currentInstruction = instruction;
|
||||
childRouter = router.childRouter(instruction.componentType);
|
||||
|
||||
var controllerConstructor, componentName;
|
||||
controllerConstructor = instruction.componentType;
|
||||
componentName = $componentMapper.component(controllerConstructor.$$controllerName);
|
||||
|
||||
var componentTemplateUrl = $componentMapper.template(componentName);
|
||||
return $templateRequest(componentTemplateUrl).then(function (templateHtml) {
|
||||
myCtrl.$$router = childRouter;
|
||||
myCtrl.$$template = templateHtml;
|
||||
}).then(function () {
|
||||
var newScope = scope.$new();
|
||||
var locals = {
|
||||
$scope: newScope,
|
||||
$router: childRouter,
|
||||
$routeParams: (instruction.params || {})
|
||||
};
|
||||
|
||||
// todo(shahata): controllerConstructor is not minify friendly
|
||||
currentController = $controller(controllerConstructor, locals);
|
||||
|
||||
var clone = $transclude(newScope, function (clone) {
|
||||
$animate.enter(clone, null, currentElement || $element);
|
||||
cleanupLastView();
|
||||
});
|
||||
|
||||
var controllerAs = $componentMapper.controllerAs(componentName) || componentName;
|
||||
newScope[controllerAs] = currentController;
|
||||
currentElement = clone;
|
||||
currentScope = newScope;
|
||||
|
||||
if (currentController.onActivate) {
|
||||
return currentController.onActivate(instruction, previousInstruction);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, outletName);
|
||||
}
|
||||
}
|
||||
|
||||
function ngOutletFillContentDirective($compile) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
priority: -400,
|
||||
require: 'ngOutlet',
|
||||
link: function (scope, $element, attrs, ctrl) {
|
||||
var template = ctrl.$$template;
|
||||
$element.html(template);
|
||||
var link = $compile($element.contents());
|
||||
link(scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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', ['ngFuturisticRouter'])
|
||||
* .controller('AppController', ['$router', function($router) {
|
||||
* $router.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($router, $location, $parse) {
|
||||
var rootRouter = $router;
|
||||
|
||||
return {
|
||||
require: '?^^ngOutlet',
|
||||
restrict: 'A',
|
||||
link: ngLinkDirectiveLinkFn
|
||||
};
|
||||
|
||||
function ngLinkDirectiveLinkFn(scope, elt, attrs, ctrl) {
|
||||
var router = (ctrl && ctrl.$$router) || rootRouter;
|
||||
if (!router) {
|
||||
return;
|
||||
}
|
||||
|
||||
var link = attrs.ngLink || '';
|
||||
|
||||
function getLink(params) {
|
||||
return './' + angular.stringifyInstruction(router.generate(params));
|
||||
}
|
||||
|
||||
var routeParamsGetter = $parse(link);
|
||||
// we can avoid adding a watcher if it's a literal
|
||||
if (routeParamsGetter.constant) {
|
||||
var params = routeParamsGetter();
|
||||
elt.attr('href', getLink(params));
|
||||
} else {
|
||||
scope.$watch(function () {
|
||||
return routeParamsGetter(scope);
|
||||
}, function (params) {
|
||||
elt.attr('href', getLink(params));
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function anchorLinkDirective($router) {
|
||||
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);
|
||||
if (href && $router.recognize(href)) {
|
||||
$router.navigate(href);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name $componentMapperFactory
|
||||
* @description
|
||||
*
|
||||
* This lets you configure conventions for what controllers are named and where to load templates from.
|
||||
*
|
||||
* The default behavior is to dasherize and serve from `./components`. A component called `myWidget`
|
||||
* uses a controller named `MyWidgetController` and a template loaded from `./components/my-widget/my-widget.html`.
|
||||
*
|
||||
* A component is:
|
||||
* - a controller
|
||||
* - a template
|
||||
* - an optional router
|
||||
*
|
||||
* This service makes it easy to group all of them into a single concept.
|
||||
*/
|
||||
function $componentMapperFactory() {
|
||||
|
||||
var DEFAULT_SUFFIX = 'Controller';
|
||||
|
||||
var componentToCtrl = function componentToCtrlDefault(name) {
|
||||
return name[0].toUpperCase() + name.substr(1) + DEFAULT_SUFFIX;
|
||||
};
|
||||
|
||||
var componentToTemplate = function componentToTemplateDefault(name) {
|
||||
var dashName = dashCase(name);
|
||||
return './components/' + dashName + '/' + dashName + '.html';
|
||||
};
|
||||
|
||||
var ctrlToComponent = function ctrlToComponentDefault(name) {
|
||||
return name[0].toLowerCase() + name.substr(1, name.length - DEFAULT_SUFFIX.length - 1);
|
||||
};
|
||||
|
||||
var componentToControllerAs = function componentToControllerAsDefault(name) {
|
||||
return name;
|
||||
};
|
||||
|
||||
return {
|
||||
controllerName: function (name) {
|
||||
return componentToCtrl(name);
|
||||
},
|
||||
|
||||
controllerAs: function (name) {
|
||||
return componentToControllerAs(name);
|
||||
},
|
||||
|
||||
template: function (name) {
|
||||
return componentToTemplate(name);
|
||||
},
|
||||
|
||||
component: function (name) {
|
||||
return ctrlToComponent(name);
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setCtrlNameMapping
|
||||
* @description takes a function for mapping component names to component controller names
|
||||
*/
|
||||
setCtrlNameMapping: function (newFn) {
|
||||
componentToCtrl = newFn;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setCtrlAsMapping
|
||||
* @description takes a function for mapping component names to controllerAs name in the template
|
||||
*/
|
||||
setCtrlAsMapping: function (newFn) {
|
||||
componentToControllerAs = newFn;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setComponentFromCtrlMapping
|
||||
* @description takes a function for mapping component controller names to component names
|
||||
*/
|
||||
setComponentFromCtrlMapping: function (newFn) {
|
||||
ctrlToComponent = newFn;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setTemplateMapping
|
||||
* @description takes a function for mapping component names to component template URLs
|
||||
*/
|
||||
setTemplateMapping: function (newFn) {
|
||||
componentToTemplate = newFn;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function dashCase(str) {
|
||||
return str.replace(/([A-Z])/g, function ($1) {
|
||||
return '-' + $1.toLowerCase();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
'use strict';
|
||||
|
||||
describe('$componentMapper', function () {
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$templateCache;
|
||||
|
||||
function Ctrl() {
|
||||
this.message = 'howdy';
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function ($controllerProvider) {
|
||||
$controllerProvider.register('myComponentController', Ctrl);
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a component name to a controller name', inject(function ($componentMapper) {
|
||||
expect($componentMapper.controllerName('foo')).toBe('FooController');
|
||||
}));
|
||||
|
||||
it('should convert a controller name to a component name', inject(function ($componentMapper) {
|
||||
expect($componentMapper.component('FooController')).toBe('foo');
|
||||
}));
|
||||
|
||||
it('should convert a component name to a template URL', inject(function ($componentMapper) {
|
||||
expect($componentMapper.template('foo')).toBe('./components/foo/foo.html');
|
||||
}));
|
||||
|
||||
it('should work with a controller constructor fn and a template url', inject(function ($componentMapper) {
|
||||
var routes = {};
|
||||
$componentMapper.setCtrlNameMapping(function (name) {
|
||||
return routes[name].controller;
|
||||
});
|
||||
$componentMapper.setTemplateMapping(function (name) {
|
||||
return routes[name].templateUrl;
|
||||
});
|
||||
$componentMapper.setCtrlAsMapping(function (name) {
|
||||
return 'ctrl';
|
||||
});
|
||||
|
||||
routes.myComponent = {
|
||||
controller: Ctrl,
|
||||
templateUrl: '/foo'
|
||||
};
|
||||
|
||||
inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
$templateCache = _$templateCache_;
|
||||
});
|
||||
|
||||
$templateCache.put('/foo', [200, '{{ctrl.message}}', {}]);
|
||||
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', component: Ctrl }
|
||||
]);
|
||||
|
||||
$router.navigate('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('howdy');
|
||||
}));
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
'use strict';
|
||||
|
||||
describe('$$controllerIntrospector', function () {
|
||||
|
||||
var $controllerProvider;
|
||||
|
||||
beforeEach(function() {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function(_$controllerProvider_) {
|
||||
$controllerProvider = _$controllerProvider_;
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the introspector function whenever a controller is registered', inject(function ($$controllerIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$controllerIntrospector(spy);
|
||||
function Ctrl(){}
|
||||
$controllerProvider.register('SomeController', Ctrl);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('some', Ctrl);
|
||||
}));
|
||||
|
||||
it('should call the introspector function whenever a controller is registered with array annotations', inject(function ($$controllerIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$controllerIntrospector(spy);
|
||||
function Ctrl(foo){}
|
||||
$controllerProvider.register('SomeController', ['foo', Ctrl]);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('some', Ctrl);
|
||||
}));
|
||||
|
||||
it('should retrieve a constructor', inject(function ($$controllerIntrospector) {
|
||||
function Ctrl(foo){}
|
||||
$controllerProvider.register('SomeController', ['foo', Ctrl]);
|
||||
expect($$controllerIntrospector.getTypeByName('SomeController')).toBe(Ctrl);
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,800 @@
|
|||
'use strict';
|
||||
|
||||
describe('ngOutlet', function () {
|
||||
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$templateCache,
|
||||
$controllerProvider,
|
||||
$componentMapperProvider;
|
||||
|
||||
var OneController, TwoController, UserController;
|
||||
|
||||
function instructionFor(componentType) {
|
||||
return jasmine.objectContaining({componentType: componentType});
|
||||
}
|
||||
|
||||
|
||||
beforeEach(function () {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function (_$controllerProvider_, _$componentMapperProvider_) {
|
||||
$controllerProvider = _$controllerProvider_;
|
||||
$componentMapperProvider = _$componentMapperProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$compile_, _$rootScope_, _$router_, _$templateCache_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
$templateCache = _$templateCache_;
|
||||
});
|
||||
|
||||
UserController = registerComponent('user', '<div>hello {{user.name}}</div>', function ($routeParams) {
|
||||
this.name = $routeParams.name;
|
||||
});
|
||||
OneController = registerComponent('one', '<div>{{one.number}}</div>', boringController('number', 'one'));
|
||||
TwoController = registerComponent('two', '<div>{{two.number}}</div>', boringController('number', 'two'));
|
||||
});
|
||||
|
||||
|
||||
it('should work in a simple case', function () {
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', component: OneController }
|
||||
]);
|
||||
|
||||
$router.navigate('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('one');
|
||||
});
|
||||
|
||||
|
||||
// See https://github.com/angular/router/issues/105
|
||||
xit('should warn when instantiating a component with no controller', function () {
|
||||
put('noController', '<div>{{ 2 + 2 }}</div>');
|
||||
$router.config([
|
||||
{ path: '/', component: 'noController' }
|
||||
]);
|
||||
|
||||
spyOn(console, 'warn');
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
$router.navigate('/');
|
||||
|
||||
expect(console.warn).toHaveBeenCalledWith('Could not find controller for', 'NoControllerController');
|
||||
expect(elt.text()).toBe('4');
|
||||
});
|
||||
|
||||
|
||||
it('should navigate between components with different parameters', function () {
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: UserController }
|
||||
]);
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigate('/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello brian');
|
||||
|
||||
$router.navigate('/user/igor');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('hello igor');
|
||||
});
|
||||
|
||||
|
||||
it('should not reactivate a parent when navigating between child components with different parameters', function () {
|
||||
var spy = jasmine.createSpy('onActivate');
|
||||
function ParentController() {}
|
||||
ParentController.$routeConfig = [
|
||||
{ path: '/user/:name', component: UserController }
|
||||
];
|
||||
ParentController.prototype.onActivate = spy;
|
||||
|
||||
registerComponent('parent', 'parent { <ng-outlet></ng-outlet> }', ParentController);
|
||||
|
||||
$router.config([
|
||||
{ path: '/parent/...', component: ParentController }
|
||||
]);
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.navigate('/parent/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('parent { hello brian }');
|
||||
|
||||
spy.calls.reset();
|
||||
|
||||
$router.navigate('/parent/user/igor');
|
||||
$rootScope.$digest();
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('parent { hello igor }');
|
||||
});
|
||||
|
||||
|
||||
it('should work with nested outlets', function () {
|
||||
var childComponent = registerComponent('childComponent', '<div>inner { <div ng-outlet></div> }</div>', [
|
||||
{ path: '/b', component: OneController }
|
||||
]);
|
||||
|
||||
$router.config([
|
||||
{ path: '/a/...', component: childComponent }
|
||||
]);
|
||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
||||
|
||||
$router.navigate('/a/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('outer { inner { one } }');
|
||||
});
|
||||
|
||||
|
||||
it('should work with recursive nested outlets', function () {
|
||||
put('two', '<div>recur { <div ng-outlet></div> }</div>');
|
||||
$router.config([
|
||||
{ path: '/recur', component: TwoController },
|
||||
{ path: '/', component: OneController }
|
||||
]);
|
||||
|
||||
compile('<div>root { <div ng-outlet></div> }</div>');
|
||||
$router.navigate('/');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('root { one }');
|
||||
});
|
||||
|
||||
|
||||
it('should allow linking from the parent to the child', function () {
|
||||
put('one', '<div>{{number}}</div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: OneController },
|
||||
{ path: '/b', component: TwoController, as: 'two' }
|
||||
]);
|
||||
compile('<a ng-link="[\'/two\']">link</a> | outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b');
|
||||
});
|
||||
|
||||
it('should allow linking from the child and the parent', function () {
|
||||
put('one', '<div><a ng-link="[\'/two\']">{{number}}</a></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: OneController },
|
||||
{ path: '/b', component: TwoController, as: 'two' }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b');
|
||||
});
|
||||
|
||||
|
||||
it('should allow params in routerLink directive', function () {
|
||||
put('router', '<div>outer { <div ng-outlet></div> }</div>');
|
||||
put('one', '<div><a ng-link="[\'/two\', {param: \'lol\'}]">{{number}}</a></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: OneController },
|
||||
{ path: '/b/:param', component: TwoController, as: 'two' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b/lol');
|
||||
});
|
||||
|
||||
// TODO: test dynamic links
|
||||
it('should update the href of links with bound params', function () {
|
||||
put('router', '<div>outer { <div ng-outlet></div> }</div>');
|
||||
put('one', '<div><a ng-link="[\'/two\', {param: one.number}]">{{one.number}}</a></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: OneController },
|
||||
{ path: '/b/:param', component: TwoController, as: 'two' }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.find('a').attr('href')).toBe('./b/one');
|
||||
});
|
||||
|
||||
|
||||
it('should run the activate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var activate = registerComponent('activate', '', {
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate }
|
||||
]);
|
||||
compile('<div>outer { <div ng-outlet></div> }</div>');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should pass instruction into the activate hook of a controller', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var UserController = registerComponent('user', '', {
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: UserController }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user/brian');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor(UserController), undefined);
|
||||
});
|
||||
|
||||
|
||||
it('should pass previous instruction into the activate hook of a controller', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var activate = registerComponent('activate', '', {
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: OneController },
|
||||
{ path: '/post/:id', component: activate }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user/brian');
|
||||
$rootScope.$digest();
|
||||
$router.navigate('/post/123');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor(activate),
|
||||
instructionFor(OneController));
|
||||
});
|
||||
|
||||
|
||||
it('should inject $scope into the controller constructor', function () {
|
||||
|
||||
var injectedScope;
|
||||
var UserController = registerComponent('user', '', function ($scope) {
|
||||
injectedScope = $scope;
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user', component: UserController }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(injectedScope).toBeDefined();
|
||||
});
|
||||
|
||||
|
||||
it('should run the deactivate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('deactivate');
|
||||
var deactivate = registerComponent('deactivate', '', {
|
||||
onDeactivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: deactivate },
|
||||
{ path: '/b', component: OneController }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
$router.navigate('/b');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('should pass instructions into the deactivate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('deactivate');
|
||||
var deactivate = registerComponent('deactivate', '', {
|
||||
onDeactivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: deactivate },
|
||||
{ path: '/post/:id', component: OneController }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user/brian');
|
||||
$rootScope.$digest();
|
||||
$router.navigate('/post/123');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor(OneController),
|
||||
instructionFor(deactivate));
|
||||
});
|
||||
|
||||
|
||||
it('should run the deactivate hook before the activate hook', function () {
|
||||
var log = [];
|
||||
|
||||
var activate = registerComponent('activate', '', {
|
||||
onActivate: function () {
|
||||
log.push('activate');
|
||||
}
|
||||
});
|
||||
|
||||
var deactivate = registerComponent('deactivate', '', {
|
||||
onDeactivate: function () {
|
||||
log.push('deactivate');
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: deactivate },
|
||||
{ path: '/b', component: activate }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
$router.navigate('/b');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(log).toEqual(['deactivate', 'activate']);
|
||||
});
|
||||
|
||||
|
||||
it('should not activate a component when canActivate returns false', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var activate = registerComponent('activate', '', {
|
||||
canActivate: function () {
|
||||
return false;
|
||||
},
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('outer { }');
|
||||
});
|
||||
|
||||
|
||||
it('should activate a component when canActivate returns true', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var activate = registerComponent('activate', 'hi', {
|
||||
canActivate: function () {
|
||||
return true;
|
||||
},
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).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');
|
||||
var activate = registerComponent('activate', 'hi', {
|
||||
canActivate: function () {
|
||||
return $q.when(true);
|
||||
},
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/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);
|
||||
var activate = registerComponent('activate', '', {
|
||||
canActivate: spy
|
||||
});
|
||||
|
||||
spy.$inject = ['$routeParams', '$http'];
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: activate }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user/brian');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith({name: 'brian'}, $http);
|
||||
}));
|
||||
|
||||
|
||||
it('should not navigate when canDeactivate returns false', function () {
|
||||
var activate = registerComponent('activate', 'hi', {
|
||||
canDeactivate: function () {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate },
|
||||
{ path: '/b', component: OneController }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { hi }');
|
||||
|
||||
$router.navigate('/b');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { hi }');
|
||||
});
|
||||
|
||||
|
||||
it('should navigate when canDeactivate returns true', function () {
|
||||
var activate = registerComponent('activate', 'hi', {
|
||||
canDeactivate: function () {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate },
|
||||
{ path: '/b', component: OneController }
|
||||
]);
|
||||
compile('outer { <div ng-outlet></div> }');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { hi }');
|
||||
|
||||
$router.navigate('/b');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('outer { one }');
|
||||
});
|
||||
|
||||
|
||||
it('should activate a component when canActivate returns true', function () {
|
||||
var spy = jasmine.createSpy('activate');
|
||||
var activate = registerComponent('activate', 'hi', {
|
||||
canActivate: function () {
|
||||
return true;
|
||||
},
|
||||
onActivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/a', component: activate }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/a');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(elt.text()).toBe('hi');
|
||||
});
|
||||
|
||||
|
||||
it('should pass instructions into the canDeactivate hook of controllers', function () {
|
||||
var spy = jasmine.createSpy('canDeactivate').and.returnValue(true);
|
||||
var deactivate = registerComponent('deactivate', '', {
|
||||
canDeactivate: spy
|
||||
});
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: deactivate },
|
||||
{ path: '/post/:id', component: OneController }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user/brian');
|
||||
$rootScope.$digest();
|
||||
$router.navigate('/post/123');
|
||||
$rootScope.$digest();
|
||||
expect(spy).toHaveBeenCalledWith(instructionFor(OneController),
|
||||
instructionFor(deactivate));
|
||||
});
|
||||
|
||||
|
||||
it('should change location path', inject(function ($location) {
|
||||
$router.config([
|
||||
{ path: '/user', component: UserController }
|
||||
]);
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/user');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/user');
|
||||
}));
|
||||
|
||||
// TODO: test injecting $scope
|
||||
|
||||
it('should navigate on left-mouse click when a link url matches a route', function () {
|
||||
$router.config([
|
||||
{ path: '/', component: OneController },
|
||||
{ path: '/two', component: TwoController }
|
||||
]);
|
||||
|
||||
compile('<a href="/two">link</a> | <div ng-outlet></div>');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | one');
|
||||
elt.find('a')[0].click();
|
||||
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | two');
|
||||
});
|
||||
|
||||
|
||||
it('should not navigate on non-left mouse click when a link url matches a route', inject(function ($router) {
|
||||
$router.config([
|
||||
{ path: '/', component: OneController },
|
||||
{ path: '/two', component: TwoController }
|
||||
]);
|
||||
|
||||
compile('<a href="./two">link</a> | <div ng-outlet></div>');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link | one');
|
||||
elt.find('a').triggerHandler({ type: 'click', which: 3 });
|
||||
|
||||
$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 () {
|
||||
$router.config([
|
||||
{ path: '/', component: OneController },
|
||||
{ path: '/two', component: TwoController }
|
||||
]);
|
||||
expect(function () {
|
||||
compile('<a>link</a>');
|
||||
$rootScope.$digest();
|
||||
expect(elt.text()).toBe('link');
|
||||
elt.find('a')[0].click();
|
||||
$rootScope.$digest();
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should change location to the canonical route', inject(function ($location) {
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', redirectTo: '/user' },
|
||||
{ path: '/user', component: UserController }
|
||||
]);
|
||||
|
||||
$router.navigate('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/user');
|
||||
}));
|
||||
|
||||
|
||||
it('should change location to the canonical route with nested components', inject(function ($location) {
|
||||
var childRouter = registerComponent('childRouter', '<div>inner { <div ng-outlet></div> }</div>', [
|
||||
{ path: '/old-child', redirectTo: '/new-child' },
|
||||
{ path: '/new-child', component: OneController},
|
||||
{ path: '/old-child-two', redirectTo: '/new-child-two' },
|
||||
{ path: '/new-child-two', component: TwoController}
|
||||
]);
|
||||
|
||||
$router.config([
|
||||
{ path: '/old-parent', redirectTo: '/new-parent' },
|
||||
{ path: '/new-parent/...', component: childRouter }
|
||||
]);
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/old-parent/old-child');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect($location.path()).toBe('/new-parent/new-child');
|
||||
expect(elt.text()).toBe('inner { one }');
|
||||
|
||||
$router.navigate('/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) {
|
||||
$router.config([
|
||||
{ path: '/one', component: OneController }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$location.path('/one');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('one');
|
||||
}));
|
||||
|
||||
|
||||
it('should expose a "navigating" property on $router', inject(function ($q) {
|
||||
var defer;
|
||||
var pendingActivate = registerComponent('pendingActivate', '', {
|
||||
onActivate: function () {
|
||||
defer = $q.defer();
|
||||
return defer.promise;
|
||||
}
|
||||
});
|
||||
$router.config([
|
||||
{ path: '/pendingActivate', component: pendingActivate }
|
||||
]);
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.navigate('/pendingActivate');
|
||||
$rootScope.$digest();
|
||||
expect($router.navigating).toBe(true);
|
||||
defer.resolve();
|
||||
$rootScope.$digest();
|
||||
expect($router.navigating).toBe(false);
|
||||
}));
|
||||
|
||||
|
||||
function registerComponent(name, template, config) {
|
||||
var Ctrl;
|
||||
if (!template) {
|
||||
template = '';
|
||||
}
|
||||
if (!config) {
|
||||
Ctrl = function () {};
|
||||
} else if (angular.isArray(config)) {
|
||||
Ctrl = function () {};
|
||||
Ctrl.annotations = [new angular.annotations.RouteConfig(config)];
|
||||
} else if (typeof config === 'function') {
|
||||
Ctrl = config;
|
||||
} else {
|
||||
Ctrl = function () {};
|
||||
if (config.canActivate) {
|
||||
Ctrl.$canActivate = config.canActivate;
|
||||
delete config.canActivate;
|
||||
}
|
||||
Ctrl.prototype = config;
|
||||
}
|
||||
$controllerProvider.register(componentControllerName(name), Ctrl);
|
||||
put(name, template);
|
||||
return Ctrl;
|
||||
}
|
||||
|
||||
function boringController(model, value) {
|
||||
return function () {
|
||||
this[model] = value;
|
||||
};
|
||||
}
|
||||
|
||||
function put(name, template) {
|
||||
$templateCache.put(componentTemplatePath(name), [200, template, {}]);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
describe('ngOutlet animations', function () {
|
||||
|
||||
var elt,
|
||||
$animate,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$templateCache,
|
||||
$controllerProvider;
|
||||
|
||||
function UserController($routeParams) {
|
||||
this.name = $routeParams.name;
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
module('ngAnimate');
|
||||
module('ngAnimateMock');
|
||||
module('ngComponentRouter');
|
||||
module(function (_$controllerProvider_) {
|
||||
$controllerProvider = _$controllerProvider_;
|
||||
});
|
||||
|
||||
inject(function (_$animate_, _$compile_, _$rootScope_, _$router_, _$templateCache_) {
|
||||
$animate = _$animate_;
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
$templateCache = _$templateCache_;
|
||||
});
|
||||
|
||||
put('user', '<div>hello {{user.name}}</div>');
|
||||
$controllerProvider.register('UserController', UserController);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
expect($animate.queue).toEqual([]);
|
||||
});
|
||||
|
||||
it('should work in a simple case', function () {
|
||||
var item;
|
||||
|
||||
compile('<div ng-outlet></div>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/user/:name', component: UserController }
|
||||
]);
|
||||
|
||||
$router.navigate('/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
|
||||
$router.navigate('/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 put(name, template) {
|
||||
$templateCache.put(componentTemplatePath(name), [200, template, {}]);
|
||||
}
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 boringController (model, value) {
|
||||
return function () {
|
||||
this[model] = value;
|
||||
};
|
||||
}
|
||||
|
||||
function provideHelpers(fn, preInject) {
|
||||
return function () {
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$templateCache,
|
||||
$controllerProvider;
|
||||
|
||||
module('ng');
|
||||
module('ngNewRouter');
|
||||
module(function(_$controllerProvider_) {
|
||||
$controllerProvider = _$controllerProvider_;
|
||||
});
|
||||
|
||||
inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
$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,
|
||||
$router: $router,
|
||||
put: put,
|
||||
compile: compile
|
||||
})
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"angular": "1.3.5",
|
||||
"angular-animate": "1.3.5",
|
||||
"angular-mocks": "1.3.5",
|
||||
"base64-js": "^0.0.8",
|
||||
"bower": "^1.3.12",
|
||||
"broccoli": "^0.15.3",
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo =============================================================================
|
||||
# go to project dir
|
||||
SCRIPT_DIR=$(dirname $0)
|
||||
# this is needed because we're running JS tests in Dartium too
|
||||
source $SCRIPT_DIR/env_dart.sh
|
||||
cd $SCRIPT_DIR/../..
|
||||
|
||||
./node_modules/.bin/gulp buildRouter.dev
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo =============================================================================
|
||||
# go to project dir
|
||||
SCRIPT_DIR=$(dirname $0)
|
||||
source $SCRIPT_DIR/env_dart.sh
|
||||
cd $SCRIPT_DIR/../..
|
||||
|
||||
./node_modules/.bin/gulp test.unit.router/ci --browsers=${KARMA_BROWSERS:-ChromeCanary}
|
|
@ -76,6 +76,7 @@ module.exports = function makeBrowserTree(options, destinationPath) {
|
|||
exclude: [
|
||||
'**/*.cjs',
|
||||
'benchmarks/e2e_test/**',
|
||||
'angular1_router/**',
|
||||
// Exclude ES6 polyfill typings when tsc target=ES6
|
||||
'angular2/traceur-runtime.d.ts',
|
||||
'angular2/typings/es6-promise/**'
|
||||
|
|
|
@ -56,7 +56,7 @@ function stripModulePrefix(relativePath: string): string {
|
|||
|
||||
function getSourceTree() {
|
||||
// Transpile everything in 'modules' except for rtts_assertions.
|
||||
var tsInputTree = modulesFunnel(['**/*.js', '**/*.ts', '**/*.dart']);
|
||||
var tsInputTree = modulesFunnel(['**/*.js', '**/*.ts', '**/*.dart'], ['angular1_router/**/*']);
|
||||
var transpiled = ts2dart(tsInputTree, {
|
||||
generateLibraryName: true,
|
||||
generateSourceMap: false,
|
||||
|
@ -147,7 +147,7 @@ function getDocsTree() {
|
|||
var licenses = new MultiCopy('', {
|
||||
srcPath: 'LICENSE',
|
||||
targetPatterns: ['modules/*'],
|
||||
exclude: ['*/rtts_assert', '*/http', '*/upgrade'], // Not in dart.
|
||||
exclude: ['*/rtts_assert', '*/http', '*/upgrade', '*/angular1_router'] // Not in dart.
|
||||
});
|
||||
licenses = stew.rename(licenses, stripModulePrefix);
|
||||
|
||||
|
@ -157,7 +157,7 @@ function getDocsTree() {
|
|||
relativePath => relativePath.replace(/\.dart\.md$/, '.md'));
|
||||
// Copy all assets, ignore .js. and .dart. (handled above).
|
||||
var docs = modulesFunnel(['**/*.md', '**/*.png', '**/*.html', '**/*.css', '**/*.scss'],
|
||||
['**/*.js.md', '**/*.dart.md']);
|
||||
['**/*.js.md', '**/*.dart.md', 'angular1_router/**/*']);
|
||||
|
||||
var assets = modulesFunnel(['examples/**/*.json']);
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ module.exports = function makeNodeTree(destinationPath) {
|
|||
'angular2/test/core/zone/**',
|
||||
'angular2/test/test_lib/fake_async_spec.ts',
|
||||
'angular2/test/render/xhr_impl_spec.ts',
|
||||
'angular2/test/forms/**'
|
||||
'angular2/test/forms/**',
|
||||
'angular1_router/**'
|
||||
]
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue