Compare commits
58 Commits
Author | SHA1 | Date | |
---|---|---|---|
9a9a7ac7b5 | |||
423dd2898a | |||
ee2d6e572a | |||
ba8645c529 | |||
eba53fd16c | |||
c0698de2ea | |||
dc6728e7ad | |||
eb173bcd30 | |||
e39e16ae6a | |||
ff56da554f | |||
d160591453 | |||
380377139b | |||
9c7680ef69 | |||
69572ac2f1 | |||
76f53f929c | |||
ba52f2f252 | |||
e122f6bf0f | |||
453c758d1a | |||
015ca47336 | |||
f32e287812 | |||
9946ac5cc7 | |||
593e05dc97 | |||
da77b580c9 | |||
1733ea09bd | |||
1f4fa28fac | |||
c12e56ec0c | |||
4a5c8bd25f | |||
9c954740d1 | |||
11ed8f56ab | |||
a49acbf027 | |||
8e41910429 | |||
a4ab14bf74 | |||
ea4fc9b421 | |||
0956acee58 | |||
2ca67e1674 | |||
472666fc2b | |||
462316b0f1 | |||
96c2b2cc25 | |||
3d407fc010 | |||
64bd672e3a | |||
ef38676091 | |||
38be2b81c6 | |||
39a71eb0ec | |||
2fe6fb1163 | |||
b5afe51b26 | |||
170525a225 | |||
0c98f45105 | |||
e7025c9423 | |||
8f295287a2 | |||
030facc66a | |||
45af8f6752 | |||
33a79028be | |||
09226d96f8 | |||
6c3166e6e4 | |||
8df328b15a | |||
115f18fa06 | |||
511cd4d182 | |||
87d5d49530 |
62
CHANGELOG.md
62
CHANGELOG.md
@ -1,3 +1,65 @@
|
|||||||
|
<a name="2.2.4"></a>
|
||||||
|
## [2.2.4](https://github.com/angular/angular/compare/2.2.3...2.2.4) (2016-11-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **common:** update DatePipe to allow closure compilation ([eba53fd](https://github.com/angular/angular/commit/eba53fd))
|
||||||
|
* **compiler:** fix performance regression caused by 5b0f9e2 ([ee2d6e5](https://github.com/angular/angular/commit/ee2d6e5)), closes [#13146](https://github.com/angular/angular/issues/13146)
|
||||||
|
* **compiler-cli:** fix paths in source maps to be relative ([eb173bc](https://github.com/angular/angular/commit/eb173bc)), closes [#13040](https://github.com/angular/angular/issues/13040)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.2.3"></a>
|
||||||
|
## [2.2.3](https://github.com/angular/angular/compare/2.2.2...2.2.3) (2016-11-23)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** Revert: fix versions of `@angular/tsc-wrapped` ([015ca47](https://github.com/angular/angular/commit/015ca47))
|
||||||
|
* **animations:** Revert: blend in all previously transitioned styles into next animation if interrupted ([c12e56e](https://github.com/angular/angular/commit/c12e56e))
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.2.2"></a>
|
||||||
|
## [2.2.2](https://github.com/angular/angular/compare/2.2.1...2.2.2) (2016-11-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** blend in all previously transitioned styles into next animation if interrupted ([#13014](https://github.com/angular/angular/issues/13014)) ([ea4fc9b](https://github.com/angular/angular/commit/ea4fc9b)), closes [#13013](https://github.com/angular/angular/issues/13013)
|
||||||
|
* **benchmarks:** use sanitized style values ([#12943](https://github.com/angular/angular/issues/12943)) ([33a7902](https://github.com/angular/angular/commit/33a7902))
|
||||||
|
* **closure:** quote date pattern aliases ([#13012](https://github.com/angular/angular/issues/13012)) ([0956ace](https://github.com/angular/angular/commit/0956ace))
|
||||||
|
* **compiler:** fix versions of `@angular/tsc-wrapped` ([2fe6fb1](https://github.com/angular/angular/commit/2fe6fb1))
|
||||||
|
* **router:** add a banner file for the router ([#12919](https://github.com/angular/angular/issues/12919)) ([8df328b](https://github.com/angular/angular/commit/8df328b))
|
||||||
|
* **router:** add a banner file for the router ([#12919](https://github.com/angular/angular/issues/12919)) ([511cd4d](https://github.com/angular/angular/commit/511cd4d))
|
||||||
|
* **router:** removes a peer dependency from router to upgrade ([115f18f](https://github.com/angular/angular/commit/115f18f))
|
||||||
|
* **router:** removes a peer dependency from router to upgrade ([87d5d49](https://github.com/angular/angular/commit/87d5d49))
|
||||||
|
* **router:** support redirects to named outlets ([09226d9](https://github.com/angular/angular/commit/09226d9)), closes [#12740](https://github.com/angular/angular/issues/12740) [#9921](https://github.com/angular/angular/issues/9921)
|
||||||
|
* **upgrade:** call ng1 lifecycle hooks ([#12875](https://github.com/angular/angular/issues/12875)) ([462316b](https://github.com/angular/angular/commit/462316b))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="2.3.0-beta.0"></a>
|
||||||
|
# [2.3.0-beta.0](https://github.com/angular/angular/compare/2.2.0...2.3.0-beta.0) (2016-11-17)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** assert xliff messages have translations ([7908679](https://github.com/angular/angular/commit/7908679)), closes [#12815](https://github.com/angular/angular/issues/12815) [#12604](https://github.com/angular/angular/issues/12604)
|
||||||
|
* **compiler:** updates hash algo for xmb/xtb files ([2f14415](https://github.com/angular/angular/commit/2f14415))
|
||||||
|
* **core:** fix placeholders handling in i18n. ([76e4911](https://github.com/angular/angular/commit/76e4911)), closes [#12512](https://github.com/angular/angular/issues/12512)
|
||||||
|
* **core:** misc i18n fixes ([ed5e98d](https://github.com/angular/angular/commit/ed5e98d))
|
||||||
|
* **core:** xmb serializer uses decimal messaged IDs ([08c038e](https://github.com/angular/angular/commit/08c038e)), closes [#12511](https://github.com/angular/angular/issues/12511)
|
||||||
|
* **platform-browser:** enable AOT ([efbbefd](https://github.com/angular/angular/commit/efbbefd)), closes [#12783](https://github.com/angular/angular/issues/12783)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **core:** add `attachView` / `detachView` to ApplicationRef ([9f7d32a](https://github.com/angular/angular/commit/9f7d32a)), closes [#9293](https://github.com/angular/angular/issues/9293)
|
||||||
|
* **core:** expose `ViewRef` as `ChangeDetectorRef` ([1b5384e](https://github.com/angular/angular/commit/1b5384e)), closes [#12722](https://github.com/angular/angular/issues/12722)
|
||||||
|
* **core:** implements a decimal fingerprint for i18n ([582550a](https://github.com/angular/angular/commit/582550a))
|
||||||
|
* **router:** register router with ngprobe ([c2fae72](https://github.com/angular/angular/commit/c2fae72))
|
||||||
|
* **router_link:** add skipLocationChange and replaceUrl inputs ([#12850](https://github.com/angular/angular/issues/12850)) ([46d1502](https://github.com/angular/angular/commit/46d1502))
|
||||||
|
|
||||||
|
Note: The 2.3.0-beta.0 release also contains all the changes present in the 2.2.1 release.
|
||||||
|
|
||||||
<a name="2.2.1"></a>
|
<a name="2.2.1"></a>
|
||||||
## [2.2.1](https://github.com/angular/angular/compare/2.2.0...2.2.1) (2016-11-17)
|
## [2.2.1](https://github.com/angular/angular/compare/2.2.0...2.2.1) (2016-11-17)
|
||||||
|
|
||||||
|
29
build.sh
29
build.sh
@ -20,6 +20,10 @@ PACKAGES=(core
|
|||||||
benchpress)
|
benchpress)
|
||||||
BUILD_ALL=true
|
BUILD_ALL=true
|
||||||
BUNDLE=true
|
BUNDLE=true
|
||||||
|
VERSION_PREFIX=$(node -p "require('./package.json').version")
|
||||||
|
VERSION_SUFFIX="-$(git log --oneline -1 | awk '{print $1}')"
|
||||||
|
ROUTER_VERSION_PREFIX=$(node -p "require('./package.json').version.replace(/^2/, '3')")
|
||||||
|
REMOVE_BENCHPRESS=false
|
||||||
|
|
||||||
for ARG in "$@"; do
|
for ARG in "$@"; do
|
||||||
case "$ARG" in
|
case "$ARG" in
|
||||||
@ -31,6 +35,10 @@ for ARG in "$@"; do
|
|||||||
--bundle=*)
|
--bundle=*)
|
||||||
BUNDLE=( "${ARG#--bundle=}" )
|
BUNDLE=( "${ARG#--bundle=}" )
|
||||||
;;
|
;;
|
||||||
|
--publish)
|
||||||
|
VERSION_SUFFIX=""
|
||||||
|
REMOVE_BENCHPRESS=true
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option $ARG."
|
echo "Unknown option $ARG."
|
||||||
exit 1
|
exit 1
|
||||||
@ -38,6 +46,10 @@ for ARG in "$@"; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
VERSION="${VERSION_PREFIX}${VERSION_SUFFIX}"
|
||||||
|
ROUTER_VERSION="${ROUTER_VERSION_PREFIX}${VERSION_SUFFIX}"
|
||||||
|
echo "====== BUILDING: Version ${VERSION} (Router ${ROUTER_VERSION})"
|
||||||
|
|
||||||
export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools
|
export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools
|
||||||
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
|
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
|
||||||
UGLIFYJS=`pwd`/node_modules/.bin/uglifyjs
|
UGLIFYJS=`pwd`/node_modules/.bin/uglifyjs
|
||||||
@ -197,9 +209,24 @@ do
|
|||||||
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_UPGRADE_ES5_MIN_PATH} ${UMD_UPGRADE_ES5_PATH}
|
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_UPGRADE_ES5_MIN_PATH} ${UMD_UPGRADE_ES5_PATH}
|
||||||
fi
|
fi
|
||||||
) 2>&1 | grep -v "as external dependency"
|
) 2>&1 | grep -v "as external dependency"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
(
|
||||||
|
echo "====== VERSION: Updating version references"
|
||||||
|
cd ${DESTDIR}
|
||||||
|
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-PLACEHOLDER/${VERSION}/g\" $""(grep -ril 0\.0\.0\-PLACEHOLDER .)"
|
||||||
|
perl -p -i -e "s/0\.0\.0\-PLACEHOLDER/${VERSION}/g" $(grep -ril 0\.0\.0\-PLACEHOLDER .) < /dev/null 2> /dev/null
|
||||||
|
echo "====== EXECUTE: perl -p -i -e \"s/0\.0\.0\-ROUTERPLACEHOLDER/${ROUTER_VERSION}/g\" $""(grep -ril 0\.0\.0\-ROUTERPLACEHOLDER .)"
|
||||||
|
perl -p -i -e "s/0\.0\.0\-ROUTERPLACEHOLDER/${ROUTER_VERSION}/g" $(grep -ril 0\.0\.0\-ROUTERPLACEHOLDER .) < /dev/null 2> /dev/null
|
||||||
|
)
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
echo "====== Building examples: ./modules/@angular/examples/build.sh ====="
|
echo "====== Building examples: ./modules/@angular/examples/build.sh ====="
|
||||||
./modules/@angular/examples/build.sh
|
./modules/@angular/examples/build.sh
|
||||||
|
|
||||||
|
if [[ ${REMOVE_BENCHPRESS} == true ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "==== Removing benchpress from publication"
|
||||||
|
rm -r dist/packages-dist/benchpress
|
||||||
|
fi
|
||||||
|
@ -4,7 +4,7 @@ machine:
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
pre:
|
pre:
|
||||||
- npm install -g npm
|
- npm install -g npm@3.6.0
|
||||||
|
|
||||||
test:
|
test:
|
||||||
override:
|
override:
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
import {browser} from 'protractor';
|
import {browser} from 'protractor';
|
||||||
|
|
||||||
const assertEventsContainsName = function(events: any[], eventName: string) {
|
const assertEventsContainsName = function(events: any[], eventName: string) {
|
||||||
|
@ -59,7 +59,7 @@ const _observableStrategy = new ObservableStrategy();
|
|||||||
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'}
|
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'}
|
||||||
*
|
*
|
||||||
* It's also possible to use `async` with Observables. The example below binds the `time` Observable
|
* It's also possible to use `async` with Observables. The example below binds the `time` Observable
|
||||||
* to the view. The Observable continuesly updates the view with the current time.
|
* to the view. The Observable continuously updates the view with the current time.
|
||||||
*
|
*
|
||||||
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'}
|
* {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'}
|
||||||
*
|
*
|
||||||
|
@ -46,7 +46,7 @@ export class CodeGenerator {
|
|||||||
let root = this.options.basePath;
|
let root = this.options.basePath;
|
||||||
for (const eachRootDir of this.options.rootDirs || []) {
|
for (const eachRootDir of this.options.rootDirs || []) {
|
||||||
if (this.options.trace) {
|
if (this.options.trace) {
|
||||||
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
console.error(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
||||||
}
|
}
|
||||||
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
||||||
root = eachRootDir;
|
root = eachRootDir;
|
||||||
@ -161,7 +161,7 @@ export function extractProgramSymbols(
|
|||||||
|
|
||||||
const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath);
|
const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath);
|
||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
console.log(`WARNING: no metadata found for ${absSrcPath}`);
|
console.warn(`WARNING: no metadata found for ${absSrcPath}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ export class PathMappedReflectorHost extends ReflectorHost {
|
|||||||
ts.resolveModuleName(m, rootedContainingFile, this.options, this.context).resolvedModule;
|
ts.resolveModuleName(m, rootedContainingFile, this.options, this.context).resolvedModule;
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
if (this.options.traceResolution) {
|
if (this.options.traceResolution) {
|
||||||
console.log('resolve', m, containingFile, '=>', resolved.resolvedFileName);
|
console.error('resolve', m, containingFile, '=>', resolved.resolvedFileName);
|
||||||
}
|
}
|
||||||
return resolved.resolvedFileName;
|
return resolved.resolvedFileName;
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ export class PathMappedReflectorHost extends ReflectorHost {
|
|||||||
containingFile = this.resolveAssetUrl(containingFile, '');
|
containingFile = this.resolveAssetUrl(containingFile, '');
|
||||||
|
|
||||||
if (this.options.traceResolution) {
|
if (this.options.traceResolution) {
|
||||||
console.log(
|
console.error(
|
||||||
'getImportPath from containingFile', containingFile, 'to importedFile', importedFile);
|
'getImportPath from containingFile', containingFile, 'to importedFile', importedFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
}
|
}
|
||||||
return parameters;
|
return parameters;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`Failed on type ${JSON.stringify(type)} with error ${e}`);
|
console.error(`Failed on type ${JSON.stringify(type)} with error ${e}`);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
|
||||||
"target": "es5",
|
|
||||||
"lib": ["es6", "dom"],
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
"declaration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"outDir": "../../../dist/packages-dist/compiler-cli",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@angular/core": ["../../../dist/packages-dist/core"],
|
"@angular/core": ["../../../dist/packages-dist/core"],
|
||||||
"@angular/common": ["../../../dist/packages-dist/common"],
|
"@angular/common": ["../../../dist/packages-dist/common"],
|
||||||
@ -14,11 +14,11 @@
|
|||||||
"@angular/platform-browser": ["../../../dist/packages-dist/platform-browser"],
|
"@angular/platform-browser": ["../../../dist/packages-dist/platform-browser"],
|
||||||
"@angular/tsc-wrapped": ["../../../dist/tools/@angular/tsc-wrapped"]
|
"@angular/tsc-wrapped": ["../../../dist/tools/@angular/tsc-wrapped"]
|
||||||
},
|
},
|
||||||
"experimentalDecorators": true,
|
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"sourceRoot": ".",
|
"sourceMap": true,
|
||||||
"outDir": "../../../dist/packages-dist/compiler-cli",
|
"inlineSources": true,
|
||||||
"declaration": true,
|
"target": "es5",
|
||||||
|
"lib": ["es6", "dom"],
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"exclude": ["integrationtest"],
|
"exclude": ["integrationtest"],
|
||||||
|
@ -141,7 +141,7 @@ export class CompileMetadataResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _loadDirectiveMetadata(directiveType: any, isSync: boolean): Promise<any> {
|
private _loadDirectiveMetadata(directiveType: any, isSync: boolean): () => Promise<any> {
|
||||||
if (this._directiveCache.has(directiveType)) {
|
if (this._directiveCache.has(directiveType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ export class CompileMetadataResolver {
|
|||||||
if (isSync) {
|
if (isSync) {
|
||||||
throw new ComponentStillLoadingError(directiveType);
|
throw new ComponentStillLoadingError(directiveType);
|
||||||
}
|
}
|
||||||
return templateMeta.asyncResult.then(createDirectiveMetadata);
|
return () => templateMeta.asyncResult.then(createDirectiveMetadata);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// directive
|
// directive
|
||||||
@ -441,8 +441,10 @@ export class CompileMetadataResolver {
|
|||||||
transitiveModule.directives.push(declaredIdentifier);
|
transitiveModule.directives.push(declaredIdentifier);
|
||||||
declaredDirectives.push(declaredIdentifier);
|
declaredDirectives.push(declaredIdentifier);
|
||||||
this._addTypeToModule(declaredType, moduleType);
|
this._addTypeToModule(declaredType, moduleType);
|
||||||
transitiveModule.directiveLoaders.push(
|
const loader = this._loadDirectiveMetadata(declaredType, isSync);
|
||||||
() => this._loadDirectiveMetadata(declaredType, isSync));
|
if (loader) {
|
||||||
|
transitiveModule.directiveLoaders.push(loader);
|
||||||
|
}
|
||||||
} else if (this._pipeResolver.isPipe(declaredType)) {
|
} else if (this._pipeResolver.isPipe(declaredType)) {
|
||||||
transitiveModule.pipesSet.add(declaredType);
|
transitiveModule.pipesSet.add(declaredType);
|
||||||
transitiveModule.pipes.push(declaredIdentifier);
|
transitiveModule.pipes.push(declaredIdentifier);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {APP_ID} from '../application_tokens';
|
|
||||||
import {SimpleChange, devModeEqual} from '../change_detection/change_detection';
|
import {SimpleChange, devModeEqual} from '../change_detection/change_detection';
|
||||||
import {UNINITIALIZED} from '../change_detection/change_detection_util';
|
import {UNINITIALIZED} from '../change_detection/change_detection_util';
|
||||||
import {Inject, Injectable} from '../di';
|
import {Inject, Injectable} from '../di';
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
/* tslint:disable:no-console */
|
||||||
import * as webdriver from 'selenium-webdriver';
|
import * as webdriver from 'selenium-webdriver';
|
||||||
declare var browser: any;
|
declare var browser: any;
|
||||||
declare var expect: any;
|
declare var expect: any;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Observable
|
// #docregion Observable
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {Subscriber} from 'rxjs/Subscriber';
|
import {Subscriber} from 'rxjs/Subscriber';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Observable
|
// #docregion Observable
|
||||||
import 'rxjs/add/operator/map';
|
import 'rxjs/add/operator/map';
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Observable
|
// #docregion Observable
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {Subscriber} from 'rxjs/Subscriber';
|
import {Subscriber} from 'rxjs/Subscriber';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Component
|
// #docregion Component
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {FormArray, FormControl, FormGroup} from '@angular/forms';
|
import {FormArray, FormControl, FormGroup} from '@angular/forms';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Component
|
// #docregion Component
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Component
|
// #docregion Component
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {NgForm} from '@angular/forms';
|
import {NgForm} from '@angular/forms';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Component
|
// #docregion Component
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {NgForm} from '@angular/forms';
|
import {NgForm} from '@angular/forms';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
// #docregion Component
|
// #docregion Component
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
||||||
|
@ -44,7 +44,8 @@ const DATE_FORMATS_SPLIT =
|
|||||||
/((?:[^yMLdHhmsazZEwGjJ']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|J+|j+|m+|s+|a|z|Z|G+|w+))(.*)/;
|
/((?:[^yMLdHhmsazZEwGjJ']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|J+|j+|m+|s+|a|z|Z|G+|w+))(.*)/;
|
||||||
|
|
||||||
const PATTERN_ALIASES: {[format: string]: DateFormatterFn} = {
|
const PATTERN_ALIASES: {[format: string]: DateFormatterFn} = {
|
||||||
yMMMdjms: datePartGetterFactory(combine([
|
// Keys are quoted so they do not get renamed during closure compilation.
|
||||||
|
'yMMMdjms': datePartGetterFactory(combine([
|
||||||
digitCondition('year', 1),
|
digitCondition('year', 1),
|
||||||
nameCondition('month', 3),
|
nameCondition('month', 3),
|
||||||
digitCondition('day', 1),
|
digitCondition('day', 1),
|
||||||
@ -52,68 +53,70 @@ const PATTERN_ALIASES: {[format: string]: DateFormatterFn} = {
|
|||||||
digitCondition('minute', 1),
|
digitCondition('minute', 1),
|
||||||
digitCondition('second', 1),
|
digitCondition('second', 1),
|
||||||
])),
|
])),
|
||||||
yMdjm: datePartGetterFactory(combine([
|
'yMdjm': datePartGetterFactory(combine([
|
||||||
digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1),
|
digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1),
|
||||||
digitCondition('hour', 1), digitCondition('minute', 1)
|
digitCondition('hour', 1), digitCondition('minute', 1)
|
||||||
])),
|
])),
|
||||||
yMMMMEEEEd: datePartGetterFactory(combine([
|
'yMMMMEEEEd': datePartGetterFactory(combine([
|
||||||
digitCondition('year', 1), nameCondition('month', 4), nameCondition('weekday', 4),
|
digitCondition('year', 1), nameCondition('month', 4), nameCondition('weekday', 4),
|
||||||
digitCondition('day', 1)
|
digitCondition('day', 1)
|
||||||
])),
|
])),
|
||||||
yMMMMd: datePartGetterFactory(
|
'yMMMMd': datePartGetterFactory(
|
||||||
combine([digitCondition('year', 1), nameCondition('month', 4), digitCondition('day', 1)])),
|
combine([digitCondition('year', 1), nameCondition('month', 4), digitCondition('day', 1)])),
|
||||||
yMMMd: datePartGetterFactory(
|
'yMMMd': datePartGetterFactory(
|
||||||
combine([digitCondition('year', 1), nameCondition('month', 3), digitCondition('day', 1)])),
|
combine([digitCondition('year', 1), nameCondition('month', 3), digitCondition('day', 1)])),
|
||||||
yMd: datePartGetterFactory(
|
'yMd': datePartGetterFactory(
|
||||||
combine([digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1)])),
|
combine([digitCondition('year', 1), digitCondition('month', 1), digitCondition('day', 1)])),
|
||||||
jms: datePartGetterFactory(combine(
|
'jms': datePartGetterFactory(combine(
|
||||||
[digitCondition('hour', 1), digitCondition('second', 1), digitCondition('minute', 1)])),
|
[digitCondition('hour', 1), digitCondition('second', 1), digitCondition('minute', 1)])),
|
||||||
jm: datePartGetterFactory(combine([digitCondition('hour', 1), digitCondition('minute', 1)]))
|
'jm': datePartGetterFactory(combine([digitCondition('hour', 1), digitCondition('minute', 1)]))
|
||||||
};
|
};
|
||||||
|
|
||||||
const DATE_FORMATS: {[format: string]: DateFormatterFn} = {
|
const DATE_FORMATS: {[format: string]: DateFormatterFn} = {
|
||||||
yyyy: datePartGetterFactory(digitCondition('year', 4)),
|
// Keys are quoted so they do not get renamed.
|
||||||
yy: datePartGetterFactory(digitCondition('year', 2)),
|
'yyyy': datePartGetterFactory(digitCondition('year', 4)),
|
||||||
y: datePartGetterFactory(digitCondition('year', 1)),
|
'yy': datePartGetterFactory(digitCondition('year', 2)),
|
||||||
MMMM: datePartGetterFactory(nameCondition('month', 4)),
|
'y': datePartGetterFactory(digitCondition('year', 1)),
|
||||||
MMM: datePartGetterFactory(nameCondition('month', 3)),
|
'MMMM': datePartGetterFactory(nameCondition('month', 4)),
|
||||||
MM: datePartGetterFactory(digitCondition('month', 2)),
|
'MMM': datePartGetterFactory(nameCondition('month', 3)),
|
||||||
M: datePartGetterFactory(digitCondition('month', 1)),
|
'MM': datePartGetterFactory(digitCondition('month', 2)),
|
||||||
LLLL: datePartGetterFactory(nameCondition('month', 4)),
|
'M': datePartGetterFactory(digitCondition('month', 1)),
|
||||||
L: datePartGetterFactory(nameCondition('month', 1)),
|
'LLLL': datePartGetterFactory(nameCondition('month', 4)),
|
||||||
dd: datePartGetterFactory(digitCondition('day', 2)),
|
'L': datePartGetterFactory(nameCondition('month', 1)),
|
||||||
d: datePartGetterFactory(digitCondition('day', 1)),
|
'dd': datePartGetterFactory(digitCondition('day', 2)),
|
||||||
HH: digitModifier(
|
'd': datePartGetterFactory(digitCondition('day', 1)),
|
||||||
|
'HH': digitModifier(
|
||||||
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), false)))),
|
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), false)))),
|
||||||
H: hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), false))),
|
'H': hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), false))),
|
||||||
hh: digitModifier(
|
'hh': digitModifier(
|
||||||
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), true)))),
|
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), true)))),
|
||||||
h: hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
'h': hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
||||||
jj: datePartGetterFactory(digitCondition('hour', 2)),
|
'jj': datePartGetterFactory(digitCondition('hour', 2)),
|
||||||
j: datePartGetterFactory(digitCondition('hour', 1)),
|
'j': datePartGetterFactory(digitCondition('hour', 1)),
|
||||||
mm: digitModifier(datePartGetterFactory(digitCondition('minute', 2))),
|
'mm': digitModifier(datePartGetterFactory(digitCondition('minute', 2))),
|
||||||
m: datePartGetterFactory(digitCondition('minute', 1)),
|
'm': datePartGetterFactory(digitCondition('minute', 1)),
|
||||||
ss: digitModifier(datePartGetterFactory(digitCondition('second', 2))),
|
'ss': digitModifier(datePartGetterFactory(digitCondition('second', 2))),
|
||||||
s: datePartGetterFactory(digitCondition('second', 1)),
|
's': datePartGetterFactory(digitCondition('second', 1)),
|
||||||
// while ISO 8601 requires fractions to be prefixed with `.` or `,`
|
// while ISO 8601 requires fractions to be prefixed with `.` or `,`
|
||||||
// we can be just safely rely on using `sss` since we currently don't support single or two digit
|
// we can be just safely rely on using `sss` since we currently don't support single or two digit
|
||||||
// fractions
|
// fractions
|
||||||
sss: datePartGetterFactory(digitCondition('second', 3)),
|
'sss': datePartGetterFactory(digitCondition('second', 3)),
|
||||||
EEEE: datePartGetterFactory(nameCondition('weekday', 4)),
|
'EEEE': datePartGetterFactory(nameCondition('weekday', 4)),
|
||||||
EEE: datePartGetterFactory(nameCondition('weekday', 3)),
|
'EEE': datePartGetterFactory(nameCondition('weekday', 3)),
|
||||||
EE: datePartGetterFactory(nameCondition('weekday', 2)),
|
'EE': datePartGetterFactory(nameCondition('weekday', 2)),
|
||||||
E: datePartGetterFactory(nameCondition('weekday', 1)),
|
'E': datePartGetterFactory(nameCondition('weekday', 1)),
|
||||||
a: hourClockExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
'a': hourClockExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
||||||
Z: timeZoneGetter('short'),
|
'Z': timeZoneGetter('short'),
|
||||||
z: timeZoneGetter('long'),
|
'z': timeZoneGetter('long'),
|
||||||
ww: datePartGetterFactory({}), // Week of year, padded (00-53). Week 01 is the week with the
|
'ww': datePartGetterFactory({}), // Week of year, padded (00-53). Week 01 is the week with the
|
||||||
// first Thursday of the year. not support ?
|
// first Thursday of the year. not support ?
|
||||||
w: datePartGetterFactory({}), // Week of year (0-53). Week 1 is the week with the first Thursday
|
'w':
|
||||||
|
datePartGetterFactory({}), // Week of year (0-53). Week 1 is the week with the first Thursday
|
||||||
// of the year not support ?
|
// of the year not support ?
|
||||||
G: datePartGetterFactory(nameCondition('era', 1)),
|
'G': datePartGetterFactory(nameCondition('era', 1)),
|
||||||
GG: datePartGetterFactory(nameCondition('era', 2)),
|
'GG': datePartGetterFactory(nameCondition('era', 2)),
|
||||||
GGG: datePartGetterFactory(nameCondition('era', 3)),
|
'GGG': datePartGetterFactory(nameCondition('era', 3)),
|
||||||
GGGG: datePartGetterFactory(nameCondition('era', 4))
|
'GGGG': datePartGetterFactory(nameCondition('era', 4))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ export function isJsObject(o: any): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function print(obj: Error | Object) {
|
export function print(obj: Error | Object) {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
console.log(obj);
|
console.log(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ export class XHRConnection implements Connection {
|
|||||||
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
||||||
// response/responseType properties were introduced in ResourceLoader Level2 spec
|
// response/responseType properties were introduced in ResourceLoader Level2 spec
|
||||||
// (supported by IE10)
|
// (supported by IE10)
|
||||||
body = _xhr.response == null ? _xhr.responseText : _xhr.response;
|
body = (typeof _xhr.response === 'undefined') ? _xhr.responseText : _xhr.response;
|
||||||
|
|
||||||
// Implicitly strip a potential XSSI prefix.
|
// Implicitly strip a potential XSSI prefix.
|
||||||
if (typeof body === 'string') {
|
if (typeof body === 'string') {
|
||||||
|
@ -85,6 +85,7 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||||||
|
|
||||||
log(error: string): void {
|
log(error: string): void {
|
||||||
if (window.console) {
|
if (window.console) {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
window.console.log && window.console.log(error);
|
window.console.log && window.console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ export class AngularProfiler {
|
|||||||
|
|
||||||
constructor(ref: ComponentRef<any>) { this.appRef = ref.injector.get(ApplicationRef); }
|
constructor(ref: ComponentRef<any>) { this.appRef = ref.injector.get(ApplicationRef); }
|
||||||
|
|
||||||
|
// tslint:disable:no-console
|
||||||
/**
|
/**
|
||||||
* Exercises change detection in a loop and then prints the average amount of
|
* Exercises change detection in a loop and then prints the average amount of
|
||||||
* time in milliseconds how long a single round of change detection takes for
|
* time in milliseconds how long a single round of change detection takes for
|
||||||
|
@ -63,6 +63,7 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||||||
|
|
||||||
logError(error: string) { console.error(error); }
|
logError(error: string) { console.error(error); }
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
log(error: string) { console.log(error); }
|
log(error: string) { console.log(error); }
|
||||||
|
|
||||||
logGroup(error: string) { console.error(error); }
|
logGroup(error: string) { console.error(error); }
|
||||||
|
@ -22,10 +22,12 @@ export class WorkerDomAdapter extends DomAdapter {
|
|||||||
if (console.error) {
|
if (console.error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
} else {
|
} else {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
log(error: any /** TODO #9100 */) { console.log(error); }
|
log(error: any /** TODO #9100 */) { console.log(error); }
|
||||||
|
|
||||||
logGroup(error: any /** TODO #9100 */) {
|
logGroup(error: any /** TODO #9100 */) {
|
||||||
@ -33,6 +35,7 @@ export class WorkerDomAdapter extends DomAdapter {
|
|||||||
console.group(error);
|
console.group(error);
|
||||||
this.logError(error);
|
this.logError(error);
|
||||||
} else {
|
} else {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ import {EmptyError} from 'rxjs/util/EmptyError';
|
|||||||
|
|
||||||
import {Route, Routes, UrlMatchResult} from './config';
|
import {Route, Routes, UrlMatchResult} from './config';
|
||||||
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
import {LoadedRouterConfig, RouterConfigLoader} from './router_config_loader';
|
||||||
import {NavigationCancelingError, PRIMARY_OUTLET, defaultUrlMatcher} from './shared';
|
import {NavigationCancelingError, PRIMARY_OUTLET, Params, defaultUrlMatcher} from './shared';
|
||||||
import {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
|
import {UrlSegment, UrlSegmentGroup, UrlSerializer, UrlTree} from './url_tree';
|
||||||
import {andObservables, forEach, merge, waitForMap, wrapIntoObservable} from './utils/collection';
|
import {andObservables, forEach, merge, waitForMap, wrapIntoObservable} from './utils/collection';
|
||||||
|
|
||||||
class NoMatch {
|
class NoMatch {
|
||||||
@ -29,7 +29,7 @@ class NoMatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AbsoluteRedirect {
|
class AbsoluteRedirect {
|
||||||
constructor(public segments: UrlSegment[]) {}
|
constructor(public urlTree: UrlTree) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function noMatch(segmentGroup: UrlSegmentGroup): Observable<UrlSegmentGroup> {
|
function noMatch(segmentGroup: UrlSegmentGroup): Observable<UrlSegmentGroup> {
|
||||||
@ -37,9 +37,15 @@ function noMatch(segmentGroup: UrlSegmentGroup): Observable<UrlSegmentGroup> {
|
|||||||
(obs: Observer<UrlSegmentGroup>) => obs.error(new NoMatch(segmentGroup)));
|
(obs: Observer<UrlSegmentGroup>) => obs.error(new NoMatch(segmentGroup)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function absoluteRedirect(segments: UrlSegment[]): Observable<UrlSegmentGroup> {
|
function absoluteRedirect(newTree: UrlTree): Observable<any> {
|
||||||
return new Observable<UrlSegmentGroup>(
|
return new Observable<UrlSegmentGroup>(
|
||||||
(obs: Observer<UrlSegmentGroup>) => obs.error(new AbsoluteRedirect(segments)));
|
(obs: Observer<UrlSegmentGroup>) => obs.error(new AbsoluteRedirect(newTree)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function namedOutletsRedirect(redirectTo: string): Observable<any> {
|
||||||
|
return new Observable<UrlSegmentGroup>(
|
||||||
|
(obs: Observer<UrlSegmentGroup>) => obs.error(new Error(
|
||||||
|
`Only absolute redirects can have named outlets. redirectTo: '${redirectTo}'`)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function canLoadFails(route: Route): Observable<LoadedRouterConfig> {
|
function canLoadFails(route: Route): Observable<LoadedRouterConfig> {
|
||||||
@ -50,9 +56,9 @@ function canLoadFails(route: Route): Observable<LoadedRouterConfig> {
|
|||||||
|
|
||||||
|
|
||||||
export function applyRedirects(
|
export function applyRedirects(
|
||||||
injector: Injector, configLoader: RouterConfigLoader, urlTree: UrlTree,
|
injector: Injector, configLoader: RouterConfigLoader, urlSerializer: UrlSerializer,
|
||||||
config: Routes): Observable<UrlTree> {
|
urlTree: UrlTree, config: Routes): Observable<UrlTree> {
|
||||||
return new ApplyRedirects(injector, configLoader, urlTree, config).apply();
|
return new ApplyRedirects(injector, configLoader, urlSerializer, urlTree, config).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApplyRedirects {
|
class ApplyRedirects {
|
||||||
@ -60,21 +66,20 @@ class ApplyRedirects {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private injector: Injector, private configLoader: RouterConfigLoader,
|
private injector: Injector, private configLoader: RouterConfigLoader,
|
||||||
private urlTree: UrlTree, private config: Routes) {}
|
private urlSerializer: UrlSerializer, private urlTree: UrlTree, private config: Routes) {}
|
||||||
|
|
||||||
apply(): Observable<UrlTree> {
|
apply(): Observable<UrlTree> {
|
||||||
const expanded$ =
|
const expanded$ =
|
||||||
this.expandSegmentGroup(this.injector, this.config, this.urlTree.root, PRIMARY_OUTLET);
|
this.expandSegmentGroup(this.injector, this.config, this.urlTree.root, PRIMARY_OUTLET);
|
||||||
const urlTrees$ = map.call(
|
const urlTrees$ = map.call(
|
||||||
expanded$, (rootSegmentGroup: UrlSegmentGroup) => this.createUrlTree(rootSegmentGroup));
|
expanded$, (rootSegmentGroup: UrlSegmentGroup) => this.createUrlTree(
|
||||||
|
rootSegmentGroup, this.urlTree.queryParams, this.urlTree.fragment));
|
||||||
return _catch.call(urlTrees$, (e: any) => {
|
return _catch.call(urlTrees$, (e: any) => {
|
||||||
if (e instanceof AbsoluteRedirect) {
|
if (e instanceof AbsoluteRedirect) {
|
||||||
// after an absolute redirect we do not apply any more redirects!
|
// after an absolute redirect we do not apply any more redirects!
|
||||||
this.allowRedirects = false;
|
this.allowRedirects = false;
|
||||||
const group =
|
|
||||||
new UrlSegmentGroup([], {[PRIMARY_OUTLET]: new UrlSegmentGroup(e.segments, {})});
|
|
||||||
// we need to run matching, so we can fetch all lazy-loaded modules
|
// we need to run matching, so we can fetch all lazy-loaded modules
|
||||||
return this.match(group);
|
return this.match(e.urlTree);
|
||||||
} else if (e instanceof NoMatch) {
|
} else if (e instanceof NoMatch) {
|
||||||
throw this.noMatchError(e);
|
throw this.noMatchError(e);
|
||||||
} else {
|
} else {
|
||||||
@ -83,11 +88,12 @@ class ApplyRedirects {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private match(segmentGroup: UrlSegmentGroup): Observable<UrlTree> {
|
private match(tree: UrlTree): Observable<UrlTree> {
|
||||||
const expanded$ =
|
const expanded$ =
|
||||||
this.expandSegmentGroup(this.injector, this.config, segmentGroup, PRIMARY_OUTLET);
|
this.expandSegmentGroup(this.injector, this.config, tree.root, PRIMARY_OUTLET);
|
||||||
const mapped$ = map.call(
|
const mapped$ = map.call(
|
||||||
expanded$, (rootSegmentGroup: UrlSegmentGroup) => this.createUrlTree(rootSegmentGroup));
|
expanded$, (rootSegmentGroup: UrlSegmentGroup) =>
|
||||||
|
this.createUrlTree(rootSegmentGroup, tree.queryParams, tree.fragment));
|
||||||
return _catch.call(mapped$, (e: any): Observable<UrlTree> => {
|
return _catch.call(mapped$, (e: any): Observable<UrlTree> => {
|
||||||
if (e instanceof NoMatch) {
|
if (e instanceof NoMatch) {
|
||||||
throw this.noMatchError(e);
|
throw this.noMatchError(e);
|
||||||
@ -101,11 +107,12 @@ class ApplyRedirects {
|
|||||||
return new Error(`Cannot match any routes. URL Segment: '${e.segmentGroup}'`);
|
return new Error(`Cannot match any routes. URL Segment: '${e.segmentGroup}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createUrlTree(rootCandidate: UrlSegmentGroup): UrlTree {
|
private createUrlTree(rootCandidate: UrlSegmentGroup, queryParams: Params, fragment: string):
|
||||||
|
UrlTree {
|
||||||
const root = rootCandidate.segments.length > 0 ?
|
const root = rootCandidate.segments.length > 0 ?
|
||||||
new UrlSegmentGroup([], {[PRIMARY_OUTLET]: rootCandidate}) :
|
new UrlSegmentGroup([], {[PRIMARY_OUTLET]: rootCandidate}) :
|
||||||
rootCandidate;
|
rootCandidate;
|
||||||
return new UrlTree(root, this.urlTree.queryParams, this.urlTree.fragment);
|
return new UrlTree(root, queryParams, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private expandSegmentGroup(
|
private expandSegmentGroup(
|
||||||
@ -191,12 +198,14 @@ class ApplyRedirects {
|
|||||||
private expandWildCardWithParamsAgainstRouteUsingRedirect(
|
private expandWildCardWithParamsAgainstRouteUsingRedirect(
|
||||||
injector: Injector, routes: Route[], route: Route,
|
injector: Injector, routes: Route[], route: Route,
|
||||||
outlet: string): Observable<UrlSegmentGroup> {
|
outlet: string): Observable<UrlSegmentGroup> {
|
||||||
const newSegments = applyRedirectCommands([], route.redirectTo, {});
|
const newTree = this.applyRedirectCommands([], route.redirectTo, {});
|
||||||
if (route.redirectTo.startsWith('/')) {
|
if (route.redirectTo.startsWith('/')) {
|
||||||
return absoluteRedirect(newSegments);
|
return absoluteRedirect(newTree);
|
||||||
} else {
|
} else {
|
||||||
const group = new UrlSegmentGroup(newSegments, {});
|
return mergeMap.call(this.lineralizeSegments(route, newTree), (newSegments: UrlSegment[]) => {
|
||||||
return this.expandSegment(injector, group, routes, newSegments, outlet, false);
|
const group = new UrlSegmentGroup(newSegments, {});
|
||||||
|
return this.expandSegment(injector, group, routes, newSegments, outlet, false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,14 +216,16 @@ class ApplyRedirects {
|
|||||||
match(segmentGroup, route, segments);
|
match(segmentGroup, route, segments);
|
||||||
if (!matched) return noMatch(segmentGroup);
|
if (!matched) return noMatch(segmentGroup);
|
||||||
|
|
||||||
const newSegments =
|
const newTree = this.applyRedirectCommands(
|
||||||
applyRedirectCommands(consumedSegments, route.redirectTo, <any>positionalParamSegments);
|
consumedSegments, route.redirectTo, <any>positionalParamSegments);
|
||||||
if (route.redirectTo.startsWith('/')) {
|
if (route.redirectTo.startsWith('/')) {
|
||||||
return absoluteRedirect(newSegments);
|
return absoluteRedirect(newTree);
|
||||||
} else {
|
} else {
|
||||||
return this.expandSegment(
|
return mergeMap.call(this.lineralizeSegments(route, newTree), (newSegments: UrlSegment[]) => {
|
||||||
injector, segmentGroup, routes, newSegments.concat(segments.slice(lastChild)), outlet,
|
return this.expandSegment(
|
||||||
false);
|
injector, segmentGroup, routes, newSegments.concat(segments.slice(lastChild)), outlet,
|
||||||
|
false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,6 +295,92 @@ class ApplyRedirects {
|
|||||||
return of (new LoadedRouterConfig([], injector, null, null));
|
return of (new LoadedRouterConfig([], injector, null, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lineralizeSegments(route: Route, urlTree: UrlTree): Observable<UrlSegment[]> {
|
||||||
|
let res: UrlSegment[] = [];
|
||||||
|
let c = urlTree.root;
|
||||||
|
while (true) {
|
||||||
|
res = res.concat(c.segments);
|
||||||
|
if (c.numberOfChildren === 0) {
|
||||||
|
return of (res);
|
||||||
|
} else if (c.numberOfChildren > 1 || !c.children[PRIMARY_OUTLET]) {
|
||||||
|
return namedOutletsRedirect(route.redirectTo);
|
||||||
|
} else {
|
||||||
|
c = c.children[PRIMARY_OUTLET];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyRedirectCommands(
|
||||||
|
segments: UrlSegment[], redirectTo: string, posParams: {[k: string]: UrlSegment}): UrlTree {
|
||||||
|
const t = this.urlSerializer.parse(redirectTo);
|
||||||
|
return this.applyRedirectCreatreUrlTree(
|
||||||
|
redirectTo, this.urlSerializer.parse(redirectTo), segments, posParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyRedirectCreatreUrlTree(
|
||||||
|
redirectTo: string, urlTree: UrlTree, segments: UrlSegment[],
|
||||||
|
posParams: {[k: string]: UrlSegment}): UrlTree {
|
||||||
|
const newRoot = this.createSegmentGroup(redirectTo, urlTree.root, segments, posParams);
|
||||||
|
return new UrlTree(
|
||||||
|
newRoot, this.createQueryParams(urlTree.queryParams, this.urlTree.queryParams),
|
||||||
|
urlTree.fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createQueryParams(redirectToParams: Params, actualParams: Params): Params {
|
||||||
|
const res: Params = {};
|
||||||
|
forEach(redirectToParams, (v: any, k: string) => {
|
||||||
|
if (v.startsWith(':')) {
|
||||||
|
res[k] = actualParams[v.substring(1)];
|
||||||
|
} else {
|
||||||
|
res[k] = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSegmentGroup(
|
||||||
|
redirectTo: string, group: UrlSegmentGroup, segments: UrlSegment[],
|
||||||
|
posParams: {[k: string]: UrlSegment}): UrlSegmentGroup {
|
||||||
|
const updatedSegments = this.createSegments(redirectTo, group.segments, segments, posParams);
|
||||||
|
|
||||||
|
let children: {[n: string]: UrlSegmentGroup} = {};
|
||||||
|
forEach(group.children, (child: UrlSegmentGroup, name: string) => {
|
||||||
|
children[name] = this.createSegmentGroup(redirectTo, child, segments, posParams);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new UrlSegmentGroup(updatedSegments, children);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createSegments(
|
||||||
|
redirectTo: string, redirectToSegments: UrlSegment[], actualSegments: UrlSegment[],
|
||||||
|
posParams: {[k: string]: UrlSegment}): UrlSegment[] {
|
||||||
|
return redirectToSegments.map(
|
||||||
|
s => s.path.startsWith(':') ? this.findPosParam(redirectTo, s, posParams) :
|
||||||
|
this.findOrReturn(s, actualSegments));
|
||||||
|
}
|
||||||
|
|
||||||
|
private findPosParam(
|
||||||
|
redirectTo: string, redirectToUrlSegment: UrlSegment,
|
||||||
|
posParams: {[k: string]: UrlSegment}): UrlSegment {
|
||||||
|
const pos = posParams[redirectToUrlSegment.path.substring(1)];
|
||||||
|
if (!pos)
|
||||||
|
throw new Error(
|
||||||
|
`Cannot redirect to '${redirectTo}'. Cannot find '${redirectToUrlSegment.path}'.`);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private findOrReturn(redirectToUrlSegment: UrlSegment, actualSegments: UrlSegment[]): UrlSegment {
|
||||||
|
let idx = 0;
|
||||||
|
for (const s of actualSegments) {
|
||||||
|
if (s.path === redirectToUrlSegment.path) {
|
||||||
|
actualSegments.splice(idx);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
return redirectToUrlSegment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runGuards(injector: Injector, route: Route): Observable<boolean> {
|
function runGuards(injector: Injector, route: Route): Observable<boolean> {
|
||||||
@ -328,46 +425,6 @@ function match(segmentGroup: UrlSegmentGroup, route: Route, segments: UrlSegment
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyRedirectCommands(
|
|
||||||
segments: UrlSegment[], redirectTo: string,
|
|
||||||
posParams: {[k: string]: UrlSegment}): UrlSegment[] {
|
|
||||||
const r = redirectTo.startsWith('/') ? redirectTo.substring(1) : redirectTo;
|
|
||||||
if (r === '') {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
return createSegments(redirectTo, r.split('/'), segments, posParams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSegments(
|
|
||||||
redirectTo: string, parts: string[], segments: UrlSegment[],
|
|
||||||
posParams: {[k: string]: UrlSegment}): UrlSegment[] {
|
|
||||||
return parts.map(
|
|
||||||
p => p.startsWith(':') ? findPosParam(p, posParams, redirectTo) :
|
|
||||||
findOrCreateSegment(p, segments));
|
|
||||||
}
|
|
||||||
|
|
||||||
function findPosParam(
|
|
||||||
part: string, posParams: {[k: string]: UrlSegment}, redirectTo: string): UrlSegment {
|
|
||||||
const paramName = part.substring(1);
|
|
||||||
const pos = posParams[paramName];
|
|
||||||
if (!pos) throw new Error(`Cannot redirect to '${redirectTo}'. Cannot find '${part}'.`);
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findOrCreateSegment(part: string, segments: UrlSegment[]): UrlSegment {
|
|
||||||
let idx = 0;
|
|
||||||
for (const s of segments) {
|
|
||||||
if (s.path === part) {
|
|
||||||
segments.splice(idx);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
return new UrlSegment(part, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function split(
|
function split(
|
||||||
segmentGroup: UrlSegmentGroup, consumedSegments: UrlSegment[], slicedSegments: UrlSegment[],
|
segmentGroup: UrlSegmentGroup, consumedSegments: UrlSegment[], slicedSegments: UrlSegment[],
|
||||||
config: Route[]) {
|
config: Route[]) {
|
||||||
|
@ -650,7 +650,7 @@ export class Router {
|
|||||||
let urlAndSnapshot$: Observable<{appliedUrl: UrlTree, snapshot: RouterStateSnapshot}>;
|
let urlAndSnapshot$: Observable<{appliedUrl: UrlTree, snapshot: RouterStateSnapshot}>;
|
||||||
if (!precreatedState) {
|
if (!precreatedState) {
|
||||||
const redirectsApplied$ =
|
const redirectsApplied$ =
|
||||||
applyRedirects(this.injector, this.configLoader, url, this.config);
|
applyRedirects(this.injector, this.configLoader, this.urlSerializer, url, this.config);
|
||||||
|
|
||||||
urlAndSnapshot$ = mergeMap.call(redirectsApplied$, (appliedUrl: UrlTree) => {
|
urlAndSnapshot$ = mergeMap.call(redirectsApplied$, (appliedUrl: UrlTree) => {
|
||||||
return map.call(
|
return map.call(
|
||||||
|
@ -15,6 +15,7 @@ import {LoadedRouterConfig} from '../src/router_config_loader';
|
|||||||
import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree, equalSegments} from '../src/url_tree';
|
import {DefaultUrlSerializer, UrlSegmentGroup, UrlTree, equalSegments} from '../src/url_tree';
|
||||||
|
|
||||||
describe('applyRedirects', () => {
|
describe('applyRedirects', () => {
|
||||||
|
const serializer = new DefaultUrlSerializer();
|
||||||
|
|
||||||
it('should return the same url tree when no redirects', () => {
|
it('should return the same url tree when no redirects', () => {
|
||||||
checkRedirect(
|
checkRedirect(
|
||||||
@ -38,7 +39,7 @@ describe('applyRedirects', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when cannot handle a positional parameter', () => {
|
it('should throw when cannot handle a positional parameter', () => {
|
||||||
applyRedirects(null, null, tree('/a/1'), [
|
applyRedirects(null, null, serializer, tree('/a/1'), [
|
||||||
{path: 'a/:id', redirectTo: 'a/:other'}
|
{path: 'a/:id', redirectTo: 'a/:other'}
|
||||||
]).subscribe(() => {}, (e) => {
|
]).subscribe(() => {}, (e) => {
|
||||||
expect(e.message).toEqual('Cannot redirect to \'a/:other\'. Cannot find \':other\'.');
|
expect(e.message).toEqual('Cannot redirect to \'a/:other\'. Cannot find \':other\'.');
|
||||||
@ -133,11 +134,11 @@ describe('applyRedirects', () => {
|
|||||||
{
|
{
|
||||||
path: 'a',
|
path: 'a',
|
||||||
component: ComponentA,
|
component: ComponentA,
|
||||||
children: [{path: 'b/:id', redirectTo: '/absolute/:id'}]
|
children: [{path: 'b/:id', redirectTo: '/absolute/:id?a=1&b=:b#f1'}]
|
||||||
},
|
},
|
||||||
{path: '**', component: ComponentC}
|
{path: '**', component: ComponentC}
|
||||||
],
|
],
|
||||||
'/a/b/1', (t: UrlTree) => { compareTrees(t, tree('/absolute/1')); });
|
'/a/b/1?b=2', (t: UrlTree) => { compareTrees(t, tree('/absolute/1?a=1&b=2#f1')); });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('lazy loading', () => {
|
describe('lazy loading', () => {
|
||||||
@ -153,10 +154,11 @@ describe('applyRedirects', () => {
|
|||||||
};
|
};
|
||||||
const config = [{path: 'a', component: ComponentA, loadChildren: 'children'}];
|
const config = [{path: 'a', component: ComponentA, loadChildren: 'children'}];
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree('a/b'), config).forEach(r => {
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree('a/b'), config)
|
||||||
compareTrees(r, tree('/a/b'));
|
.forEach(r => {
|
||||||
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
compareTrees(r, tree('/a/b'));
|
||||||
});
|
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle the case when the loader errors', () => {
|
it('should handle the case when the loader errors', () => {
|
||||||
@ -165,9 +167,8 @@ describe('applyRedirects', () => {
|
|||||||
};
|
};
|
||||||
const config = [{path: 'a', component: ComponentA, loadChildren: 'children'}];
|
const config = [{path: 'a', component: ComponentA, loadChildren: 'children'}];
|
||||||
|
|
||||||
applyRedirects(null, <any>loader, tree('a/b'), config).subscribe(() => {}, (e) => {
|
applyRedirects(null, <any>loader, serializer, tree('a/b'), config)
|
||||||
expect(e.message).toEqual('Loading Error');
|
.subscribe(() => {}, (e) => { expect(e.message).toEqual('Loading Error'); });
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load when all canLoad guards return true', () => {
|
it('should load when all canLoad guards return true', () => {
|
||||||
@ -186,7 +187,7 @@ describe('applyRedirects', () => {
|
|||||||
loadChildren: 'children'
|
loadChildren: 'children'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
applyRedirects(<any>injector, <any>loader, tree('a/b'), config).forEach(r => {
|
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config).forEach(r => {
|
||||||
compareTrees(r, tree('/a/b'));
|
compareTrees(r, tree('/a/b'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -208,7 +209,7 @@ describe('applyRedirects', () => {
|
|||||||
loadChildren: 'children'
|
loadChildren: 'children'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
applyRedirects(<any>injector, <any>loader, tree('a/b'), config)
|
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => { throw 'Should not reach'; },
|
() => { throw 'Should not reach'; },
|
||||||
(e) => {
|
(e) => {
|
||||||
@ -234,7 +235,7 @@ describe('applyRedirects', () => {
|
|||||||
loadChildren: 'children'
|
loadChildren: 'children'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
applyRedirects(<any>injector, <any>loader, tree('a/b'), config)
|
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
() => { throw 'Should not reach'; }, (e) => { expect(e).toEqual('someError'); });
|
() => { throw 'Should not reach'; }, (e) => { expect(e).toEqual('someError'); });
|
||||||
});
|
});
|
||||||
@ -251,7 +252,7 @@ describe('applyRedirects', () => {
|
|||||||
const config =
|
const config =
|
||||||
[{path: 'a', component: ComponentA, canLoad: ['guard'], loadChildren: 'children'}];
|
[{path: 'a', component: ComponentA, canLoad: ['guard'], loadChildren: 'children'}];
|
||||||
|
|
||||||
applyRedirects(<any>injector, <any>loader, tree('a/b'), config)
|
applyRedirects(<any>injector, <any>loader, serializer, tree('a/b'), config)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(r) => { compareTrees(r, tree('/a/b')); }, (e) => { throw 'Should not reach'; });
|
(r) => { compareTrees(r, tree('/a/b')); }, (e) => { throw 'Should not reach'; });
|
||||||
|
|
||||||
@ -267,10 +268,11 @@ describe('applyRedirects', () => {
|
|||||||
const config =
|
const config =
|
||||||
[{path: '', pathMatch: 'full', redirectTo: '/a'}, {path: 'a', loadChildren: 'children'}];
|
[{path: '', pathMatch: 'full', redirectTo: '/a'}, {path: 'a', loadChildren: 'children'}];
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree(''), config).forEach(r => {
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree(''), config)
|
||||||
compareTrees(r, tree('a'));
|
.forEach(r => {
|
||||||
expect((<any>config[1])._loadedConfig).toBe(loadedConfig);
|
compareTrees(r, tree('a'));
|
||||||
});
|
expect((<any>config[1])._loadedConfig).toBe(loadedConfig);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the configuration only once', () => {
|
it('should load the configuration only once', () => {
|
||||||
@ -289,12 +291,13 @@ describe('applyRedirects', () => {
|
|||||||
|
|
||||||
const config = [{path: 'a', loadChildren: 'children'}];
|
const config = [{path: 'a', loadChildren: 'children'}];
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree('a?k1'), config).subscribe(r => {});
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree('a?k1'), config)
|
||||||
|
.subscribe(r => {});
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree('a?k2'), config)
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree('a?k2'), config)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
r => {
|
r => {
|
||||||
compareTrees(r, tree('a'));
|
compareTrees(r, tree('a?k2'));
|
||||||
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
||||||
},
|
},
|
||||||
(e) => { throw 'Should not reach'; });
|
(e) => { throw 'Should not reach'; });
|
||||||
@ -309,9 +312,8 @@ describe('applyRedirects', () => {
|
|||||||
|
|
||||||
const config = [{path: '**', loadChildren: 'children'}];
|
const config = [{path: '**', loadChildren: 'children'}];
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree('xyz'), config).forEach(r => {
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree('xyz'), config)
|
||||||
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
.forEach(r => { expect((<any>config[0])._loadedConfig).toBe(loadedConfig); });
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the configuration after a local redirect from a wildcard route', () => {
|
it('should load the configuration after a local redirect from a wildcard route', () => {
|
||||||
@ -324,9 +326,8 @@ describe('applyRedirects', () => {
|
|||||||
const config =
|
const config =
|
||||||
[{path: 'not-found', loadChildren: 'children'}, {path: '**', redirectTo: 'not-found'}];
|
[{path: 'not-found', loadChildren: 'children'}, {path: '**', redirectTo: 'not-found'}];
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree('xyz'), config).forEach(r => {
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree('xyz'), config)
|
||||||
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
.forEach(r => { expect((<any>config[0])._loadedConfig).toBe(loadedConfig); });
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should load the configuration after an absolute redirect from a wildcard route', () => {
|
it('should load the configuration after an absolute redirect from a wildcard route', () => {
|
||||||
@ -339,9 +340,8 @@ describe('applyRedirects', () => {
|
|||||||
const config =
|
const config =
|
||||||
[{path: 'not-found', loadChildren: 'children'}, {path: '**', redirectTo: '/not-found'}];
|
[{path: 'not-found', loadChildren: 'children'}, {path: '**', redirectTo: '/not-found'}];
|
||||||
|
|
||||||
applyRedirects(<any>'providedInjector', <any>loader, tree('xyz'), config).forEach(r => {
|
applyRedirects(<any>'providedInjector', <any>loader, serializer, tree('xyz'), config)
|
||||||
expect((<any>config[0])._loadedConfig).toBe(loadedConfig);
|
.forEach(r => { expect((<any>config[0])._loadedConfig).toBe(loadedConfig); });
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -388,7 +388,7 @@ describe('applyRedirects', () => {
|
|||||||
{path: '', redirectTo: 'a', pathMatch: 'full'}
|
{path: '', redirectTo: 'a', pathMatch: 'full'}
|
||||||
];
|
];
|
||||||
|
|
||||||
applyRedirects(null, null, tree('b'), config)
|
applyRedirects(null, null, serializer, tree('b'), config)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(_) => { throw 'Should not be reached'; },
|
(_) => { throw 'Should not be reached'; },
|
||||||
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'b\''); });
|
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'b\''); });
|
||||||
@ -518,7 +518,7 @@ describe('applyRedirects', () => {
|
|||||||
]
|
]
|
||||||
}];
|
}];
|
||||||
|
|
||||||
applyRedirects(null, null, tree('a/(d//aux:e)'), config)
|
applyRedirects(null, null, serializer, tree('a/(d//aux:e)'), config)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(_) => { throw 'Should not be reached'; },
|
(_) => { throw 'Should not be reached'; },
|
||||||
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'a\''); });
|
e => { expect(e.message).toEqual('Cannot match any routes. URL Segment: \'a\''); });
|
||||||
@ -549,7 +549,7 @@ describe('applyRedirects', () => {
|
|||||||
|
|
||||||
it('should error when no children matching and some url is left', () => {
|
it('should error when no children matching and some url is left', () => {
|
||||||
applyRedirects(
|
applyRedirects(
|
||||||
null, null, tree('/a/c'),
|
null, null, serializer, tree('/a/c'),
|
||||||
[{path: 'a', component: ComponentA, children: [{path: 'b', component: ComponentB}]}])
|
[{path: 'a', component: ComponentA, children: [{path: 'b', component: ComponentB}]}])
|
||||||
.subscribe(
|
.subscribe(
|
||||||
(_) => { throw 'Should not be reached'; },
|
(_) => { throw 'Should not be reached'; },
|
||||||
@ -576,10 +576,46 @@ describe('applyRedirects', () => {
|
|||||||
'/a/1/b', (t: UrlTree) => { compareTrees(t, tree('a/1/b')); });
|
'/a/1/b', (t: UrlTree) => { compareTrees(t, tree('a/1/b')); });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('redirecting to named outlets', () => {
|
||||||
|
it('should work when using absolute redirects', () => {
|
||||||
|
checkRedirect(
|
||||||
|
[
|
||||||
|
{path: 'a/:id', redirectTo: '/b/:id(aux:c/:id)'},
|
||||||
|
{path: 'b/:id', component: ComponentB},
|
||||||
|
{path: 'c/:id', component: ComponentC, outlet: 'aux'}
|
||||||
|
],
|
||||||
|
'a/1;p=99', (t: UrlTree) => { compareTrees(t, tree('/b/1;p=99(aux:c/1;p=99)')); });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when using absolute redirects (wildcard)', () => {
|
||||||
|
checkRedirect(
|
||||||
|
[
|
||||||
|
{path: '**', redirectTo: '/b(aux:c)'}, {path: 'b', component: ComponentB},
|
||||||
|
{path: 'c', component: ComponentC, outlet: 'aux'}
|
||||||
|
],
|
||||||
|
'a/1', (t: UrlTree) => { compareTrees(t, tree('/b(aux:c)')); });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw when using non-absolute redirects', () => {
|
||||||
|
applyRedirects(
|
||||||
|
null, null, serializer, tree('a'),
|
||||||
|
[
|
||||||
|
{path: 'a', redirectTo: 'b(aux:c)'},
|
||||||
|
])
|
||||||
|
.subscribe(
|
||||||
|
() => { throw new Error('should not be reached'); },
|
||||||
|
(e) => {
|
||||||
|
expect(e.message).toEqual(
|
||||||
|
'Only absolute redirects can have named outlets. redirectTo: \'b(aux:c)\'');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function checkRedirect(config: Routes, url: string, callback: any): void {
|
function checkRedirect(config: Routes, url: string, callback: any): void {
|
||||||
applyRedirects(null, null, tree(url), config).subscribe(callback, e => { throw e; });
|
applyRedirects(null, null, new DefaultUrlSerializer(), tree(url), config)
|
||||||
|
.subscribe(callback, e => { throw e; });
|
||||||
}
|
}
|
||||||
|
|
||||||
function tree(url: string): UrlTree {
|
function tree(url: string): UrlTree {
|
||||||
@ -591,6 +627,8 @@ function compareTrees(actual: UrlTree, expected: UrlTree): void {
|
|||||||
const error =
|
const error =
|
||||||
`"${serializer.serialize(actual)}" is not equal to "${serializer.serialize(expected)}"`;
|
`"${serializer.serialize(actual)}" is not equal to "${serializer.serialize(expected)}"`;
|
||||||
compareSegments(actual.root, expected.root, error);
|
compareSegments(actual.root, expected.root, error);
|
||||||
|
expect(actual.queryParams).toEqual(expected.queryParams);
|
||||||
|
expect(actual.fragment).toEqual(expected.fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareSegments(actual: UrlSegmentGroup, expected: UrlSegmentGroup, error: string): void {
|
function compareSegments(actual: UrlSegmentGroup, expected: UrlSegmentGroup, error: string): void {
|
||||||
|
@ -166,16 +166,14 @@ export class UpgradeModule {
|
|||||||
(testabilityDelegate: angular.ITestabilityService) => {
|
(testabilityDelegate: angular.ITestabilityService) => {
|
||||||
const originalWhenStable: Function = testabilityDelegate.whenStable;
|
const originalWhenStable: Function = testabilityDelegate.whenStable;
|
||||||
const injector = this.injector;
|
const injector = this.injector;
|
||||||
// Cannot use arrow function below because we need to grab the context
|
// Cannot use arrow function below because we need the context
|
||||||
const newWhenStable = function(callback: Function) {
|
const newWhenStable = function(callback: Function) {
|
||||||
const whenStableContext: any = this;
|
|
||||||
originalWhenStable.call(this, function() {
|
originalWhenStable.call(this, function() {
|
||||||
const ng2Testability: Testability = injector.get(Testability);
|
const ng2Testability: Testability = injector.get(Testability);
|
||||||
if (ng2Testability.isStable()) {
|
if (ng2Testability.isStable()) {
|
||||||
callback.apply(this, arguments);
|
callback.apply(this, arguments);
|
||||||
} else {
|
} else {
|
||||||
ng2Testability.whenStable(
|
ng2Testability.whenStable(newWhenStable.bind(this, callback));
|
||||||
newWhenStable.bind(whenStableContext, callback));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -355,14 +355,14 @@ export class UpgradeAdapter {
|
|||||||
function(testabilityDelegate: angular.ITestabilityService) {
|
function(testabilityDelegate: angular.ITestabilityService) {
|
||||||
|
|
||||||
const originalWhenStable: Function = testabilityDelegate.whenStable;
|
const originalWhenStable: Function = testabilityDelegate.whenStable;
|
||||||
const newWhenStable = (callback: Function): void => {
|
// Cannot use arrow function below because we need the context
|
||||||
const whenStableContext: any = this;
|
const newWhenStable = function(callback: Function) {
|
||||||
originalWhenStable.call(this, function() {
|
originalWhenStable.call(this, function() {
|
||||||
const ng2Testability: Testability = moduleRef.injector.get(Testability);
|
const ng2Testability: Testability = moduleRef.injector.get(Testability);
|
||||||
if (ng2Testability.isStable()) {
|
if (ng2Testability.isStable()) {
|
||||||
callback.apply(this, arguments);
|
callback.apply(this, arguments);
|
||||||
} else {
|
} else {
|
||||||
ng2Testability.whenStable(newWhenStable.bind(whenStableContext, callback));
|
ng2Testability.whenStable(newWhenStable.bind(this, callback));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -433,8 +433,9 @@ export class UpgradeAdapter {
|
|||||||
if (windowAngular.resumeBootstrap) {
|
if (windowAngular.resumeBootstrap) {
|
||||||
const originalResumeBootstrap: () => void = windowAngular.resumeBootstrap;
|
const originalResumeBootstrap: () => void = windowAngular.resumeBootstrap;
|
||||||
windowAngular.resumeBootstrap = function() {
|
windowAngular.resumeBootstrap = function() {
|
||||||
|
let args = arguments;
|
||||||
windowAngular.resumeBootstrap = originalResumeBootstrap;
|
windowAngular.resumeBootstrap = originalResumeBootstrap;
|
||||||
windowAngular.resumeBootstrap.apply(this, arguments);
|
ngZone.run(() => { windowAngular.resumeBootstrap.apply(this, args); });
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -49,7 +49,8 @@ export class UpgradeNg1ComponentAdapterBuilder {
|
|||||||
],
|
],
|
||||||
ngOnInit: function() { /* needs to be here for ng2 to properly detect it */ },
|
ngOnInit: function() { /* needs to be here for ng2 to properly detect it */ },
|
||||||
ngOnChanges: function() { /* needs to be here for ng2 to properly detect it */ },
|
ngOnChanges: function() { /* needs to be here for ng2 to properly detect it */ },
|
||||||
ngDoCheck: function() { /* needs to be here for ng2 to properly detect it */ }
|
ngDoCheck: function() { /* needs to be here for ng2 to properly detect it */ },
|
||||||
|
ngOnDestroy: function() { /* needs to be here for ng2 to properly detect it */ },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,16 +263,18 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
for (const name in changes) {
|
const ng1Changes: any = {};
|
||||||
if ((<Object>changes).hasOwnProperty(name)) {
|
Object.keys(changes).forEach(name => {
|
||||||
const change: SimpleChange = changes[name];
|
const change: SimpleChange = changes[name];
|
||||||
this.setComponentProperty(name, change.currentValue);
|
this.setComponentProperty(name, change.currentValue);
|
||||||
}
|
ng1Changes[this.propertyMap[name]] = change;
|
||||||
|
});
|
||||||
|
if (this.destinationObj.$onChanges) {
|
||||||
|
this.destinationObj.$onChanges(ng1Changes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngDoCheck(): number {
|
ngDoCheck() {
|
||||||
const count = 0;
|
|
||||||
const destinationObj = this.destinationObj;
|
const destinationObj = this.destinationObj;
|
||||||
const lastValues = this.checkLastValues;
|
const lastValues = this.checkLastValues;
|
||||||
const checkProperties = this.checkProperties;
|
const checkProperties = this.checkProperties;
|
||||||
@ -287,7 +290,15 @@ class UpgradeNg1ComponentAdapter implements OnInit, OnChanges, DoCheck {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
if (this.destinationObj.$doCheck && this.directive.controller) {
|
||||||
|
this.destinationObj.$doCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.destinationObj.$onDestroy && this.directive.controller) {
|
||||||
|
this.destinationObj.$onDestroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setComponentProperty(name: string, value: any) {
|
setComponentProperty(name: string, value: any) {
|
||||||
|
@ -15,7 +15,12 @@ export function stringify(obj: any): string {
|
|||||||
|
|
||||||
export function onError(e: any) {
|
export function onError(e: any) {
|
||||||
// TODO: (misko): We seem to not have a stack trace here!
|
// TODO: (misko): We seem to not have a stack trace here!
|
||||||
console.log(e, e.stack);
|
if (console.error) {
|
||||||
|
console.error(e, e.stack);
|
||||||
|
} else {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.log(e, e.stack);
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should throw an uncaught error', fakeAsync(() => {
|
it('should throw an uncaught error', fakeAsync(() => {
|
||||||
const resolveSpy = jasmine.createSpy('resolveSpy');
|
const resolveSpy = jasmine.createSpy('resolveSpy');
|
||||||
spyOn(console, 'log');
|
spyOn(console, 'error');
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']).ready(resolveSpy);
|
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']).ready(resolveSpy);
|
||||||
@ -50,14 +50,14 @@ export function main() {
|
|||||||
expect(resolveSpy).not.toHaveBeenCalled();
|
expect(resolveSpy).not.toHaveBeenCalled();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should properly log to the console and re-throw', fakeAsync(() => {
|
it('should output an error message to the console and re-throw', fakeAsync(() => {
|
||||||
spyOn(console, 'log');
|
spyOn(console, 'error');
|
||||||
expect(() => {
|
expect(() => {
|
||||||
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']);
|
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']);
|
||||||
flushMicrotasks();
|
flushMicrotasks();
|
||||||
}).toThrowError();
|
}).toThrowError();
|
||||||
expect(console.log).toHaveBeenCalled();
|
expect(console.error).toHaveBeenCalled();
|
||||||
expect(console.log).toHaveBeenCalledWith(jasmine.any(Error), jasmine.any(String));
|
expect(console.error).toHaveBeenCalledWith(jasmine.any(Error), jasmine.any(String));
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -922,6 +922,127 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should call $doCheck of components', async(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
const valueToFind = '$doCheck';
|
||||||
|
|
||||||
|
let spy = jasmine.createSpy('doCheck');
|
||||||
|
|
||||||
|
const ng1 = {
|
||||||
|
bindings: {},
|
||||||
|
template: '{{$ctrl.value}}',
|
||||||
|
controller: Class({
|
||||||
|
constructor: function() {},
|
||||||
|
$doCheck: function() {
|
||||||
|
this.value = valueToFind;
|
||||||
|
spy();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
|
const Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
|
||||||
|
constructor: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
expect(multiTrim(document.body.textContent)).toEqual(valueToFind);
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
|
let count = spy.calls.count();
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(spy.calls.count()).toBeGreaterThan(count);
|
||||||
|
ref.dispose();
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call $onChanges of components', async(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
const valueToFind = '$onChanges init';
|
||||||
|
const valueToChange = '$onChanges changed';
|
||||||
|
|
||||||
|
const ng1 = {
|
||||||
|
bindings: {val: '<'},
|
||||||
|
template: '{{$ctrl.value}}',
|
||||||
|
controller: Class({
|
||||||
|
constructor: function() {},
|
||||||
|
$onChanges: function(changes: any) { this.value = changes.val.currentValue; }
|
||||||
|
})
|
||||||
|
};
|
||||||
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
|
const Ng2 = Component({selector: 'ng2', template: '<ng1 [val]="val"></ng1>'}).Class({
|
||||||
|
constructor: function() { this.val = valueToFind; },
|
||||||
|
ngOnInit: function() { setTimeout(() => { this.val = valueToChange; }, 100); }
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
expect(multiTrim(document.body.textContent)).toEqual(valueToFind);
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(multiTrim(document.body.textContent)).toEqual(valueToChange);
|
||||||
|
ref.dispose();
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call $onDestroy of components', async(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
|
||||||
|
let spy = jasmine.createSpy('$onDestroy');
|
||||||
|
|
||||||
|
const ng1 = {
|
||||||
|
bindings: {},
|
||||||
|
template: '<div>ng1</div>',
|
||||||
|
controller: function($rootScope: any) { this.$onDestroy = function() { spy(); }; }
|
||||||
|
};
|
||||||
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
|
const Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
|
||||||
|
constructor: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
|
const element = html(`<div ng-if="!destroy"><ng2></ng2></div>`);
|
||||||
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
(<any>ref.ng1RootScope).destroy = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
(<any>ref.ng1RootScope).destroy = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
|
ref.dispose();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should bind input properties (<) of components', async(() => {
|
it('should bind input properties (<) of components', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const ng1Module = angular.module('ng1', []);
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
@ -24,7 +24,6 @@ describe('ng2 largetable benchmark', function() {
|
|||||||
|
|
||||||
['interpolation', 'interpolationAttr', 'interpolationFn'].forEach(function(benchmarkType) {
|
['interpolation', 'interpolationAttr', 'interpolationFn'].forEach(function(benchmarkType) {
|
||||||
it('should log the ng stats with: ' + benchmarkType, function(done) {
|
it('should log the ng stats with: ' + benchmarkType, function(done) {
|
||||||
console.log('executing for type', benchmarkType);
|
|
||||||
runClickBenchmark({
|
runClickBenchmark({
|
||||||
url: URL,
|
url: URL,
|
||||||
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
|
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
|
||||||
|
@ -7,15 +7,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, Input, NgModule} from '@angular/core';
|
import {Component, Input, NgModule} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule, DomSanitizer, SafeStyle} from '@angular/platform-browser';
|
||||||
|
|
||||||
import {TableCell, emptyTable} from '../util';
|
import {TableCell, emptyTable} from '../util';
|
||||||
|
|
||||||
|
let trustedEmptyColor: SafeStyle;
|
||||||
|
let trustedGreyColor: SafeStyle;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'largetable',
|
selector: 'largetable',
|
||||||
template: `<table><tbody>
|
template: `<table><tbody>
|
||||||
<tr *ngFor="let row of data; trackBy: trackByIndex">
|
<tr *ngFor="let row of data; trackBy: trackByIndex">
|
||||||
<td *ngFor="let cell of row; trackBy: trackByIndex" [style.backgroundColor]="cell.row % 2 ? '' : 'grey'">
|
<td *ngFor="let cell of row; trackBy: trackByIndex" [style.backgroundColor]="getColor(cell.row)">
|
||||||
{{cell.value}}
|
{{cell.value}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -26,8 +29,14 @@ export class TableComponent {
|
|||||||
data: TableCell[][] = emptyTable;
|
data: TableCell[][] = emptyTable;
|
||||||
|
|
||||||
trackByIndex(index: number, item: any) { return index; }
|
trackByIndex(index: number, item: any) { return index; }
|
||||||
|
|
||||||
|
getColor(row: number) { return row % 2 ? trustedEmptyColor : trustedGreyColor; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({imports: [BrowserModule], bootstrap: [TableComponent], declarations: [TableComponent]})
|
@NgModule({imports: [BrowserModule], bootstrap: [TableComponent], declarations: [TableComponent]})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
constructor(sanitizer: DomSanitizer) {
|
||||||
|
trustedEmptyColor = sanitizer.bypassSecurityTrustStyle('');
|
||||||
|
trustedGreyColor = sanitizer.bypassSecurityTrustStyle('grey');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,20 +7,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, NgModule} from '@angular/core';
|
import {Component, NgModule} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule, DomSanitizer, SafeStyle} from '@angular/platform-browser';
|
||||||
|
|
||||||
import {TreeNode, emptyTree} from '../util';
|
import {TreeNode, emptyTree} from '../util';
|
||||||
|
|
||||||
|
let trustedEmptyColor: SafeStyle;
|
||||||
|
let trustedGreyColor: SafeStyle;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'tree',
|
selector: 'tree',
|
||||||
inputs: ['data'],
|
inputs: ['data'],
|
||||||
template:
|
template:
|
||||||
`<span [style.backgroundColor]="data.depth % 2 ? '' : 'grey'"> {{data.value}} </span><tree *ngIf='data.right != null' [data]='data.right'></tree><tree *ngIf='data.left != null' [data]='data.left'></tree>`
|
`<span [style.backgroundColor]="bgColor"> {{data.value}} </span><tree *ngIf='data.right != null' [data]='data.right'></tree><tree *ngIf='data.left != null' [data]='data.left'></tree>`
|
||||||
})
|
})
|
||||||
export class TreeComponent {
|
export class TreeComponent {
|
||||||
data: TreeNode = emptyTree;
|
data: TreeNode = emptyTree;
|
||||||
|
get bgColor() { return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({imports: [BrowserModule], bootstrap: [TreeComponent], declarations: [TreeComponent]})
|
@NgModule({imports: [BrowserModule], bootstrap: [TreeComponent], declarations: [TreeComponent]})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
|
constructor(sanitizer: DomSanitizer) {
|
||||||
|
trustedEmptyColor = sanitizer.bypassSecurityTrustStyle('');
|
||||||
|
trustedGreyColor = sanitizer.bypassSecurityTrustStyle('grey');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, Input, NgModule} from '@angular/core';
|
import {Component, Input, NgModule} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule, DomSanitizer, SafeStyle} from '@angular/platform-browser';
|
||||||
|
|
||||||
import {TreeNode, emptyTree, maxDepth} from '../util';
|
import {TreeNode, emptyTree, maxDepth} from '../util';
|
||||||
|
|
||||||
|
let trustedEmptyColor: SafeStyle;
|
||||||
|
let trustedGreyColor: SafeStyle;
|
||||||
|
|
||||||
function createTreeComponent(level: number, isLeaf: boolean) {
|
function createTreeComponent(level: number, isLeaf: boolean) {
|
||||||
const nextTreeEl = `tree${level+1}`;
|
const nextTreeEl = `tree${level+1}`;
|
||||||
let template =
|
let template = `<span [style.backgroundColor]="bgColor"> {{data.value}} </span>`;
|
||||||
`<span [style.backgroundColor]="data.depth % 2 ? '' : 'grey'"> {{data.value}} </span>`;
|
|
||||||
if (!isLeaf) {
|
if (!isLeaf) {
|
||||||
template +=
|
template +=
|
||||||
`<${nextTreeEl} [data]='data.right'></${nextTreeEl}><${nextTreeEl} [data]='data.left'></${nextTreeEl}>`;
|
`<${nextTreeEl} [data]='data.right'></${nextTreeEl}><${nextTreeEl} [data]='data.left'></${nextTreeEl}>`;
|
||||||
@ -24,6 +26,7 @@ function createTreeComponent(level: number, isLeaf: boolean) {
|
|||||||
class TreeComponent {
|
class TreeComponent {
|
||||||
@Input()
|
@Input()
|
||||||
data: TreeNode;
|
data: TreeNode;
|
||||||
|
get bgColor() { return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return TreeComponent;
|
return TreeComponent;
|
||||||
@ -43,6 +46,10 @@ function createModule(): any {
|
|||||||
|
|
||||||
@NgModule({imports: [BrowserModule], bootstrap: [RootTreeComponent], declarations: [components]})
|
@NgModule({imports: [BrowserModule], bootstrap: [RootTreeComponent], declarations: [components]})
|
||||||
class AppModule {
|
class AppModule {
|
||||||
|
constructor(sanitizer: DomSanitizer) {
|
||||||
|
trustedEmptyColor = sanitizer.bypassSecurityTrustStyle('');
|
||||||
|
trustedGreyColor = sanitizer.bypassSecurityTrustStyle('grey');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return AppModule;
|
return AppModule;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
urlParamsToForm();
|
urlParamsToForm();
|
||||||
|
|
||||||
export function getIntParameter(name: string) {
|
export function getIntParameter(name: string) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
import {browser} from 'protractor';
|
import {browser} from 'protractor';
|
||||||
|
|
||||||
const yargs = require('yargs');
|
const yargs = require('yargs');
|
||||||
|
@ -67,7 +67,7 @@ describe('WebWorkers Animations', function() {
|
|||||||
browser.wait(protractor.until.elementLocated(by.css(selector + ' .box')), 5000)
|
browser.wait(protractor.until.elementLocated(by.css(selector + ' .box')), 5000)
|
||||||
.then(() => {}, () => {
|
.then(() => {}, () => {
|
||||||
// jasmine will timeout if this gets called too many times
|
// jasmine will timeout if this gets called too many times
|
||||||
console.log('>> unexpected timeout -> browser.refresh()');
|
console.error('>> unexpected timeout -> browser.refresh()');
|
||||||
browser.refresh();
|
browser.refresh();
|
||||||
waitForBootstrap();
|
waitForBootstrap();
|
||||||
});
|
});
|
||||||
|
@ -67,7 +67,7 @@ describe('WebWorkers Input', function() {
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
// jasmine will timeout if this gets called too many times
|
// jasmine will timeout if this gets called too many times
|
||||||
console.log('>> unexpected timeout -> browser.refresh()');
|
console.error('>> unexpected timeout -> browser.refresh()');
|
||||||
browser.refresh();
|
browser.refresh();
|
||||||
waitForBootstrap();
|
waitForBootstrap();
|
||||||
});
|
});
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
import {Component, Host, NgModule} from '@angular/core';
|
import {Component, Host, NgModule} from '@angular/core';
|
||||||
import {AbstractControl, FormBuilder, FormGroup, FormGroupDirective, ReactiveFormsModule, Validators} from '@angular/forms';
|
import {AbstractControl, FormBuilder, FormGroup, FormGroupDirective, ReactiveFormsModule, Validators} from '@angular/forms';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
|
|
||||||
import {Component, Directive, Host, NgModule} from '@angular/core';
|
import {Component, Directive, Host, NgModule} from '@angular/core';
|
||||||
import {FormControl, FormGroup, FormsModule, NG_VALIDATORS, NgForm} from '@angular/forms';
|
import {FormControl, FormGroup, FormsModule, NG_VALIDATORS, NgForm} from '@angular/forms';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "2.2.1",
|
"version": "2.2.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"branchPattern": "2.0.*",
|
"branchPattern": "2.0.*",
|
||||||
"description": "Angular 2 - a web framework for modern web apps",
|
"description": "Angular 2 - a web framework for modern web apps",
|
||||||
|
@ -28,6 +28,7 @@ export interface CompilerInterface {
|
|||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
|
|
||||||
function debug(msg: string, ...o: any[]) {
|
function debug(msg: string, ...o: any[]) {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
if (DEBUG) console.log(msg, ...o);
|
if (DEBUG) console.log(msg, ...o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
import {spawn} from 'child_process';
|
import {spawn} from 'child_process';
|
||||||
import {existsSync, mkdirSync, writeFileSync} from 'fs';
|
import {existsSync, mkdirSync, writeFileSync} from 'fs';
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable:no-console */
|
||||||
import {spawn} from 'child_process';
|
import {spawn} from 'child_process';
|
||||||
import {platform} from 'os';
|
import {platform} from 'os';
|
||||||
import {normalize} from 'path';
|
import {normalize} from 'path';
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"file-header": [true, "Copyright Google Inc\\."],
|
"file-header": [true, "Copyright Google Inc\\."],
|
||||||
|
"no-console": [true, "log"],
|
||||||
"no-duplicate-imports": true,
|
"no-duplicate-imports": true,
|
||||||
"no-duplicate-variable": true,
|
"no-duplicate-variable": true,
|
||||||
"no-jasmine-focus": true,
|
"no-jasmine-focus": true,
|
||||||
|
Reference in New Issue
Block a user