Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
84542d8ae7 | |||
17cb3ec565 | |||
015878afe6 | |||
2af58622c1 | |||
7ffd10541d | |||
481b099d82 | |||
49c4b0fa92 | |||
b8b6b1d27a | |||
892b5ba950 | |||
bd15110c7d | |||
2250082fd7 | |||
87316c52db | |||
606b76d9bb | |||
3d0b1b8184 | |||
261fd16780 | |||
104cc42f6d |
18
CHANGELOG.md
18
CHANGELOG.md
@ -1,3 +1,19 @@
|
|||||||
|
<a name="2.4.4"></a>
|
||||||
|
## [2.4.4](https://github.com/angular/angular/compare/2.4.3...2.4.4) (2017-01-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **animations:** fix internal jscompiler issue and AOT quoting ([#13798](https://github.com/angular/angular/issues/13798)) ([261fd16](https://github.com/angular/angular/commit/261fd16))
|
||||||
|
* **common:** support numeric value as discrete cases for NgPlural ([#13876](https://github.com/angular/angular/issues/13876)) ([3d0b1b8](https://github.com/angular/angular/commit/3d0b1b8))
|
||||||
|
* **http:** don't create a blob out of ArrayBuffer when type is application/octet-stream ([#13992](https://github.com/angular/angular/issues/13992)) ([015878a](https://github.com/angular/angular/commit/015878a)), closes [#13973](https://github.com/angular/angular/issues/13973)
|
||||||
|
* **router:** enable loadChildren with function in aot ([#13909](https://github.com/angular/angular/issues/13909)) ([2af5862](https://github.com/angular/angular/commit/2af5862)), closes [#11075](https://github.com/angular/angular/issues/11075)
|
||||||
|
* **router:** routerLinkActive should not throw when not initialized ([#13273](https://github.com/angular/angular/issues/13273)) ([49c4b0f](https://github.com/angular/angular/commit/49c4b0f)), closes [#13270](https://github.com/angular/angular/issues/13270)
|
||||||
|
* **security:** allow calc and gradient functions. ([#13943](https://github.com/angular/angular/issues/13943)) ([bd15110](https://github.com/angular/angular/commit/bd15110))
|
||||||
|
* **upgrade:** detect async downgrade component changes ([#13812](https://github.com/angular/angular/issues/13812)) ([2250082](https://github.com/angular/angular/commit/2250082)), closes [#6385](https://github.com/angular/angular/issues/6385) [#6385](https://github.com/angular/angular/issues/6385) [#10660](https://github.com/angular/angular/issues/10660) [#12318](https://github.com/angular/angular/issues/12318) [#12034](https://github.com/angular/angular/issues/12034)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="2.4.3"></a>
|
<a name="2.4.3"></a>
|
||||||
## [2.4.3](https://github.com/angular/angular/compare/2.4.2...2.4.3) (2017-01-11)
|
## [2.4.3](https://github.com/angular/angular/compare/2.4.2...2.4.3) (2017-01-11)
|
||||||
|
|
||||||
@ -26,7 +42,7 @@
|
|||||||
* **common:** allow null/undefined values for `NgForTrackBy` ([6be55cc](https://github.com/angular/angular/commit/6be55cc)), closes [#13641](https://github.com/angular/angular/issues/13641)
|
* **common:** allow null/undefined values for `NgForTrackBy` ([6be55cc](https://github.com/angular/angular/commit/6be55cc)), closes [#13641](https://github.com/angular/angular/issues/13641)
|
||||||
* **compiler:** don’t throw when using `ANALYZE_FOR_ENTRY_COMPONENTS` with user classes ([#13679](https://github.com/angular/angular/issues/13679)) ([230e33f](https://github.com/angular/angular/commit/230e33f)), closes [#13565](https://github.com/angular/angular/issues/13565)
|
* **compiler:** don’t throw when using `ANALYZE_FOR_ENTRY_COMPONENTS` with user classes ([#13679](https://github.com/angular/angular/issues/13679)) ([230e33f](https://github.com/angular/angular/commit/230e33f)), closes [#13565](https://github.com/angular/angular/issues/13565)
|
||||||
* **compiler:** query `<template>` elements before their children. ([#13677](https://github.com/angular/angular/issues/13677)) ([1cd73c7](https://github.com/angular/angular/commit/1cd73c7)), closes [#13118](https://github.com/angular/angular/issues/13118) [#13167](https://github.com/angular/angular/issues/13167)
|
* **compiler:** query `<template>` elements before their children. ([#13677](https://github.com/angular/angular/issues/13677)) ([1cd73c7](https://github.com/angular/angular/commit/1cd73c7)), closes [#13118](https://github.com/angular/angular/issues/13118) [#13167](https://github.com/angular/angular/issues/13167)
|
||||||
* **compiler:** allow "." in attribute selectors ([#13653](https://github.com/angular/angular/issues/13653)) ([29ffdfd](https://github.com/angular/angular/commit/29ffdfd)), closes [#13645](https://github.com/angular/angular/issues/13645)
|
* **compiler:** allow "." in attribute selectors ([#13653](https://github.com/angular/angular/issues/13653)) ([29ffdfd](https://github.com/angular/angular/commit/29ffdfd)), closes [#13645](https://github.com/angular/angular/issues/13645) [#13982](https://github.com/angular/angular/issues/13982)
|
||||||
* **core:** animations no longer silently exits if the element is not apart of the DOM ([#13763](https://github.com/angular/angular/issues/13763)) ([f1cde43](https://github.com/angular/angular/commit/f1cde43))
|
* **core:** animations no longer silently exits if the element is not apart of the DOM ([#13763](https://github.com/angular/angular/issues/13763)) ([f1cde43](https://github.com/angular/angular/commit/f1cde43))
|
||||||
* **core:** animations should blend in all previously transitioned styles into next animation if interrupted ([#13148](https://github.com/angular/angular/issues/13148)) ([b245b92](https://github.com/angular/angular/commit/b245b92))
|
* **core:** animations should blend in all previously transitioned styles into next animation if interrupted ([#13148](https://github.com/angular/angular/issues/13148)) ([b245b92](https://github.com/angular/angular/commit/b245b92))
|
||||||
* **core:** remove reference to "Angular 2" in dev mode warning ([#13751](https://github.com/angular/angular/issues/13751)) ([21f5f05](https://github.com/angular/angular/commit/21f5f05))
|
* **core:** remove reference to "Angular 2" in dev mode warning ([#13751](https://github.com/angular/angular/issues/13751)) ([21f5f05](https://github.com/angular/angular/commit/21f5f05))
|
||||||
|
@ -103,6 +103,7 @@ export class NgPluralCase {
|
|||||||
constructor(
|
constructor(
|
||||||
@Attribute('ngPluralCase') public value: string, template: TemplateRef<Object>,
|
@Attribute('ngPluralCase') public value: string, template: TemplateRef<Object>,
|
||||||
viewContainer: ViewContainerRef, @Host() ngPlural: NgPlural) {
|
viewContainer: ViewContainerRef, @Host() ngPlural: NgPlural) {
|
||||||
ngPlural.addCase(value, new SwitchView(viewContainer, template));
|
const isANumber: boolean = !isNaN(Number(value));
|
||||||
|
ngPlural.addCase(isANumber ? `=${value}` : value, new SwitchView(viewContainer, template));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
|||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('switch', () => {
|
describe('ngPlural', () => {
|
||||||
let fixture: ComponentFixture<any>;
|
let fixture: ComponentFixture<any>;
|
||||||
|
|
||||||
function getComponent(): TestComponent { return fixture.componentInstance; }
|
function getComponent(): TestComponent { return fixture.componentInstance; }
|
||||||
@ -47,6 +47,22 @@ export function main() {
|
|||||||
detectChangesAndExpectText('you have one message.');
|
detectChangesAndExpectText('you have one message.');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should display the template according to the exact numeric value', async(() => {
|
||||||
|
const template = '<div>' +
|
||||||
|
'<ul [ngPlural]="switchValue">' +
|
||||||
|
'<template ngPluralCase="0"><li>you have no messages.</li></template>' +
|
||||||
|
'<template ngPluralCase="1"><li>you have one message.</li></template>' +
|
||||||
|
'</ul></div>';
|
||||||
|
|
||||||
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
|
getComponent().switchValue = 0;
|
||||||
|
detectChangesAndExpectText('you have no messages.');
|
||||||
|
|
||||||
|
getComponent().switchValue = 1;
|
||||||
|
detectChangesAndExpectText('you have one message.');
|
||||||
|
}));
|
||||||
|
|
||||||
// https://github.com/angular/angular/issues/9868
|
// https://github.com/angular/angular/issues/9868
|
||||||
// https://github.com/angular/angular/issues/9882
|
// https://github.com/angular/angular/issues/9882
|
||||||
it('should not throw when ngPluralCase contains expressions', async(() => {
|
it('should not throw when ngPluralCase contains expressions', async(() => {
|
||||||
|
@ -36,29 +36,6 @@ export class CodeGenerator {
|
|||||||
public host: ts.CompilerHost, private compiler: compiler.AotCompiler,
|
public host: ts.CompilerHost, private compiler: compiler.AotCompiler,
|
||||||
private ngCompilerHost: CompilerHost) {}
|
private ngCompilerHost: CompilerHost) {}
|
||||||
|
|
||||||
// Write codegen in a directory structure matching the sources.
|
|
||||||
private calculateEmitPath(filePath: string): string {
|
|
||||||
let root = this.options.basePath;
|
|
||||||
for (const eachRootDir of this.options.rootDirs || []) {
|
|
||||||
if (this.options.trace) {
|
|
||||||
console.error(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
|
||||||
}
|
|
||||||
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
|
||||||
root = eachRootDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// transplant the codegen path to be inside the `genDir`
|
|
||||||
let relativePath: string = path.relative(root, filePath);
|
|
||||||
while (relativePath.startsWith('..' + path.sep)) {
|
|
||||||
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
|
||||||
// into `genDir`.
|
|
||||||
relativePath = relativePath.substr(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.join(this.options.genDir, relativePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
codegen(): Promise<any> {
|
codegen(): Promise<any> {
|
||||||
return this.compiler
|
return this.compiler
|
||||||
.compileAll(this.program.getSourceFiles().map(
|
.compileAll(this.program.getSourceFiles().map(
|
||||||
@ -66,7 +43,7 @@ export class CodeGenerator {
|
|||||||
.then(generatedModules => {
|
.then(generatedModules => {
|
||||||
generatedModules.forEach(generatedModule => {
|
generatedModules.forEach(generatedModule => {
|
||||||
const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl);
|
const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl);
|
||||||
const emitPath = this.calculateEmitPath(generatedModule.genFileUrl);
|
const emitPath = this.ngCompilerHost.calculateEmitPath(generatedModule.genFileUrl);
|
||||||
const source = GENERATED_META_FILES.test(emitPath) ? generatedModule.source :
|
const source = GENERATED_META_FILES.test(emitPath) ? generatedModule.source :
|
||||||
PREAMBLE + generatedModule.source;
|
PREAMBLE + generatedModule.source;
|
||||||
this.host.writeFile(emitPath, source, false, () => {}, [sourceFile]);
|
this.host.writeFile(emitPath, source, false, () => {}, [sourceFile]);
|
||||||
|
@ -261,6 +261,29 @@ export class CompilerHost implements AotCompilerHost {
|
|||||||
this.options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
this.options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
||||||
return !excludeRegex.test(filePath);
|
return !excludeRegex.test(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculateEmitPath(filePath: string): string {
|
||||||
|
// Write codegen in a directory structure matching the sources.
|
||||||
|
let root = this.options.basePath;
|
||||||
|
for (const eachRootDir of this.options.rootDirs || []) {
|
||||||
|
if (this.options.trace) {
|
||||||
|
console.error(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
||||||
|
}
|
||||||
|
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
||||||
|
root = eachRootDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transplant the codegen path to be inside the `genDir`
|
||||||
|
let relativePath: string = path.relative(root, filePath);
|
||||||
|
while (relativePath.startsWith('..' + path.sep)) {
|
||||||
|
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
||||||
|
// into `genDir`.
|
||||||
|
relativePath = relativePath.substr(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.join(this.options.genDir, relativePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CompilerHostContextAdapter {
|
export class CompilerHostContextAdapter {
|
||||||
|
@ -404,8 +404,9 @@ function createViewTopLevelStmts(view: CompileView, targetStatements: o.Statemen
|
|||||||
o.literal(view.component.template.ngContentSelectors.length),
|
o.literal(view.component.template.ngContentSelectors.length),
|
||||||
ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
|
ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
|
||||||
view.styles,
|
view.styles,
|
||||||
o.literalMap(view.animations.map(
|
o.literalMap(
|
||||||
(entry): [string, o.Expression] => [entry.name, entry.fnExp])),
|
view.animations.map((entry): [string, o.Expression] => [entry.name, entry.fnExp]),
|
||||||
|
null, true),
|
||||||
]))
|
]))
|
||||||
.toDeclStmt(o.importType(createIdentifier(Identifiers.RenderComponentType))));
|
.toDeclStmt(o.importType(createIdentifier(Identifiers.RenderComponentType))));
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import {isPromise} from '../src/util/lang';
|
|||||||
|
|
||||||
import {ApplicationInitStatus} from './application_init';
|
import {ApplicationInitStatus} from './application_init';
|
||||||
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
|
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
|
||||||
import {ChangeDetectorRef} from './change_detection/change_detector_ref';
|
|
||||||
import {Console} from './console';
|
import {Console} from './console';
|
||||||
import {Injectable, Injector, OpaqueToken, Optional, Provider, ReflectiveInjector} from './di';
|
import {Injectable, Injector, OpaqueToken, Optional, Provider, ReflectiveInjector} from './di';
|
||||||
import {CompilerFactory, CompilerOptions} from './linker/compiler';
|
import {CompilerFactory, CompilerOptions} from './linker/compiler';
|
||||||
|
@ -112,7 +112,7 @@ export class Request extends Body {
|
|||||||
case 'text/html':
|
case 'text/html':
|
||||||
return ContentType.TEXT;
|
return ContentType.TEXT;
|
||||||
case 'application/octet-stream':
|
case 'application/octet-stream':
|
||||||
return ContentType.BLOB;
|
return this._body instanceof ArrayBuffer ? ContentType.ARRAY_BUFFER : ContentType.BLOB;
|
||||||
default:
|
default:
|
||||||
return this.detectContentTypeFromBody();
|
return this.detectContentTypeFromBody();
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ export class Request extends Body {
|
|||||||
return ContentType.BLOB;
|
return ContentType.BLOB;
|
||||||
} else if (this._body instanceof ArrayBuffer) {
|
} else if (this._body instanceof ArrayBuffer) {
|
||||||
return ContentType.ARRAY_BUFFER;
|
return ContentType.ARRAY_BUFFER;
|
||||||
} else if (this._body && typeof this._body == 'object') {
|
} else if (this._body && typeof this._body === 'object') {
|
||||||
return ContentType.JSON;
|
return ContentType.JSON;
|
||||||
} else {
|
} else {
|
||||||
return ContentType.TEXT;
|
return ContentType.TEXT;
|
||||||
@ -167,4 +167,4 @@ const noop = function() {};
|
|||||||
const w = typeof window == 'object' ? window : noop;
|
const w = typeof window == 'object' ? window : noop;
|
||||||
const FormData = (w as any /** TODO #9100 */)['FormData'] || noop;
|
const FormData = (w as any /** TODO #9100 */)['FormData'] || noop;
|
||||||
const Blob = (w as any /** TODO #9100 */)['Blob'] || noop;
|
const Blob = (w as any /** TODO #9100 */)['Blob'] || noop;
|
||||||
const ArrayBuffer = (w as any /** TODO #9100 */)['ArrayBuffer'] || noop;
|
export const ArrayBuffer = (w as any /** TODO #9100 */)['ArrayBuffer'] || noop;
|
||||||
|
@ -36,7 +36,7 @@ import {Headers} from './headers';
|
|||||||
*/
|
*/
|
||||||
export class Response extends Body {
|
export class Response extends Body {
|
||||||
/**
|
/**
|
||||||
* One of "basic", "cors", "default", "error, or "opaque".
|
* One of "basic", "cors", "default", "error", or "opaque".
|
||||||
*
|
*
|
||||||
* Defaults to "default".
|
* Defaults to "default".
|
||||||
*/
|
*/
|
||||||
|
@ -11,7 +11,7 @@ import {describe, expect, it} from '@angular/core/testing/testing_internal';
|
|||||||
import {RequestOptions} from '../src/base_request_options';
|
import {RequestOptions} from '../src/base_request_options';
|
||||||
import {ContentType} from '../src/enums';
|
import {ContentType} from '../src/enums';
|
||||||
import {Headers} from '../src/headers';
|
import {Headers} from '../src/headers';
|
||||||
import {Request} from '../src/static_request';
|
import {ArrayBuffer, Request} from '../src/static_request';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('Request', () => {
|
describe('Request', () => {
|
||||||
@ -76,6 +76,17 @@ export function main() {
|
|||||||
|
|
||||||
expect(req.detectContentType()).toEqual(ContentType.BLOB);
|
expect(req.detectContentType()).toEqual(ContentType.BLOB);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not create a blob out of ArrayBuffer', () => {
|
||||||
|
const req = new Request(new RequestOptions({
|
||||||
|
url: 'test',
|
||||||
|
method: 'GET',
|
||||||
|
body: new ArrayBuffer(1),
|
||||||
|
headers: new Headers({'content-type': 'application/octet-stream'})
|
||||||
|
}));
|
||||||
|
|
||||||
|
expect(req.detectContentType()).toEqual(ContentType.ARRAY_BUFFER);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return empty string if no body is present', () => {
|
it('should return empty string if no body is present', () => {
|
||||||
|
@ -96,7 +96,9 @@ export class WebAnimationsPlayer implements AnimationPlayer {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_triggerWebAnimation(element: any, keyframes: any[], options: any): DomAnimatePlayer {
|
_triggerWebAnimation(element: any, keyframes: any[], options: any): DomAnimatePlayer {
|
||||||
return <DomAnimatePlayer>element.animate(keyframes, options);
|
// jscompiler doesn't seem to know animate is a native property because it's not fully
|
||||||
|
// supported yet across common browsers (we polyfill it for Edge/Safari) [CL #143630929]
|
||||||
|
return <DomAnimatePlayer>element['animate'](keyframes, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
get domPlayer() { return this._player; }
|
get domPlayer() { return this._player; }
|
||||||
|
@ -30,9 +30,14 @@ import {sanitizeUrl} from './url_sanitizer';
|
|||||||
const VALUES = '[-,."\'%_!# a-zA-Z0-9]+';
|
const VALUES = '[-,."\'%_!# a-zA-Z0-9]+';
|
||||||
const TRANSFORMATION_FNS = '(?:matrix|translate|scale|rotate|skew|perspective)(?:X|Y|3d)?';
|
const TRANSFORMATION_FNS = '(?:matrix|translate|scale|rotate|skew|perspective)(?:X|Y|3d)?';
|
||||||
const COLOR_FNS = '(?:rgb|hsl)a?';
|
const COLOR_FNS = '(?:rgb|hsl)a?';
|
||||||
const FN_ARGS = '\\([-0-9.%, a-zA-Z]+\\)';
|
const GRADIENTS = '(?:repeating-)?(?:linear|radial)-gradient';
|
||||||
const SAFE_STYLE_VALUE =
|
const CSS3_FNS = '(?:calc|attr)';
|
||||||
new RegExp(`^(${VALUES}|(?:${TRANSFORMATION_FNS}|${COLOR_FNS})${FN_ARGS})$`, 'g');
|
const FN_ARGS = '\\([-0-9.%, #a-zA-Z]+\\)';
|
||||||
|
const SAFE_STYLE_VALUE = new RegExp(
|
||||||
|
`^(${VALUES}|` +
|
||||||
|
`(?:${TRANSFORMATION_FNS}|${COLOR_FNS}|${GRADIENTS}|${CSS3_FNS})` +
|
||||||
|
`${FN_ARGS})$`,
|
||||||
|
'g');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Matches a `url(...)` value with an arbitrary argument as long as it does
|
* Matches a `url(...)` value with an arbitrary argument as long as it does
|
||||||
|
@ -39,6 +39,16 @@ export function main() {
|
|||||||
expectSanitize('translateX(12px, -5px)').toEqual('translateX(12px, -5px)');
|
expectSanitize('translateX(12px, -5px)').toEqual('translateX(12px, -5px)');
|
||||||
expectSanitize('scale3d(1, 1, 2)').toEqual('scale3d(1, 1, 2)');
|
expectSanitize('scale3d(1, 1, 2)').toEqual('scale3d(1, 1, 2)');
|
||||||
});
|
});
|
||||||
|
t.it('accepts gradients', () => {
|
||||||
|
expectSanitize('linear-gradient(to bottom, #fg34a1, #bada55)')
|
||||||
|
.toEqual('linear-gradient(to bottom, #fg34a1, #bada55)');
|
||||||
|
expectSanitize('repeating-radial-gradient(ellipse cover, black, red, black, red)')
|
||||||
|
.toEqual('repeating-radial-gradient(ellipse cover, black, red, black, red)');
|
||||||
|
});
|
||||||
|
t.it('accepts calc', () => { expectSanitize('calc(90%-123px)').toEqual('calc(90%-123px)'); });
|
||||||
|
t.it('accepts attr', () => {
|
||||||
|
expectSanitize('attr(value string)').toEqual('attr(value string)');
|
||||||
|
});
|
||||||
t.it('sanitizes URLs', () => {
|
t.it('sanitizes URLs', () => {
|
||||||
expectSanitize('url(foo/bar.png)').toEqual('url(foo/bar.png)');
|
expectSanitize('url(foo/bar.png)').toEqual('url(foo/bar.png)');
|
||||||
expectSanitize('url( foo/bar.png\n )').toEqual('url( foo/bar.png\n )');
|
expectSanitize('url( foo/bar.png\n )').toEqual('url( foo/bar.png\n )');
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Type} from '@angular/core';
|
import {NgModuleFactory, Type} from '@angular/core';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {PRIMARY_OUTLET} from './shared';
|
import {PRIMARY_OUTLET} from './shared';
|
||||||
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
import {UrlSegment, UrlSegmentGroup} from './url_tree';
|
||||||
@ -310,7 +310,8 @@ export type ResolveData = {
|
|||||||
* See {@link Routes} for more details.
|
* See {@link Routes} for more details.
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export type LoadChildrenCallback = () => Type<any>| Promise<Type<any>>| Observable<Type<any>>;
|
export type LoadChildrenCallback = () =>
|
||||||
|
Type<any>| NgModuleFactory<any>| Promise<Type<any>>| Observable<Type<any>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes The type of `loadChildren`.
|
* @whatItDoes The type of `loadChildren`.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {AfterContentInit, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer} from '@angular/core';
|
import {AfterContentInit, ChangeDetectorRef, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer, SimpleChanges} from '@angular/core';
|
||||||
import {Subscription} from 'rxjs/Subscription';
|
import {Subscription} from 'rxjs/Subscription';
|
||||||
|
|
||||||
import {NavigationEnd, Router} from '../router';
|
import {NavigationEnd, Router} from '../router';
|
||||||
@ -14,6 +14,7 @@ import {NavigationEnd, Router} from '../router';
|
|||||||
import {RouterLink, RouterLinkWithHref} from './router_link';
|
import {RouterLink, RouterLinkWithHref} from './router_link';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @whatItDoes Lets you add a CSS class to an element when the link's route becomes active.
|
* @whatItDoes Lets you add a CSS class to an element when the link's route becomes active.
|
||||||
*
|
*
|
||||||
@ -89,10 +90,13 @@ export class RouterLinkActive implements OnChanges,
|
|||||||
|
|
||||||
private classes: string[] = [];
|
private classes: string[] = [];
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
|
private active: boolean = false;
|
||||||
|
|
||||||
@Input() routerLinkActiveOptions: {exact: boolean} = {exact: false};
|
@Input() routerLinkActiveOptions: {exact: boolean} = {exact: false};
|
||||||
|
|
||||||
constructor(private router: Router, private element: ElementRef, private renderer: Renderer) {
|
constructor(
|
||||||
|
private router: Router, private element: ElementRef, private renderer: Renderer,
|
||||||
|
private cdr: ChangeDetectorRef) {
|
||||||
this.subscription = router.events.subscribe(s => {
|
this.subscription = router.events.subscribe(s => {
|
||||||
if (s instanceof NavigationEnd) {
|
if (s instanceof NavigationEnd) {
|
||||||
this.update();
|
this.update();
|
||||||
@ -100,35 +104,34 @@ export class RouterLinkActive implements OnChanges,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get isActive(): boolean { return this.hasActiveLink(); }
|
get isActive(): boolean { return this.active; }
|
||||||
|
|
||||||
ngAfterContentInit(): void {
|
ngAfterContentInit(): void {
|
||||||
this.links.changes.subscribe(s => this.update());
|
this.links.changes.subscribe(_ => this.update());
|
||||||
this.linksWithHrefs.changes.subscribe(s => this.update());
|
this.linksWithHrefs.changes.subscribe(_ => this.update());
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set routerLinkActive(data: string[]|string) {
|
set routerLinkActive(data: string[]|string) {
|
||||||
if (Array.isArray(data)) {
|
const classes = Array.isArray(data) ? data : data.split(' ');
|
||||||
this.classes = <any>data;
|
this.classes = classes.filter(c => !!c);
|
||||||
} else {
|
|
||||||
this.classes = data.split(' ');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: {}): any { this.update(); }
|
ngOnChanges(changes: SimpleChanges): void { this.update(); }
|
||||||
ngOnDestroy(): any { this.subscription.unsubscribe(); }
|
ngOnDestroy(): void { this.subscription.unsubscribe(); }
|
||||||
|
|
||||||
private update(): void {
|
private update(): void {
|
||||||
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
|
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return;
|
||||||
|
const hasActiveLinks = this.hasActiveLinks();
|
||||||
|
|
||||||
const isActive = this.hasActiveLink();
|
// react only when status has changed to prevent unnecessary dom updates
|
||||||
this.classes.forEach(c => {
|
if (this.active !== hasActiveLinks) {
|
||||||
if (c) {
|
this.active = hasActiveLinks;
|
||||||
this.renderer.setElementClass(this.element.nativeElement, c, isActive);
|
this.classes.forEach(
|
||||||
|
c => this.renderer.setElementClass(this.element.nativeElement, c, hasActiveLinks));
|
||||||
|
this.cdr.detectChanges();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
|
private isLinkActive(router: Router): (link: (RouterLink|RouterLinkWithHref)) => boolean {
|
||||||
@ -136,7 +139,7 @@ export class RouterLinkActive implements OnChanges,
|
|||||||
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
|
router.isActive(link.urlTree, this.routerLinkActiveOptions.exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasActiveLink(): boolean {
|
private hasActiveLinks(): boolean {
|
||||||
return this.links.some(this.isLinkActive(this.router)) ||
|
return this.links.some(this.isLinkActive(this.router)) ||
|
||||||
this.linksWithHrefs.some(this.isLinkActive(this.router));
|
this.linksWithHrefs.some(this.isLinkActive(this.router));
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {NgModuleFactory} from '@angular/core';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {fromPromise} from 'rxjs/observable/fromPromise';
|
import {fromPromise} from 'rxjs/observable/fromPromise';
|
||||||
import {of } from 'rxjs/observable/of';
|
import {of } from 'rxjs/observable/of';
|
||||||
@ -126,7 +127,8 @@ export function andObservables(observables: Observable<Observable<any>>): Observ
|
|||||||
return every.call(merged$, (result: any) => result === true);
|
return every.call(merged$, (result: any) => result === true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapIntoObservable<T>(value: T | Promise<T>| Observable<T>): Observable<T> {
|
export function wrapIntoObservable<T>(value: T | NgModuleFactory<T>| Promise<T>| Observable<T>):
|
||||||
|
Observable<T> {
|
||||||
if (value instanceof Observable) {
|
if (value instanceof Observable) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -2032,6 +2032,8 @@ describe('Integration', () => {
|
|||||||
@Component({
|
@Component({
|
||||||
template: `<a routerLink="/team" routerLinkActive #rla="routerLinkActive"></a>
|
template: `<a routerLink="/team" routerLinkActive #rla="routerLinkActive"></a>
|
||||||
<p>{{rla.isActive}}</p>
|
<p>{{rla.isActive}}</p>
|
||||||
|
<span *ngIf="rla.isActive"></span>
|
||||||
|
<span [ngClass]="{'highlight': rla.isActive}"></span>
|
||||||
<router-outlet></router-outlet>`
|
<router-outlet></router-outlet>`
|
||||||
})
|
})
|
||||||
class ComponentWithRouterLink {
|
class ComponentWithRouterLink {
|
||||||
@ -2051,15 +2053,15 @@ describe('Integration', () => {
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const f = TestBed.createComponent(ComponentWithRouterLink);
|
const fixture = TestBed.createComponent(ComponentWithRouterLink);
|
||||||
router.navigateByUrl('/team');
|
router.navigateByUrl('/team');
|
||||||
advance(f);
|
expect(() => advance(fixture)).not.toThrow();
|
||||||
|
|
||||||
const paragraph = f.nativeElement.querySelector('p');
|
const paragraph = fixture.nativeElement.querySelector('p');
|
||||||
expect(paragraph.textContent).toEqual('true');
|
expect(paragraph.textContent).toEqual('true');
|
||||||
|
|
||||||
router.navigateByUrl('/otherteam');
|
router.navigateByUrl('/otherteam');
|
||||||
advance(f);
|
advance(fixture);
|
||||||
|
|
||||||
expect(paragraph.textContent).toEqual('false');
|
expect(paragraph.textContent).toEqual('false');
|
||||||
}));
|
}));
|
||||||
|
@ -577,10 +577,6 @@ export class UpgradeAdapter {
|
|||||||
})
|
})
|
||||||
.then((ref: NgModuleRef<any>) => {
|
.then((ref: NgModuleRef<any>) => {
|
||||||
this.moduleRef = ref;
|
this.moduleRef = ref;
|
||||||
let subscription = this.ngZone.onMicrotaskEmpty.subscribe({
|
|
||||||
next: (_: any) => this.ngZone.runOutsideAngular(() => rootScope.$evalAsync())
|
|
||||||
});
|
|
||||||
rootScope.$on('$destroy', () => { subscription.unsubscribe(); });
|
|
||||||
this.ngZone.run(() => {
|
this.ngZone.run(() => {
|
||||||
if (rootScopePrototype) {
|
if (rootScopePrototype) {
|
||||||
rootScopePrototype.$apply = original$applyFn; // restore original $apply
|
rootScopePrototype.$apply = original$applyFn; // restore original $apply
|
||||||
@ -591,7 +587,12 @@ export class UpgradeAdapter {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(() => this.ng2BootstrapDeferred.resolve(ng1Injector), onError);
|
.then(() => this.ng2BootstrapDeferred.resolve(ng1Injector), onError)
|
||||||
|
.then(() => {
|
||||||
|
let subscription =
|
||||||
|
this.ngZone.onMicrotaskEmpty.subscribe({next: () => rootScope.$digest()});
|
||||||
|
rootScope.$on('$destroy', () => { subscription.unsubscribe(); });
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((e) => this.ng2BootstrapDeferred.reject(e));
|
.catch((e) => this.ng2BootstrapDeferred.reject(e));
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef, Class, Component, EventEmitter, NO_ERRORS_SCHEMA, NgModule, SimpleChange, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core';
|
import {ChangeDetectorRef, Class, Component, EventEmitter, Input, NO_ERRORS_SCHEMA, NgModule, NgZone, SimpleChange, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core';
|
||||||
import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
|
import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
@ -18,51 +18,9 @@ export function main() {
|
|||||||
beforeEach(() => destroyPlatform());
|
beforeEach(() => destroyPlatform());
|
||||||
afterEach(() => destroyPlatform());
|
afterEach(() => destroyPlatform());
|
||||||
|
|
||||||
|
describe('(basic use)', () => {
|
||||||
it('should have angular 1 loaded', () => expect(angular.version.major).toBe(1));
|
it('should have angular 1 loaded', () => expect(angular.version.major).toBe(1));
|
||||||
|
|
||||||
describe('bootstrap errors', () => {
|
|
||||||
let adapter: UpgradeAdapter;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
angular.module('ng1', []);
|
|
||||||
|
|
||||||
const ng2Component = Component({
|
|
||||||
selector: 'ng2',
|
|
||||||
template: `<BAD TEMPLATE div></div>`,
|
|
||||||
}).Class({constructor: function() {}});
|
|
||||||
|
|
||||||
const Ng2Module = NgModule({
|
|
||||||
declarations: [ng2Component],
|
|
||||||
imports: [BrowserModule],
|
|
||||||
}).Class({constructor: function() {}});
|
|
||||||
|
|
||||||
adapter = new UpgradeAdapter(Ng2Module);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an uncaught error', fakeAsync(() => {
|
|
||||||
const resolveSpy = jasmine.createSpy('resolveSpy');
|
|
||||||
spyOn(console, 'error');
|
|
||||||
|
|
||||||
expect(() => {
|
|
||||||
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']).ready(resolveSpy);
|
|
||||||
flushMicrotasks();
|
|
||||||
}).toThrowError();
|
|
||||||
expect(resolveSpy).not.toHaveBeenCalled();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should output an error message to the console and re-throw', fakeAsync(() => {
|
|
||||||
let consoleErrorSpy: jasmine.Spy = spyOn(console, 'error');
|
|
||||||
expect(() => {
|
|
||||||
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']);
|
|
||||||
flushMicrotasks();
|
|
||||||
}).toThrowError();
|
|
||||||
let args: any[] = consoleErrorSpy.calls.mostRecent().args;
|
|
||||||
expect(consoleErrorSpy).toHaveBeenCalled();
|
|
||||||
expect(args.length).toBeGreaterThan(0);
|
|
||||||
expect(args[0]).toEqual(jasmine.any(Error));
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should instantiate ng2 in ng1 template and project content', async(() => {
|
it('should instantiate ng2 in ng1 template and project content', async(() => {
|
||||||
const ng1Module = angular.module('ng1', []);
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
|
||||||
@ -142,6 +100,50 @@ export function main() {
|
|||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('bootstrap errors', () => {
|
||||||
|
let adapter: UpgradeAdapter;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
angular.module('ng1', []);
|
||||||
|
|
||||||
|
const ng2Component = Component({
|
||||||
|
selector: 'ng2',
|
||||||
|
template: `<BAD TEMPLATE div></div>`,
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [ng2Component],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
adapter = new UpgradeAdapter(Ng2Module);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an uncaught error', fakeAsync(() => {
|
||||||
|
const resolveSpy = jasmine.createSpy('resolveSpy');
|
||||||
|
spyOn(console, 'error');
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']).ready(resolveSpy);
|
||||||
|
flushMicrotasks();
|
||||||
|
}).toThrowError();
|
||||||
|
expect(resolveSpy).not.toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should output an error message to the console and re-throw', fakeAsync(() => {
|
||||||
|
const consoleErrorSpy: jasmine.Spy = spyOn(console, 'error');
|
||||||
|
expect(() => {
|
||||||
|
adapter.bootstrap(html('<ng2></ng2>'), ['ng1']);
|
||||||
|
flushMicrotasks();
|
||||||
|
}).toThrowError();
|
||||||
|
const args: any[] = consoleErrorSpy.calls.mostRecent().args;
|
||||||
|
expect(consoleErrorSpy).toHaveBeenCalled();
|
||||||
|
expect(args.length).toBeGreaterThan(0);
|
||||||
|
expect(args[0]).toEqual(jasmine.any(Error));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
describe('scope/component change-detection', () => {
|
describe('scope/component change-detection', () => {
|
||||||
it('should interleave scope and component expressions', async(() => {
|
it('should interleave scope and component expressions', async(() => {
|
||||||
@ -184,6 +186,87 @@ export function main() {
|
|||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should propagate changes to a downgraded component inside the ngZone', async(() => {
|
||||||
|
let appComponent: AppComponent;
|
||||||
|
let upgradeRef: UpgradeAdapterRef;
|
||||||
|
|
||||||
|
@Component({selector: 'my-app', template: '<my-child [value]="value"></my-child>'})
|
||||||
|
class AppComponent {
|
||||||
|
value: number;
|
||||||
|
constructor() { appComponent = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-child',
|
||||||
|
template: '<div>{{valueFromPromise}}',
|
||||||
|
})
|
||||||
|
class ChildComponent {
|
||||||
|
valueFromPromise: number;
|
||||||
|
@Input()
|
||||||
|
set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); }
|
||||||
|
|
||||||
|
constructor(private zone: NgZone) {}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
if (changes['value'].isFirstChange()) return;
|
||||||
|
|
||||||
|
this.zone.onMicrotaskEmpty.subscribe(() => {
|
||||||
|
expect(element.textContent).toEqual('5');
|
||||||
|
upgradeRef.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.resolve().then(() => this.valueFromPromise = changes['value'].currentValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [AppComponent, ChildComponent], imports: [BrowserModule]})
|
||||||
|
class Ng2Module {
|
||||||
|
}
|
||||||
|
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
const ng1Module = angular.module('ng1', []).directive(
|
||||||
|
'myApp', adapter.downgradeNg2Component(AppComponent));
|
||||||
|
|
||||||
|
const element = html('<my-app></my-app>');
|
||||||
|
|
||||||
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
upgradeRef = ref;
|
||||||
|
appComponent.value = 5;
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
// This test demonstrates https://github.com/angular/angular/issues/6385
|
||||||
|
// which was invalidly fixed by https://github.com/angular/angular/pull/6386
|
||||||
|
// it('should not trigger $digest from an async operation in a watcher', async(() => {
|
||||||
|
// @Component({selector: 'my-app', template: ''})
|
||||||
|
// class AppComponent {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @NgModule({declarations: [AppComponent], imports: [BrowserModule]})
|
||||||
|
// class Ng2Module {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
// const ng1Module = angular.module('ng1', []).directive(
|
||||||
|
// 'myApp', adapter.downgradeNg2Component(AppComponent));
|
||||||
|
|
||||||
|
// const element = html('<my-app></my-app>');
|
||||||
|
|
||||||
|
// adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
// let doTimeout = false;
|
||||||
|
// let timeoutId: number;
|
||||||
|
// ref.ng1RootScope.$watch(() => {
|
||||||
|
// if (doTimeout && !timeoutId) {
|
||||||
|
// timeoutId = window.setTimeout(function() {
|
||||||
|
// timeoutId = null;
|
||||||
|
// }, 10);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// doTimeout = true;
|
||||||
|
// });
|
||||||
|
// }));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('downgrade ng2 component', () => {
|
describe('downgrade ng2 component', () => {
|
||||||
@ -388,6 +471,31 @@ export function main() {
|
|||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should allow attribute selectors for components in ng2', async(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
|
||||||
|
const ng1Module = angular.module('myExample', []);
|
||||||
|
|
||||||
|
@Component({selector: '[works]', template: 'works!'})
|
||||||
|
class WorksComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'root-component', template: 'It <div works></div>'})
|
||||||
|
class RootComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({imports: [BrowserModule], declarations: [RootComponent, WorksComponent]})
|
||||||
|
class MyNg2Module {
|
||||||
|
}
|
||||||
|
|
||||||
|
ng1Module.directive('rootComponent', adapter.downgradeNg2Component(RootComponent));
|
||||||
|
|
||||||
|
document.body.innerHTML = '<root-component></root-component>';
|
||||||
|
adapter.bootstrap(document.body.firstElementChild, ['myExample']).ready((ref) => {
|
||||||
|
expect(multiTrim(document.body.textContent)).toEqual('It works!');
|
||||||
|
ref.dispose();
|
||||||
|
});
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('upgrade ng1 component', () => {
|
describe('upgrade ng1 component', () => {
|
||||||
@ -1627,31 +1735,6 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow attribute selectors for components in ng2', async(() => {
|
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
|
|
||||||
const ng1Module = angular.module('myExample', []);
|
|
||||||
|
|
||||||
@Component({selector: '[works]', template: 'works!'})
|
|
||||||
class WorksComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'root-component', template: 'It <div works></div>'})
|
|
||||||
class RootComponent {
|
|
||||||
}
|
|
||||||
|
|
||||||
@NgModule({imports: [BrowserModule], declarations: [RootComponent, WorksComponent]})
|
|
||||||
class MyNg2Module {
|
|
||||||
}
|
|
||||||
|
|
||||||
ng1Module.directive('rootComponent', adapter.downgradeNg2Component(RootComponent));
|
|
||||||
|
|
||||||
document.body.innerHTML = '<root-component></root-component>';
|
|
||||||
adapter.bootstrap(document.body.firstElementChild, ['myExample']).ready((ref) => {
|
|
||||||
expect(multiTrim(document.body.textContent)).toEqual('It works!');
|
|
||||||
ref.dispose();
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('examples', () => {
|
describe('examples', () => {
|
||||||
it('should verify UpgradeAdapter example', async(() => {
|
it('should verify UpgradeAdapter example', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
|
File diff suppressed because it is too large
Load Diff
3826
npm-shrinkwrap.json
generated
3826
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "2.4.3",
|
"version": "2.4.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",
|
||||||
@ -79,7 +79,7 @@
|
|||||||
"source-map-support": "^0.4.2",
|
"source-map-support": "^0.4.2",
|
||||||
"systemjs": "0.18.10",
|
"systemjs": "0.18.10",
|
||||||
"ts-api-guardian": "0.1.4",
|
"ts-api-guardian": "0.1.4",
|
||||||
"tsickle": "^0.2.1",
|
"tsickle": "^0.2.4",
|
||||||
"tslint": "^4.1.1",
|
"tslint": "^4.1.1",
|
||||||
"tslint-eslint-rules": "^3.1.0",
|
"tslint-eslint-rules": "^3.1.0",
|
||||||
"typescript": "^2.0.2",
|
"typescript": "^2.0.2",
|
||||||
|
8
tools/public_api_guard/router/index.d.ts
vendored
8
tools/public_api_guard/router/index.d.ts
vendored
@ -85,7 +85,7 @@ export interface ExtraOptions {
|
|||||||
export declare type LoadChildren = string | LoadChildrenCallback;
|
export declare type LoadChildren = string | LoadChildrenCallback;
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare type LoadChildrenCallback = () => Type<any> | Promise<Type<any>> | Observable<Type<any>>;
|
export declare type LoadChildrenCallback = () => Type<any> | NgModuleFactory<any> | Promise<Type<any>> | Observable<Type<any>>;
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare class NavigationCancel {
|
export declare class NavigationCancel {
|
||||||
@ -262,10 +262,10 @@ export declare class RouterLinkActive implements OnChanges, OnDestroy, AfterCont
|
|||||||
routerLinkActiveOptions: {
|
routerLinkActiveOptions: {
|
||||||
exact: boolean;
|
exact: boolean;
|
||||||
};
|
};
|
||||||
constructor(router: Router, element: ElementRef, renderer: Renderer);
|
constructor(router: Router, element: ElementRef, renderer: Renderer, cdr: ChangeDetectorRef);
|
||||||
ngAfterContentInit(): void;
|
ngAfterContentInit(): void;
|
||||||
ngOnChanges(changes: {}): any;
|
ngOnChanges(changes: SimpleChanges): void;
|
||||||
ngOnDestroy(): any;
|
ngOnDestroy(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
|
Reference in New Issue
Block a user