Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
84542d8ae7 | |||
17cb3ec565 | |||
015878afe6 | |||
2af58622c1 | |||
7ffd10541d | |||
481b099d82 | |||
49c4b0fa92 | |||
b8b6b1d27a | |||
892b5ba950 | |||
bd15110c7d | |||
2250082fd7 | |||
87316c52db | |||
606b76d9bb | |||
3d0b1b8184 | |||
261fd16780 | |||
104cc42f6d | |||
a7d28044c5 | |||
055bea2969 | |||
dad0d21b89 | |||
313683f6f3 | |||
338be6d6a5 | |||
4b56f79328 | |||
d7f2a3c71b | |||
1c929ae244 | |||
83d0ff6d13 | |||
d43e5dd44d | |||
61ba223c1a | |||
6164eb25f3 | |||
5e9d3dba3a | |||
16922655ca | |||
7dc12b93fe | |||
1c82b58185 | |||
d6c414c08f | |||
d25d1730c7 |
32
.pullapprove.yml
Normal file
32
.pullapprove.yml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Configuration for pullapprove.com
|
||||||
|
# See ownership spreadsheet:
|
||||||
|
# https://docs.google.com/spreadsheets/d/1-HIlzfbPYGsPr9KuYMe6bLfc4LXzPjpoALqtYRYTZB0/edit?pli=1#gid=0&vpid=A5
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
group_defaults:
|
||||||
|
required: 1
|
||||||
|
reset_on_reopened:
|
||||||
|
enabled: true
|
||||||
|
approve_by_comment:
|
||||||
|
enabled: true
|
||||||
|
approve_regex: '^(Approved|:\+1:|LGTM)'
|
||||||
|
|
||||||
|
groups:
|
||||||
|
config:
|
||||||
|
conditions:
|
||||||
|
files:
|
||||||
|
- "*.yml"
|
||||||
|
- "*.json"
|
||||||
|
teams:
|
||||||
|
- repoowners
|
||||||
|
|
||||||
|
compiler:
|
||||||
|
conditions:
|
||||||
|
files:
|
||||||
|
- "tools/@angular/tsc-wrapped/*"
|
||||||
|
- "modules/@angular/compiler/*"
|
||||||
|
- "modules/@angular/compiler-cli/*"
|
||||||
|
teams:
|
||||||
|
- compiler-owners
|
||||||
|
- repoowners
|
35
CHANGELOG.md
35
CHANGELOG.md
@ -1,3 +1,36 @@
|
|||||||
|
<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>
|
||||||
|
## [2.4.3](https://github.com/angular/angular/compare/2.4.2...2.4.3) (2017-01-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** avoid evaluating arguments to unknown decorators ([5e9d3db](https://github.com/angular/angular/commit/5e9d3db)), closes [#13605](https://github.com/angular/angular/issues/13605)
|
||||||
|
* **compiler:** fix template binding parsing (`*directive="-..."`) ([7dc12b9](https://github.com/angular/angular/commit/7dc12b9)), closes [#13800](https://github.com/angular/angular/issues/13800)
|
||||||
|
* **compiler-cli:** add support for more than 2 levels of nested lazy routes ([6164eb2](https://github.com/angular/angular/commit/6164eb2)), closes [angular/angular-cli#3663](https://github.com/angular/angular-cli/issues/3663)
|
||||||
|
* **compiler-cli:** avoid handling functions in loadChildren as lazy load routes paths ([313683f](https://github.com/angular/angular/commit/313683f)), closes [angular/angular-cli#3204](https://github.com/angular/angular-cli/issues/3204)
|
||||||
|
* **i18n:** translate attributes inside elements marked for translation ([d7f2a3c](https://github.com/angular/angular/commit/d7f2a3c))
|
||||||
|
* **router:** RouterLink mirrors input `target` as attribute ([1c82b58](https://github.com/angular/angular/commit/1c82b58)), closes [#13837](https://github.com/angular/angular/issues/13837)
|
||||||
|
* **router:** throw an error when navigate to null/undefined path ([61ba223](https://github.com/angular/angular/commit/61ba223)), closes [#10560](https://github.com/angular/angular/issues/10560) [#13384](https://github.com/angular/angular/issues/13384)
|
||||||
|
* **router:** fix checking for object intersection ([1692265](https://github.com/angular/angular/commit/1692265))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="2.4.2"></a>
|
<a name="2.4.2"></a>
|
||||||
## [2.4.2](https://github.com/angular/angular/compare/2.4.1...2.4.2) (2017-01-06)
|
## [2.4.2](https://github.com/angular/angular/compare/2.4.1...2.4.2) (2017-01-06)
|
||||||
|
|
||||||
@ -9,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))
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
|
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
|
||||||
|
|
||||||
import {isListLikeIterable} from '../facade/collection';
|
import {isListLikeIterable} from '../facade/collection';
|
||||||
import {isPresent, stringify} from '../facade/lang';
|
import {stringify} from '../facade/lang';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngModule CommonModule
|
* @ngModule CommonModule
|
||||||
@ -134,7 +134,7 @@ export class NgClass implements DoCheck {
|
|||||||
(<any>rawClassVal).forEach((klass: string) => this._toggleClass(klass, !isCleanup));
|
(<any>rawClassVal).forEach((klass: string) => this._toggleClass(klass, !isCleanup));
|
||||||
} else {
|
} else {
|
||||||
Object.keys(rawClassVal).forEach(klass => {
|
Object.keys(rawClassVal).forEach(klass => {
|
||||||
if (isPresent(rawClassVal[klass])) this._toggleClass(klass, !isCleanup);
|
if (rawClassVal[klass] != null) this._toggleClass(klass, !isCleanup);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,9 @@ import {SwitchView} from './ng_switch';
|
|||||||
* @howToUse
|
* @howToUse
|
||||||
* ```
|
* ```
|
||||||
* <some-element [ngPlural]="value">
|
* <some-element [ngPlural]="value">
|
||||||
* <ng-container *ngPluralCase="'=0'">there is nothing</ng-container>
|
* <template ngPluralCase="=0">there is nothing</template>
|
||||||
* <ng-container *ngPluralCase="'=1'">there is one</ng-container>
|
* <template ngPluralCase="=1">there is one</template>
|
||||||
* <ng-container *ngPluralCase="'few'">there are a few</ng-container>
|
* <template ngPluralCase="few">there are a few</template>
|
||||||
* <ng-container *ngPluralCase="'other'">there are exactly #</ng-container>
|
|
||||||
* </some-element>
|
* </some-element>
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
@ -90,8 +89,8 @@ export class NgPlural {
|
|||||||
* @howToUse
|
* @howToUse
|
||||||
* ```
|
* ```
|
||||||
* <some-element [ngPlural]="value">
|
* <some-element [ngPlural]="value">
|
||||||
* <ng-container *ngPluralCase="'=0'">...</ng-container>
|
* <template ngPluralCase="=0">...</template>
|
||||||
* <ng-container *ngPluralCase="'other'">...</ng-container>
|
* <template ngPluralCase="other">...</template>
|
||||||
* </some-element>
|
* </some-element>
|
||||||
*```
|
*```
|
||||||
*
|
*
|
||||||
@ -104,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
import {isBlank} from '../facade/lang';
|
|
||||||
import {NgLocalization, getPluralCategory} from '../localization';
|
import {NgLocalization, getPluralCategory} from '../localization';
|
||||||
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ export class I18nPluralPipe implements PipeTransform {
|
|||||||
constructor(private _localization: NgLocalization) {}
|
constructor(private _localization: NgLocalization) {}
|
||||||
|
|
||||||
transform(value: number, pluralMap: {[count: string]: string}): string {
|
transform(value: number, pluralMap: {[count: string]: string}): string {
|
||||||
if (isBlank(value)) return '';
|
if (value == null) return '';
|
||||||
|
|
||||||
if (typeof pluralMap !== 'object' || pluralMap === null) {
|
if (typeof pluralMap !== 'object' || pluralMap === null) {
|
||||||
throw new InvalidPipeArgumentError(I18nPluralPipe, pluralMap);
|
throw new InvalidPipeArgumentError(I18nPluralPipe, pluralMap);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core';
|
import {Inject, LOCALE_ID, Pipe, PipeTransform, Type} from '@angular/core';
|
||||||
|
|
||||||
import {NumberWrapper, isBlank, isPresent} from '../facade/lang';
|
import {NumberWrapper} from '../facade/lang';
|
||||||
|
|
||||||
import {NumberFormatStyle, NumberFormatter} from './intl';
|
import {NumberFormatStyle, NumberFormatter} from './intl';
|
||||||
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||||
@ -18,7 +18,7 @@ const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
|
|||||||
function formatNumber(
|
function formatNumber(
|
||||||
pipe: Type<any>, locale: string, value: number | string, style: NumberFormatStyle,
|
pipe: Type<any>, locale: string, value: number | string, style: NumberFormatStyle,
|
||||||
digits: string, currency: string = null, currencyAsSymbol: boolean = false): string {
|
digits: string, currency: string = null, currencyAsSymbol: boolean = false): string {
|
||||||
if (isBlank(value)) return null;
|
if (value == null) return null;
|
||||||
|
|
||||||
// Convert strings to numbers
|
// Convert strings to numbers
|
||||||
value = typeof value === 'string' && NumberWrapper.isNumeric(value) ? +value : value;
|
value = typeof value === 'string' && NumberWrapper.isNumeric(value) ? +value : value;
|
||||||
@ -41,13 +41,13 @@ function formatNumber(
|
|||||||
if (parts === null) {
|
if (parts === null) {
|
||||||
throw new Error(`${digits} is not a valid digit info for number pipes`);
|
throw new Error(`${digits} is not a valid digit info for number pipes`);
|
||||||
}
|
}
|
||||||
if (isPresent(parts[1])) { // min integer digits
|
if (parts[1] != null) { // min integer digits
|
||||||
minInt = NumberWrapper.parseIntAutoRadix(parts[1]);
|
minInt = NumberWrapper.parseIntAutoRadix(parts[1]);
|
||||||
}
|
}
|
||||||
if (isPresent(parts[3])) { // min fraction digits
|
if (parts[3] != null) { // min fraction digits
|
||||||
minFraction = NumberWrapper.parseIntAutoRadix(parts[3]);
|
minFraction = NumberWrapper.parseIntAutoRadix(parts[3]);
|
||||||
}
|
}
|
||||||
if (isPresent(parts[5])) { // max fraction digits
|
if (parts[5] != null) { // max fraction digits
|
||||||
maxFraction = NumberWrapper.parseIntAutoRadix(parts[5]);
|
maxFraction = NumberWrapper.parseIntAutoRadix(parts[5]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
import {isBlank} from '../facade/lang';
|
|
||||||
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +57,7 @@ import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
|
|||||||
@Pipe({name: 'slice', pure: false})
|
@Pipe({name: 'slice', pure: false})
|
||||||
export class SlicePipe implements PipeTransform {
|
export class SlicePipe implements PipeTransform {
|
||||||
transform(value: any, start: number, end?: number): any {
|
transform(value: any, start: number, end?: number): any {
|
||||||
if (isBlank(value)) return value;
|
if (value == null) return value;
|
||||||
|
|
||||||
if (!this.supports(value)) {
|
if (!this.supports(value)) {
|
||||||
throw new InvalidPipeArgumentError(SlicePipe, value);
|
throw new InvalidPipeArgumentError(SlicePipe, value);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {Component, ContentChild, TemplateRef} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||||
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
@ -29,10 +29,7 @@ export function main() {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [TestComponent],
|
||||||
TestComponent,
|
|
||||||
ComponentUsingTestComponent,
|
|
||||||
],
|
|
||||||
imports: [CommonModule],
|
imports: [CommonModule],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -77,7 +74,7 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should iterate over an array of objects', async(() => {
|
it('should iterate over an array of objects', async(() => {
|
||||||
const template = '<ul><li template="ngFor let item of items">{{item["name"]}};</li></ul>';
|
const template = '<ul><li *ngFor="let item of items">{{item["name"]}};</li></ul>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
// INIT
|
// INIT
|
||||||
@ -95,7 +92,7 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should gracefully handle nulls', async(() => {
|
it('should gracefully handle nulls', async(() => {
|
||||||
const template = '<ul><li template="ngFor let item of null">{{item}};</li></ul>';
|
const template = '<ul><li *ngFor="let item of null">{{item}};</li></ul>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
detectChangesAndExpectText('');
|
detectChangesAndExpectText('');
|
||||||
@ -140,12 +137,8 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should repeat over nested arrays', async(() => {
|
it('should repeat over nested arrays', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<div *ngFor="let item of items">' +
|
||||||
'<div template="ngFor let item of items">' +
|
'<div *ngFor="let subitem of item">{{subitem}}-{{item.length}};</div>|' +
|
||||||
'<div template="ngFor let subitem of item">' +
|
|
||||||
'{{subitem}}-{{item.length}};' +
|
|
||||||
'</div>|' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>';
|
'</div>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -157,10 +150,9 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should repeat over nested arrays with no intermediate element', async(() => {
|
it('should repeat over nested arrays with no intermediate element', async(() => {
|
||||||
const template = '<div><template ngFor let-item [ngForOf]="items">' +
|
const template = '<div *ngFor="let item of items">' +
|
||||||
'<div template="ngFor let subitem of item">' +
|
'<div *ngFor="let subitem of item">{{subitem}}-{{item.length}};</div>' +
|
||||||
'{{subitem}}-{{item.length}};' +
|
'</div>';
|
||||||
'</div></template></div>';
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [['a', 'b'], ['c']];
|
getComponent().items = [['a', 'b'], ['c']];
|
||||||
@ -170,10 +162,11 @@ export function main() {
|
|||||||
detectChangesAndExpectText('e-1;f-2;g-2;');
|
detectChangesAndExpectText('e-1;f-2;g-2;');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should repeat over nested ngIf that are the last node in the ngFor temlate', async(() => {
|
it('should repeat over nested ngIf that are the last node in the ngFor template', async(() => {
|
||||||
const template =
|
const template = `<div *ngFor="let item of items; let i=index">` +
|
||||||
`<div><template ngFor let-item [ngForOf]="items" let-i="index"><div>{{i}}|</div>` +
|
`<div>{{i}}|</div>` +
|
||||||
`<div *ngIf="i % 2 == 0">even|</div></template></div>`;
|
`<div *ngIf="i % 2 == 0">even|</div>` +
|
||||||
|
`</div>`;
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -189,8 +182,7 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should display indices correctly', async(() => {
|
it('should display indices correctly', async(() => {
|
||||||
const template =
|
const template = '<span *ngFor ="let item of items; let i=index">{{i.toString()}}</span>';
|
||||||
'<div><span template="ngFor: let item of items; let i=index">{{i.toString()}}</span></div>';
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
getComponent().items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
@ -202,7 +194,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should display first item correctly', async(() => {
|
it('should display first item correctly', async(() => {
|
||||||
const template =
|
const template =
|
||||||
'<div><span template="ngFor: let item of items; let isFirst=first">{{isFirst.toString()}}</span></div>';
|
'<span *ngFor="let item of items; let isFirst=first">{{isFirst.toString()}}</span>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [0, 1, 2];
|
getComponent().items = [0, 1, 2];
|
||||||
@ -214,7 +206,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should display last item correctly', async(() => {
|
it('should display last item correctly', async(() => {
|
||||||
const template =
|
const template =
|
||||||
'<div><span template="ngFor: let item of items; let isLast=last">{{isLast.toString()}}</span></div>';
|
'<span *ngFor="let item of items; let isLast=last">{{isLast.toString()}}</span>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [0, 1, 2];
|
getComponent().items = [0, 1, 2];
|
||||||
@ -226,7 +218,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should display even items correctly', async(() => {
|
it('should display even items correctly', async(() => {
|
||||||
const template =
|
const template =
|
||||||
'<div><span template="ngFor: let item of items; let isEven=even">{{isEven.toString()}}</span></div>';
|
'<span *ngFor="let item of items; let isEven=even">{{isEven.toString()}}</span>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [0, 1, 2];
|
getComponent().items = [0, 1, 2];
|
||||||
@ -238,7 +230,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should display odd items correctly', async(() => {
|
it('should display odd items correctly', async(() => {
|
||||||
const template =
|
const template =
|
||||||
'<div><span template="ngFor: let item of items; let isOdd=odd">{{isOdd.toString()}}</span></div>';
|
'<span *ngFor="let item of items; let isOdd=odd">{{isOdd.toString()}}</span>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [0, 1, 2, 3];
|
getComponent().items = [0, 1, 2, 3];
|
||||||
@ -249,55 +241,38 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow to use a custom template', async(() => {
|
it('should allow to use a custom template', async(() => {
|
||||||
const tcTemplate =
|
const template =
|
||||||
'<ul><template ngFor [ngForOf]="items" [ngForTemplate]="contentTpl"></template></ul>';
|
'<ng-container *ngFor="let item of items; template: tpl"></ng-container>' +
|
||||||
TestBed.overrideComponent(TestComponent, {set: {template: tcTemplate}});
|
'<template let-item let-i="index" #tpl><p>{{i}}: {{item}};</p></template>';
|
||||||
const cutTemplate =
|
fixture = createTestComponent(template);
|
||||||
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>';
|
getComponent().items = ['a', 'b', 'c'];
|
||||||
TestBed.overrideComponent(ComponentUsingTestComponent, {set: {template: cutTemplate}});
|
|
||||||
fixture = TestBed.createComponent(ComponentUsingTestComponent);
|
|
||||||
|
|
||||||
const testComponent = fixture.debugElement.children[0];
|
|
||||||
testComponent.componentInstance.items = ['a', 'b', 'c'];
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
|
detectChangesAndExpectText('0: a;1: b;2: c;');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should use a default template if a custom one is null', async(() => {
|
it('should use a default template if a custom one is null', async(() => {
|
||||||
const testTemplate = `<ul><template ngFor let-item [ngForOf]="items"
|
const template =
|
||||||
[ngForTemplate]="contentTpl" let-i="index">{{i}}: {{item}};</template></ul>`;
|
`<ul><ng-container *ngFor="let item of items; template: null; let i=index">{{i}}: {{item}};</ng-container></ul>`;
|
||||||
TestBed.overrideComponent(TestComponent, {set: {template: testTemplate}});
|
fixture = createTestComponent(template);
|
||||||
const cutTemplate =
|
getComponent().items = ['a', 'b', 'c'];
|
||||||
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>';
|
|
||||||
TestBed.overrideComponent(ComponentUsingTestComponent, {set: {template: cutTemplate}});
|
|
||||||
fixture = TestBed.createComponent(ComponentUsingTestComponent);
|
|
||||||
|
|
||||||
const testComponent = fixture.debugElement.children[0];
|
|
||||||
testComponent.componentInstance.items = ['a', 'b', 'c'];
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
|
detectChangesAndExpectText('0: a;1: b;2: c;');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should use a custom template when both default and a custom one are present', async(() => {
|
it('should use a custom template when both default and a custom one are present', async(() => {
|
||||||
const testTemplate = `<ul><template ngFor let-item [ngForOf]="items"
|
const template =
|
||||||
[ngForTemplate]="contentTpl" let-i="index">{{i}}=> {{item}};</template></ul>`;
|
'<ng-container *ngFor="let item of items; template: tpl">{{i}};</ng-container>' +
|
||||||
TestBed.overrideComponent(TestComponent, {set: {template: testTemplate}});
|
'<template let-item let-i="index" #tpl>{{i}}: {{item}};</template>';
|
||||||
const cutTemplate =
|
fixture = createTestComponent(template);
|
||||||
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>';
|
getComponent().items = ['a', 'b', 'c'];
|
||||||
TestBed.overrideComponent(ComponentUsingTestComponent, {set: {template: cutTemplate}});
|
|
||||||
fixture = TestBed.createComponent(ComponentUsingTestComponent);
|
|
||||||
|
|
||||||
const testComponent = fixture.debugElement.children[0];
|
|
||||||
testComponent.componentInstance.items = ['a', 'b', 'c'];
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
|
detectChangesAndExpectText('0: a;1: b;2: c;');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('track by', () => {
|
describe('track by', () => {
|
||||||
it('should console.warn if trackBy is not a function', async(() => {
|
it('should console.warn if trackBy is not a function', async(() => {
|
||||||
// TODO(vicb): expect a warning message when we have a proper log service
|
// TODO(vicb): expect a warning message when we have a proper log service
|
||||||
const template =
|
const template = `<p *ngFor="let item of items; trackBy: value"></p>`;
|
||||||
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="value"></template>`;
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
fixture.componentInstance.value = 0;
|
fixture.componentInstance.value = 0;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -305,8 +280,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should track by identity when trackBy is to `null` or `undefined`', async(() => {
|
it('should track by identity when trackBy is to `null` or `undefined`', async(() => {
|
||||||
// TODO(vicb): expect no warning message when we have a proper log service
|
// TODO(vicb): expect no warning message when we have a proper log service
|
||||||
const template =
|
const template = `<p *ngFor="let item of items; trackBy: value">{{ item }}</p>`;
|
||||||
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="value">{{ item }}</template>`;
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
fixture.componentInstance.items = ['a', 'b', 'c'];
|
fixture.componentInstance.items = ['a', 'b', 'c'];
|
||||||
fixture.componentInstance.value = null;
|
fixture.componentInstance.value = null;
|
||||||
@ -317,7 +291,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should set the context to the component instance', async(() => {
|
it('should set the context to the component instance', async(() => {
|
||||||
const template =
|
const template =
|
||||||
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackByContext.bind(this)"></template>`;
|
`<p *ngFor="let item of items; trackBy: trackByContext.bind(this)"></p>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
thisArg = null;
|
thisArg = null;
|
||||||
@ -327,9 +301,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should not replace tracked items', async(() => {
|
it('should not replace tracked items', async(() => {
|
||||||
const template =
|
const template =
|
||||||
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById" let-i="index">
|
`<p *ngFor="let item of items; trackBy: trackById; let i=index">{{items[i]}}</p>`;
|
||||||
<p>{{items[i]}}</p>
|
|
||||||
</template>`;
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
const buildItemList = () => {
|
const buildItemList = () => {
|
||||||
@ -345,7 +317,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should update implicit local variable on view', async(() => {
|
it('should update implicit local variable on view', async(() => {
|
||||||
const template =
|
const template =
|
||||||
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
|
`<div *ngFor="let item of items; trackBy: trackById">{{item['color']}}</div>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [{'id': 'a', 'color': 'blue'}];
|
getComponent().items = [{'id': 'a', 'color': 'blue'}];
|
||||||
@ -357,7 +329,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should move items around and keep them updated ', async(() => {
|
it('should move items around and keep them updated ', async(() => {
|
||||||
const template =
|
const template =
|
||||||
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
|
`<div *ngFor="let item of items; trackBy: trackById">{{item['color']}}</div>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = [{'id': 'a', 'color': 'blue'}, {'id': 'b', 'color': 'yellow'}];
|
getComponent().items = [{'id': 'a', 'color': 'blue'}, {'id': 'b', 'color': 'yellow'}];
|
||||||
@ -368,8 +340,7 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle added and removed items properly when tracking by index', async(() => {
|
it('should handle added and removed items properly when tracking by index', async(() => {
|
||||||
const template =
|
const template = `<div *ngFor="let item of items; trackBy: trackByIndex">{{item}}</div>`;
|
||||||
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackByIndex">{{item}}</template></div>`;
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().items = ['a', 'b', 'c', 'd'];
|
getComponent().items = ['a', 'b', 'c', 'd'];
|
||||||
@ -389,7 +360,6 @@ class Foo {
|
|||||||
|
|
||||||
@Component({selector: 'test-cmp', template: ''})
|
@Component({selector: 'test-cmp', template: ''})
|
||||||
class TestComponent {
|
class TestComponent {
|
||||||
@ContentChild(TemplateRef) contentTpl: TemplateRef<Object>;
|
|
||||||
value: any;
|
value: any;
|
||||||
items: any[] = [1, 2];
|
items: any[] = [1, 2];
|
||||||
trackById(index: number, item: any): string { return item['id']; }
|
trackById(index: number, item: any): string { return item['id']; }
|
||||||
@ -397,12 +367,7 @@ class TestComponent {
|
|||||||
trackByContext(): void { thisArg = this; }
|
trackByContext(): void { thisArg = this; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'outer-cmp', template: ''})
|
const TEMPLATE = '<div><span *ngFor="let item of items">{{item.toString()}};</span></div>';
|
||||||
class ComponentUsingTestComponent {
|
|
||||||
items: any = [1, 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
const TEMPLATE = '<div><span template="ngFor let item of items">{{item.toString()}};</span></div>';
|
|
||||||
|
|
||||||
function createTestComponent(template: string = TEMPLATE): ComponentFixture<TestComponent> {
|
function createTestComponent(template: string = TEMPLATE): ComponentFixture<TestComponent> {
|
||||||
return TestBed.overrideComponent(TestComponent, {set: {template: template}})
|
return TestBed.overrideComponent(TestComponent, {set: {template: template}})
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||||
|
import {By} from '@angular/platform-browser/src/dom/debug/by';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
|
|
||||||
@ -28,131 +29,114 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should work in a template attribute', async(() => {
|
it('should work in a template attribute', async(() => {
|
||||||
const template = '<div><span template="ngIf booleanCondition">hello</span></div>';
|
const template = '<span *ngIf="booleanCondition">hello</span>';
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(1);
|
||||||
expect(fixture.nativeElement).toHaveText('hello');
|
expect(fixture.nativeElement).toHaveText('hello');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should work in a template element', async(() => {
|
it('should work on a template element', async(() => {
|
||||||
const template =
|
const template = '<template [ngIf]="booleanCondition">hello2</template>';
|
||||||
'<div><template [ngIf]="booleanCondition"><span>hello2</span></template></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
|
||||||
expect(fixture.nativeElement).toHaveText('hello2');
|
expect(fixture.nativeElement).toHaveText('hello2');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should toggle node when condition changes', async(() => {
|
it('should toggle node when condition changes', async(() => {
|
||||||
const template = '<div><span template="ngIf booleanCondition">hello</span></div>';
|
const template = '<span *ngIf="booleanCondition">hello</span>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
getComponent().booleanCondition = false;
|
getComponent().booleanCondition = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(0);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(0);
|
||||||
expect(fixture.nativeElement).toHaveText('');
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
getComponent().booleanCondition = true;
|
getComponent().booleanCondition = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(1);
|
||||||
expect(fixture.nativeElement).toHaveText('hello');
|
expect(fixture.nativeElement).toHaveText('hello');
|
||||||
|
|
||||||
getComponent().booleanCondition = false;
|
getComponent().booleanCondition = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(0);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(0);
|
||||||
expect(fixture.nativeElement).toHaveText('');
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle nested if correctly', async(() => {
|
it('should handle nested if correctly', async(() => {
|
||||||
const template =
|
const template =
|
||||||
'<div><template [ngIf]="booleanCondition"><span *ngIf="nestedBooleanCondition">hello</span></template></div>';
|
'<div *ngIf="booleanCondition"><span *ngIf="nestedBooleanCondition">hello</span></div>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
getComponent().booleanCondition = false;
|
getComponent().booleanCondition = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(0);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(0);
|
||||||
expect(fixture.nativeElement).toHaveText('');
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
getComponent().booleanCondition = true;
|
getComponent().booleanCondition = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(1);
|
||||||
expect(fixture.nativeElement).toHaveText('hello');
|
expect(fixture.nativeElement).toHaveText('hello');
|
||||||
|
|
||||||
getComponent().nestedBooleanCondition = false;
|
getComponent().nestedBooleanCondition = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(0);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(0);
|
||||||
expect(fixture.nativeElement).toHaveText('');
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
getComponent().nestedBooleanCondition = true;
|
getComponent().nestedBooleanCondition = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(1);
|
||||||
expect(fixture.nativeElement).toHaveText('hello');
|
expect(fixture.nativeElement).toHaveText('hello');
|
||||||
|
|
||||||
getComponent().booleanCondition = false;
|
getComponent().booleanCondition = false;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(0);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(0);
|
||||||
expect(fixture.nativeElement).toHaveText('');
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should update several nodes with if', async(() => {
|
it('should update several nodes with if', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<span *ngIf="numberCondition + 1 >= 2">helloNumber</span>' +
|
||||||
'<span template="ngIf numberCondition + 1 >= 2">helloNumber</span>' +
|
'<span *ngIf="stringCondition == \'foo\'">helloString</span>' +
|
||||||
'<span template="ngIf stringCondition == \'foo\'">helloString</span>' +
|
'<span *ngIf="functionCondition(stringCondition, numberCondition)">helloFunction</span>';
|
||||||
'<span template="ngIf functionCondition(stringCondition, numberCondition)">helloFunction</span>' +
|
|
||||||
'</div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(3);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(3);
|
||||||
expect(getDOM().getText(fixture.nativeElement))
|
expect(getDOM().getText(fixture.nativeElement))
|
||||||
.toEqual('helloNumberhelloStringhelloFunction');
|
.toEqual('helloNumberhelloStringhelloFunction');
|
||||||
|
|
||||||
getComponent().numberCondition = 0;
|
getComponent().numberCondition = 0;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(1);
|
||||||
expect(fixture.nativeElement).toHaveText('helloString');
|
expect(fixture.nativeElement).toHaveText('helloString');
|
||||||
|
|
||||||
getComponent().numberCondition = 1;
|
getComponent().numberCondition = 1;
|
||||||
getComponent().stringCondition = 'bar';
|
getComponent().stringCondition = 'bar';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
expect(fixture.debugElement.queryAll(By.css('span')).length).toEqual(1);
|
||||||
expect(fixture.nativeElement).toHaveText('helloNumber');
|
expect(fixture.nativeElement).toHaveText('helloNumber');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not add the element twice if the condition goes from true to true (JS)',
|
it('should not add the element twice if the condition goes from truthy to truthy', async(() => {
|
||||||
async(() => {
|
const template = '<span *ngIf="numberCondition">hello</span>';
|
||||||
const template = '<div><span template="ngIf numberCondition">hello</span></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
let els = fixture.debugElement.queryAll(By.css('span'));
|
||||||
|
expect(els.length).toEqual(1);
|
||||||
|
getDOM().addClass(els[0].nativeElement, 'marker');
|
||||||
expect(fixture.nativeElement).toHaveText('hello');
|
expect(fixture.nativeElement).toHaveText('hello');
|
||||||
|
|
||||||
getComponent().numberCondition = 2;
|
getComponent().numberCondition = 2;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().querySelectorAll(fixture.nativeElement, 'span').length).toEqual(1);
|
els = fixture.debugElement.queryAll(By.css('span'));
|
||||||
|
expect(els.length).toEqual(1);
|
||||||
|
expect(getDOM().hasClass(els[0].nativeElement, 'marker')).toBe(true);
|
||||||
|
|
||||||
expect(fixture.nativeElement).toHaveText('hello');
|
expect(fixture.nativeElement).toHaveText('hello');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not recreate the element if the condition goes from true to true (JS)', async(() => {
|
|
||||||
const template = '<div><span template="ngIf numberCondition">hello</span></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
getDOM().addClass(getDOM().querySelector(fixture.nativeElement, 'span'), 'foo');
|
|
||||||
|
|
||||||
getComponent().numberCondition = 2;
|
|
||||||
fixture.detectChanges();
|
|
||||||
expect(getDOM().hasClass(getDOM().querySelector(fixture.nativeElement, 'span'), 'foo'))
|
|
||||||
.toBe(true);
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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; }
|
||||||
@ -33,10 +33,25 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should display the template according to the exact value', async(() => {
|
it('should display the template according to the exact value', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngPlural]="switchValue">' +
|
||||||
'<ul [ngPlural]="switchValue">' +
|
|
||||||
'<template ngPluralCase="=0"><li>you have no messages.</li></template>' +
|
'<template ngPluralCase="=0"><li>you have no messages.</li></template>' +
|
||||||
'<template ngPluralCase="=1"><li>you have one message.</li></template>' +
|
'<template ngPluralCase="=1"><li>you have one message.</li></template>' +
|
||||||
|
'</ul>';
|
||||||
|
|
||||||
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
|
getComponent().switchValue = 0;
|
||||||
|
detectChangesAndExpectText('you have no messages.');
|
||||||
|
|
||||||
|
getComponent().switchValue = 1;
|
||||||
|
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>';
|
'</ul></div>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
@ -51,10 +66,9 @@ export function main() {
|
|||||||
// 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(() => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngPlural]="switchValue">' +
|
||||||
'<ul [ngPlural]="switchValue">' +
|
|
||||||
'<template ngPluralCase="=0"><li>{{ switchValue }}</li></template>' +
|
'<template ngPluralCase="=0"><li>{{ switchValue }}</li></template>' +
|
||||||
'</ul></div>';
|
'</ul>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -64,11 +78,10 @@ export function main() {
|
|||||||
|
|
||||||
|
|
||||||
it('should be applicable to <ng-container> elements', async(() => {
|
it('should be applicable to <ng-container> elements', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<ng-container [ngPlural]="switchValue">' +
|
||||||
'<ng-container [ngPlural]="switchValue">' +
|
|
||||||
'<template ngPluralCase="=0">you have no messages.</template>' +
|
'<template ngPluralCase="=0">you have no messages.</template>' +
|
||||||
'<template ngPluralCase="=1">you have one message.</template>' +
|
'<template ngPluralCase="=1">you have one message.</template>' +
|
||||||
'</ng-container></div>';
|
'</ng-container>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -80,11 +93,10 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should display the template according to the category', async(() => {
|
it('should display the template according to the category', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngPlural]="switchValue">' +
|
||||||
'<ul [ngPlural]="switchValue">' +
|
|
||||||
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
|
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
|
||||||
'<template ngPluralCase="many"><li>you have many messages.</li></template>' +
|
'<template ngPluralCase="many"><li>you have many messages.</li></template>' +
|
||||||
'</ul></div>';
|
'</ul>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -96,11 +108,10 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should default to other when no matches are found', async(() => {
|
it('should default to other when no matches are found', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngPlural]="switchValue">' +
|
||||||
'<ul [ngPlural]="switchValue">' +
|
|
||||||
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
|
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
|
||||||
'<template ngPluralCase="other"><li>default message.</li></template>' +
|
'<template ngPluralCase="other"><li>default message.</li></template>' +
|
||||||
'</ul></div>';
|
'</ul>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -109,11 +120,10 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should prioritize value matches over category matches', async(() => {
|
it('should prioritize value matches over category matches', async(() => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngPlural]="switchValue">' +
|
||||||
'<ul [ngPlural]="switchValue">' +
|
|
||||||
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
|
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
|
||||||
'<template ngPluralCase="=2">you have two messages.</template>' +
|
'<template ngPluralCase="=2">you have two messages.</template>' +
|
||||||
'</ul></div>';
|
'</ul>';
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
|
@ -29,22 +29,19 @@ export function main() {
|
|||||||
it('should add styles specified in an object literal', async(() => {
|
it('should add styles specified in an object literal', async(() => {
|
||||||
const template = `<div [ngStyle]="{'max-width': '40px'}"></div>`;
|
const template = `<div [ngStyle]="{'max-width': '40px'}"></div>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
|
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should add and change styles specified in an object expression', async(() => {
|
it('should add and change styles specified in an object expression', async(() => {
|
||||||
const template = `<div [ngStyle]="expr"></div>`;
|
const template = `<div [ngStyle]="expr"></div>`;
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
let expr: {[k: string]: string};
|
|
||||||
|
|
||||||
getComponent().expr = {'max-width': '40px'};
|
getComponent().expr = {'max-width': '40px'};
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
|
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
|
||||||
|
|
||||||
expr = getComponent().expr;
|
let expr = getComponent().expr;
|
||||||
expr['max-width'] = '30%';
|
expr['max-width'] = '30%';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expectNativeEl(fixture).toHaveCssStyle({'max-width': '30%'});
|
expectNativeEl(fixture).toHaveCssStyle({'max-width': '30%'});
|
||||||
|
@ -33,11 +33,10 @@ export function main() {
|
|||||||
|
|
||||||
describe('switch value changes', () => {
|
describe('switch value changes', () => {
|
||||||
it('should switch amongst when values', () => {
|
it('should switch amongst when values', () => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngSwitch]="switchValue">' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<li *ngSwitchCase="\'a\'">when a</li>' +
|
||||||
'<template ngSwitchCase="a"><li>when a</li></template>' +
|
'<li *ngSwitchCase="\'b\'">when b</li>' +
|
||||||
'<template ngSwitchCase="b"><li>when b</li></template>' +
|
'</ul>';
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
@ -51,11 +50,10 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should switch amongst when values with fallback to default', () => {
|
it('should switch amongst when values with fallback to default', () => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngSwitch]="switchValue">' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<li *ngSwitchCase="\'a\'">when a</li>' +
|
||||||
'<li template="ngSwitchCase \'a\'">when a</li>' +
|
'<li *ngSwitchDefault>when default</li>' +
|
||||||
'<li template="ngSwitchDefault">when default</li>' +
|
'</ul>';
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
detectChangesAndExpectText('when default');
|
detectChangesAndExpectText('when default');
|
||||||
@ -71,15 +69,14 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should support multiple whens with the same value', () => {
|
it('should support multiple whens with the same value', () => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngSwitch]="switchValue">' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<li *ngSwitchCase="\'a\'">when a1;</li>' +
|
||||||
'<template ngSwitchCase="a"><li>when a1;</li></template>' +
|
'<li *ngSwitchCase="\'b\'">when b1;</li>' +
|
||||||
'<template ngSwitchCase="b"><li>when b1;</li></template>' +
|
'<li *ngSwitchCase="\'a\'">when a2;</li>' +
|
||||||
'<template ngSwitchCase="a"><li>when a2;</li></template>' +
|
'<li *ngSwitchCase="\'b\'">when b2;</li>' +
|
||||||
'<template ngSwitchCase="b"><li>when b2;</li></template>' +
|
'<li *ngSwitchDefault>when default1;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default1;</li></template>' +
|
'<li *ngSwitchDefault>when default2;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default2;</li></template>' +
|
'</ul>';
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
detectChangesAndExpectText('when default1;when default2;');
|
detectChangesAndExpectText('when default1;when default2;');
|
||||||
@ -94,12 +91,11 @@ export function main() {
|
|||||||
|
|
||||||
describe('when values changes', () => {
|
describe('when values changes', () => {
|
||||||
it('should switch amongst when values', () => {
|
it('should switch amongst when values', () => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngSwitch]="switchValue">' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<li *ngSwitchCase="when1">when 1;</li>' +
|
||||||
'<template [ngSwitchCase]="when1"><li>when 1;</li></template>' +
|
'<li *ngSwitchCase="when2">when 2;</li>' +
|
||||||
'<template [ngSwitchCase]="when2"><li>when 2;</li></template>' +
|
'<li *ngSwitchDefault>when default;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default;</li></template>' +
|
'</ul>';
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
getComponent().when1 = 'a';
|
getComponent().when1 = 'a';
|
||||||
@ -148,11 +144,10 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create the default case if there is no other case', () => {
|
it('should create the default case if there is no other case', () => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngSwitch]="switchValue">' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<li *ngSwitchDefault>when default1;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default1;</li></template>' +
|
'<li *ngSwitchDefault>when default2;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default2;</li></template>' +
|
'</ul>';
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
detectChangesAndExpectText('when default1;when default2;');
|
detectChangesAndExpectText('when default1;when default2;');
|
||||||
@ -160,15 +155,14 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should allow defaults before cases', () => {
|
it('should allow defaults before cases', () => {
|
||||||
const template = '<div>' +
|
const template = '<ul [ngSwitch]="switchValue">' +
|
||||||
'<ul [ngSwitch]="switchValue">' +
|
'<li *ngSwitchDefault>when default1;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default1;</li></template>' +
|
'<li *ngSwitchDefault>when default2;</li>' +
|
||||||
'<template ngSwitchDefault><li>when default2;</li></template>' +
|
'<li *ngSwitchCase="\'a\'">when a1;</li>' +
|
||||||
'<template ngSwitchCase="a"><li>when a1;</li></template>' +
|
'<li *ngSwitchCase="\'b\'">when b1;</li>' +
|
||||||
'<template ngSwitchCase="b"><li>when b1;</li></template>' +
|
'<li *ngSwitchCase="\'a\'">when a2;</li>' +
|
||||||
'<template ngSwitchCase="a"><li>when a2;</li></template>' +
|
'<li *ngSwitchCase="\'b\'">when b2;</li>' +
|
||||||
'<template ngSwitchCase="b"><li>when b2;</li></template>' +
|
'</ul>';
|
||||||
'</ul></div>';
|
|
||||||
|
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
detectChangesAndExpectText('when default1;when default2;');
|
detectChangesAndExpectText('when default1;when default2;');
|
||||||
|
@ -34,29 +34,22 @@ export function main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should do nothing if templateRef is null', async(() => {
|
it('should do nothing if templateRef is `null`', async(() => {
|
||||||
const template = `<template [ngTemplateOutlet]="null"></template>`;
|
const template = `<ng-container [ngTemplateOutlet]="null"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
detectChangesAndExpectText('');
|
detectChangesAndExpectText('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should insert content specified by TemplateRef', async(() => {
|
it('should insert content specified by TemplateRef', async(() => {
|
||||||
const template =
|
const template = `<template #tpl>foo</template>` +
|
||||||
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
|
`<ng-container [ngTemplateOutlet]="tpl"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
detectChangesAndExpectText('');
|
|
||||||
|
|
||||||
const refs = fixture.debugElement.children[0].references['refs'];
|
|
||||||
|
|
||||||
setTplRef(refs.tplRefs.first);
|
|
||||||
detectChangesAndExpectText('foo');
|
detectChangesAndExpectText('foo');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should clear content if TemplateRef becomes null', async(() => {
|
it('should clear content if TemplateRef becomes `null`', async(() => {
|
||||||
const template =
|
const template = `<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs>` +
|
||||||
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
|
`<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const refs = fixture.debugElement.children[0].references['refs'];
|
const refs = fixture.debugElement.children[0].references['refs'];
|
||||||
@ -70,7 +63,8 @@ export function main() {
|
|||||||
|
|
||||||
it('should swap content if TemplateRef changes', async(() => {
|
it('should swap content if TemplateRef changes', async(() => {
|
||||||
const template =
|
const template =
|
||||||
`<tpl-refs #refs="tplRefs"><template>foo</template><template>bar</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
|
`<tpl-refs #refs="tplRefs"><template>foo</template><template>bar</template></tpl-refs>` +
|
||||||
|
`<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
@ -83,70 +77,47 @@ export function main() {
|
|||||||
detectChangesAndExpectText('bar');
|
detectChangesAndExpectText('bar');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should display template if context is null', async(() => {
|
it('should display template if context is `null`', async(() => {
|
||||||
const template =
|
const template = `<template #tpl>foo</template>` +
|
||||||
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="null"></template>`;
|
`<ng-container [ngTemplateOutlet]="tpl" [ngOutletContext]="null"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
detectChangesAndExpectText('');
|
|
||||||
|
|
||||||
const refs = fixture.debugElement.children[0].references['refs'];
|
|
||||||
|
|
||||||
setTplRef(refs.tplRefs.first);
|
|
||||||
detectChangesAndExpectText('foo');
|
detectChangesAndExpectText('foo');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should reflect initial context and changes', async(() => {
|
it('should reflect initial context and changes', async(() => {
|
||||||
const template =
|
const template = `<template let-foo="foo" #tpl>{{foo}}</template>` +
|
||||||
`<tpl-refs #refs="tplRefs"><template let-foo="foo"><span>{{foo}}</span></template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="context"></template>`;
|
`<ng-container [ngTemplateOutlet]="tpl" [ngOutletContext]="context"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const refs = fixture.debugElement.children[0].references['refs'];
|
|
||||||
setTplRef(refs.tplRefs.first);
|
|
||||||
|
|
||||||
detectChangesAndExpectText('bar');
|
detectChangesAndExpectText('bar');
|
||||||
|
|
||||||
fixture.componentInstance.context.foo = 'alter-bar';
|
fixture.componentInstance.context.foo = 'alter-bar';
|
||||||
|
|
||||||
detectChangesAndExpectText('alter-bar');
|
detectChangesAndExpectText('alter-bar');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should reflect user defined $implicit property in the context', async(() => {
|
it('should reflect user defined `$implicit` property in the context', async(() => {
|
||||||
const template =
|
const template = `<template let-ctx #tpl>{{ctx.foo}}</template>` +
|
||||||
`<tpl-refs #refs="tplRefs"><template let-ctx><span>{{ctx.foo}}</span></template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="context"></template>`;
|
`<ng-container [ngTemplateOutlet]="tpl" [ngOutletContext]="context"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
fixture.componentInstance.context = {$implicit: {foo: 'bra'}};
|
||||||
fixture.detectChanges();
|
detectChangesAndExpectText('bra');
|
||||||
|
|
||||||
const refs = fixture.debugElement.children[0].references['refs'];
|
|
||||||
setTplRef(refs.tplRefs.first);
|
|
||||||
|
|
||||||
fixture.componentInstance.context = {$implicit: fixture.componentInstance.context};
|
|
||||||
detectChangesAndExpectText('bar');
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should reflect context re-binding', async(() => {
|
it('should reflect context re-binding', async(() => {
|
||||||
const template =
|
const template = `<template let-shawshank="shawshank" #tpl>{{shawshank}}</template>` +
|
||||||
`<tpl-refs #refs="tplRefs"><template let-shawshank="shawshank"><span>{{shawshank}}</span></template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="context"></template>`;
|
`<ng-container [ngTemplateOutlet]="tpl" [ngOutletContext]="context"></ng-container>`;
|
||||||
fixture = createTestComponent(template);
|
fixture = createTestComponent(template);
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
const refs = fixture.debugElement.children[0].references['refs'];
|
|
||||||
setTplRef(refs.tplRefs.first);
|
|
||||||
fixture.componentInstance.context = {shawshank: 'brooks'};
|
fixture.componentInstance.context = {shawshank: 'brooks'};
|
||||||
|
|
||||||
detectChangesAndExpectText('brooks');
|
detectChangesAndExpectText('brooks');
|
||||||
|
|
||||||
fixture.componentInstance.context = {shawshank: 'was here'};
|
fixture.componentInstance.context = {shawshank: 'was here'};
|
||||||
|
|
||||||
detectChangesAndExpectText('was here');
|
detectChangesAndExpectText('was here');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
|
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
|
||||||
class CaptureTplRefs {
|
class CaptureTplRefs {
|
||||||
@ContentChildren(TemplateRef) tplRefs: QueryList<TemplateRef<any>>;
|
@ContentChildren(TemplateRef) tplRefs: QueryList<TemplateRef<any>>;
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
import {RouterModule} from '@angular/router';
|
||||||
|
|
||||||
|
@Component({selector: 'lazy-feature-comp', template: 'lazy feature, nested!'})
|
||||||
|
export class LazyFeatureNestedComponent {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild([
|
||||||
|
{path: '', component: LazyFeatureNestedComponent, pathMatch: 'full'},
|
||||||
|
])],
|
||||||
|
declarations: [LazyFeatureNestedComponent]
|
||||||
|
})
|
||||||
|
export class LazyFeatureNestedModule {
|
||||||
|
}
|
@ -16,7 +16,10 @@ export class LazyFeatureComponent {
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild([
|
imports: [RouterModule.forChild([
|
||||||
{path: '', component: LazyFeatureComponent, pathMatch: 'full'},
|
{path: '', component: LazyFeatureComponent, pathMatch: 'full'},
|
||||||
{path: 'feature', loadChildren: './feature.module#FeatureModule'}
|
{path: 'feature', loadChildren: './feature.module#FeatureModule'}, {
|
||||||
|
path: 'nested-feature',
|
||||||
|
loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule'
|
||||||
|
}
|
||||||
])],
|
])],
|
||||||
declarations: [LazyFeatureComponent]
|
declarations: [LazyFeatureComponent]
|
||||||
})
|
})
|
||||||
|
@ -191,6 +191,8 @@ function lazyRoutesTest() {
|
|||||||
'./lazy.module#LazyModule': 'lazy.module.ts',
|
'./lazy.module#LazyModule': 'lazy.module.ts',
|
||||||
'./feature/feature.module#FeatureModule': 'feature/feature.module.ts',
|
'./feature/feature.module#FeatureModule': 'feature/feature.module.ts',
|
||||||
'./feature/lazy-feature.module#LazyFeatureModule': 'feature/lazy-feature.module.ts',
|
'./feature/lazy-feature.module#LazyFeatureModule': 'feature/lazy-feature.module.ts',
|
||||||
|
'./feature.module#FeatureModule': 'feature/feature.module.ts',
|
||||||
|
'./lazy-feature-nested.module#LazyFeatureNestedModule': 'feature/lazy-feature-nested.module.ts',
|
||||||
'feature2/feature2.module#Feature2Module': 'feature2/feature2.module.ts',
|
'feature2/feature2.module#Feature2Module': 'feature2/feature2.module.ts',
|
||||||
'./default.module': 'feature2/default.module.ts',
|
'./default.module': 'feature2/default.module.ts',
|
||||||
'feature/feature.module#FeatureModule': 'feature/feature.module.ts'
|
'feature/feature.module#FeatureModule': 'feature/feature.module.ts'
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"ng-xi18n": "./src/extract_i18n.js"
|
"ng-xi18n": "./src/extract_i18n.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/tsc-wrapped": "0.5.0",
|
"@angular/tsc-wrapped": "0.5.1",
|
||||||
"reflect-metadata": "^0.1.2",
|
"reflect-metadata": "^0.1.2",
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
},
|
},
|
||||||
|
@ -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 {
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
import {AotCompilerHost, StaticReflector, StaticSymbol} from '@angular/compiler';
|
import {AotCompilerHost, StaticReflector, StaticSymbol} from '@angular/compiler';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// We cannot depend directly to @angular/router.
|
// We cannot depend directly to @angular/router.
|
||||||
type Route = any;
|
type Route = any;
|
||||||
const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader';
|
const ROUTER_MODULE_PATH = '@angular/router/src/router_config_loader';
|
||||||
@ -63,29 +61,37 @@ export function listLazyRoutesOfModule(
|
|||||||
const className = entryRouteDef.className;
|
const className = entryRouteDef.className;
|
||||||
|
|
||||||
// List loadChildren of this single module.
|
// List loadChildren of this single module.
|
||||||
const staticSymbol = reflector.findDeclaration(modulePath, className, containingFile);
|
const appStaticSymbol = reflector.findDeclaration(modulePath, className, containingFile);
|
||||||
const ROUTES = reflector.findDeclaration(ROUTER_MODULE_PATH, ROUTER_ROUTES_SYMBOL_NAME);
|
const ROUTES = reflector.findDeclaration(ROUTER_MODULE_PATH, ROUTER_ROUTES_SYMBOL_NAME);
|
||||||
const lazyRoutes: LazyRoute[] =
|
const lazyRoutes: LazyRoute[] =
|
||||||
_extractLazyRoutesFromStaticModule(staticSymbol, reflector, host, ROUTES);
|
_extractLazyRoutesFromStaticModule(appStaticSymbol, reflector, host, ROUTES);
|
||||||
const routes: LazyRouteMap = {};
|
|
||||||
|
|
||||||
lazyRoutes.forEach((lazyRoute: LazyRoute) => {
|
const allLazyRoutes = lazyRoutes.reduce(
|
||||||
|
function includeLazyRouteAndSubRoutes(allRoutes: LazyRouteMap, lazyRoute: LazyRoute):
|
||||||
|
LazyRouteMap {
|
||||||
const route: string = lazyRoute.routeDef.toString();
|
const route: string = lazyRoute.routeDef.toString();
|
||||||
_assertRoute(routes, lazyRoute);
|
_assertRoute(allRoutes, lazyRoute);
|
||||||
routes[route] = lazyRoute;
|
allRoutes[route] = lazyRoute;
|
||||||
|
|
||||||
|
// StaticReflector does not support discovering annotations like `NgModule` on default
|
||||||
|
// exports
|
||||||
|
// Which means: if a default export NgModule was lazy-loaded, we can discover it, but,
|
||||||
|
// we cannot parse its routes to see if they have loadChildren or not.
|
||||||
|
if (!lazyRoute.routeDef.className) {
|
||||||
|
return allRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
const lazyModuleSymbol = reflector.findDeclaration(
|
const lazyModuleSymbol = reflector.findDeclaration(
|
||||||
lazyRoute.absoluteFilePath, lazyRoute.routeDef.className || 'default');
|
lazyRoute.absoluteFilePath, lazyRoute.routeDef.className || 'default');
|
||||||
const subRoutes = _extractLazyRoutesFromStaticModule(lazyModuleSymbol, reflector, host, ROUTES);
|
|
||||||
|
|
||||||
// Populate the map using the routes we just found.
|
const subRoutes =
|
||||||
subRoutes.forEach(subRoute => {
|
_extractLazyRoutesFromStaticModule(lazyModuleSymbol, reflector, host, ROUTES);
|
||||||
_assertRoute(routes, subRoute);
|
|
||||||
routes[subRoute.routeDef.toString()] = subRoute;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return routes;
|
return subRoutes.reduce(includeLazyRouteAndSubRoutes, allRoutes);
|
||||||
|
},
|
||||||
|
{});
|
||||||
|
|
||||||
|
return allLazyRoutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -192,7 +198,7 @@ function _collectRoutes(
|
|||||||
*/
|
*/
|
||||||
function _collectLoadChildren(routes: Route[]): string[] {
|
function _collectLoadChildren(routes: Route[]): string[] {
|
||||||
return routes.reduce((m, r) => {
|
return routes.reduce((m, r) => {
|
||||||
if (r.loadChildren) {
|
if (r.loadChildren && typeof r.loadChildren === 'string') {
|
||||||
return m.concat(r.loadChildren);
|
return m.concat(r.loadChildren);
|
||||||
} else if (Array.isArray(r)) {
|
} else if (Array.isArray(r)) {
|
||||||
return m.concat(_collectLoadChildren(r));
|
return m.concat(_collectLoadChildren(r));
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {SchemaMetadata} from '@angular/core';
|
|
||||||
|
|
||||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
import {AnimationCompiler} from '../animation/animation_compiler';
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from '../animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileTypeSummary, createHostComponentMeta, identifierModuleUrl, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, CompileTypeSummary, createHostComponentMeta, identifierModuleUrl, identifierName} from '../compile_metadata';
|
||||||
|
@ -10,8 +10,8 @@ import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, Ho
|
|||||||
|
|
||||||
import {ReflectorReader} from '../private_import_core';
|
import {ReflectorReader} from '../private_import_core';
|
||||||
|
|
||||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol} from './static_symbol';
|
||||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
import {StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
|
|
||||||
const ANGULAR_IMPORT_LOCATIONS = {
|
const ANGULAR_IMPORT_LOCATIONS = {
|
||||||
coreDecorators: '@angular/core/src/metadata',
|
coreDecorators: '@angular/core/src/metadata',
|
||||||
@ -310,6 +310,7 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
if (value && (depth != 0 || value.__symbolic != 'error')) {
|
||||||
const parameters: string[] = targetFunction['parameters'];
|
const parameters: string[] = targetFunction['parameters'];
|
||||||
const defaults: any[] = targetFunction.defaults;
|
const defaults: any[] = targetFunction.defaults;
|
||||||
|
args = args.map(arg => simplifyInContext(context, arg, depth + 1));
|
||||||
if (defaults && defaults.length > args.length) {
|
if (defaults && defaults.length > args.length) {
|
||||||
args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
|
args.push(...defaults.slice(args.length).map((value: any) => simplify(value)));
|
||||||
}
|
}
|
||||||
@ -499,15 +500,15 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
const argExpressions: any[] = expression['arguments'] || [];
|
const argExpressions: any[] = expression['arguments'] || [];
|
||||||
const args =
|
|
||||||
argExpressions.map(arg => simplifyInContext(context, arg, depth + 1));
|
|
||||||
let converter = self.conversionMap.get(staticSymbol);
|
let converter = self.conversionMap.get(staticSymbol);
|
||||||
if (converter) {
|
if (converter) {
|
||||||
|
const args =
|
||||||
|
argExpressions.map(arg => simplifyInContext(context, arg, depth + 1));
|
||||||
return converter(context, args);
|
return converter(context, args);
|
||||||
} else {
|
} else {
|
||||||
// Determine if the function is one we can simplify.
|
// Determine if the function is one we can simplify.
|
||||||
const targetFunction = resolveReferenceValue(staticSymbol);
|
const targetFunction = resolveReferenceValue(staticSymbol);
|
||||||
return simplifyCall(staticSymbol, targetFunction, args);
|
return simplifyCall(staticSymbol, targetFunction, argExpressions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -651,10 +652,6 @@ class PopulatedScope extends BindingScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sameSymbol(a: StaticSymbol, b: StaticSymbol): boolean {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function shouldIgnore(value: any): boolean {
|
function shouldIgnore(value: any): boolean {
|
||||||
return value && value.__symbolic == 'ignore';
|
return value && value.__symbolic == 'ignore';
|
||||||
}
|
}
|
||||||
|
@ -5,7 +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
|
||||||
*/
|
*/
|
||||||
import {CompileSummaryKind, CompileTypeSummary} from '../compile_metadata';
|
|
||||||
import {Summary, SummaryResolver} from '../summary_resolver';
|
import {Summary, SummaryResolver} from '../summary_resolver';
|
||||||
|
|
||||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||||
|
@ -5,16 +5,16 @@
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
import {CompileDirectiveSummary, CompileIdentifierMetadata, CompileNgModuleSummary, CompilePipeSummary, CompileSummaryKind, CompileTypeMetadata, CompileTypeSummary, identifierModuleUrl, identifierName} from '../compile_metadata';
|
import {CompileNgModuleSummary, CompileSummaryKind, CompileTypeSummary} from '../compile_metadata';
|
||||||
import {Summary, SummaryResolver} from '../summary_resolver';
|
import {Summary, SummaryResolver} from '../summary_resolver';
|
||||||
import {ValueTransformer, visitValue} from '../util';
|
import {ValueTransformer, visitValue} from '../util';
|
||||||
|
|
||||||
import {GeneratedFile} from './generated_file';
|
|
||||||
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
import {StaticSymbol, StaticSymbolCache} from './static_symbol';
|
||||||
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
import {ResolvedStaticSymbol, StaticSymbolResolver} from './static_symbol_resolver';
|
||||||
|
|
||||||
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
const STRIP_SRC_FILE_SUFFIXES = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
|
|
||||||
|
|
||||||
export interface AotSummarySerializerHost {
|
export interface AotSummarySerializerHost {
|
||||||
/**
|
/**
|
||||||
* Returns the output file path of a source file.
|
* Returns the output file path of a source file.
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Identifiers, createIdentifier} from '../identifiers';
|
import {Identifiers, createIdentifier} from '../identifiers';
|
||||||
import {ClassBuilder} from '../output/class_builder';
|
import {ClassBuilder} from '../output/class_builder';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import * as cdAst from '../expression_parser/ast';
|
import * as cdAst from '../expression_parser/ast';
|
||||||
import {isBlank, isPresent} from '../facade/lang';
|
import {isBlank} from '../facade/lang';
|
||||||
import {Identifiers, createIdentifier} from '../identifiers';
|
import {Identifiers, createIdentifier} from '../identifiers';
|
||||||
import {ClassBuilder} from '../output/class_builder';
|
import {ClassBuilder} from '../output/class_builder';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
@ -338,7 +338,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
const receiver = this.visit(ast.receiver, _Mode.Expression);
|
const receiver = this.visit(ast.receiver, _Mode.Expression);
|
||||||
if (receiver === this._implicitReceiver) {
|
if (receiver === this._implicitReceiver) {
|
||||||
const varExpr = this._getLocal(ast.name);
|
const varExpr = this._getLocal(ast.name);
|
||||||
if (isPresent(varExpr)) {
|
if (varExpr) {
|
||||||
result = varExpr.callFn(args);
|
result = varExpr.callFn(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
const receiver: o.Expression = this.visit(ast.receiver, _Mode.Expression);
|
const receiver: o.Expression = this.visit(ast.receiver, _Mode.Expression);
|
||||||
if (receiver === this._implicitReceiver) {
|
if (receiver === this._implicitReceiver) {
|
||||||
const varExpr = this._getLocal(ast.name);
|
const varExpr = this._getLocal(ast.name);
|
||||||
if (isPresent(varExpr)) {
|
if (varExpr) {
|
||||||
throw new Error('Cannot assign to a reference or variable!');
|
throw new Error('Cannot assign to a reference or variable!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {Component, ViewEncapsulation} from '@angular/core';
|
import {Component, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {CompileAnimationEntryMetadata, CompileDirectiveMetadata, CompileStylesheetMetadata, CompileTemplateMetadata, CompileTypeMetadata} from './compile_metadata';
|
import {CompileAnimationEntryMetadata, CompileDirectiveMetadata, CompileStylesheetMetadata, CompileTemplateMetadata} from './compile_metadata';
|
||||||
import {CompilerConfig} from './config';
|
import {CompilerConfig} from './config';
|
||||||
import {isBlank, isPresent, stringify} from './facade/lang';
|
import {isBlank, isPresent, stringify} from './facade/lang';
|
||||||
import {CompilerInjectable} from './injectable';
|
import {CompilerInjectable} from './injectable';
|
||||||
|
@ -14,8 +14,6 @@ import {CompilerInjectable} from './injectable';
|
|||||||
import {ReflectorReader, reflector} from './private_import_core';
|
import {ReflectorReader, reflector} from './private_import_core';
|
||||||
import {splitAtColon} from './util';
|
import {splitAtColon} from './util';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resolve a `Type` for {@link Directive}.
|
* Resolve a `Type` for {@link Directive}.
|
||||||
*
|
*
|
||||||
|
@ -128,7 +128,6 @@ class DirectiveWrapperBuilder implements ClassBuilder {
|
|||||||
new o.ClassMethod('ngOnDestroy', [], this.destroyStmts),
|
new o.ClassMethod('ngOnDestroy', [], this.destroyStmts),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const fields: o.ClassField[] = [
|
const fields: o.ClassField[] = [
|
||||||
new o.ClassField(EVENT_HANDLER_FIELD_NAME, o.FUNCTION_TYPE, [o.StmtModifier.Private]),
|
new o.ClassField(EVENT_HANDLER_FIELD_NAME, o.FUNCTION_TYPE, [o.StmtModifier.Private]),
|
||||||
new o.ClassField(CONTEXT_FIELD_NAME, o.importType(this.dirMeta.type)),
|
new o.ClassField(CONTEXT_FIELD_NAME, o.importType(this.dirMeta.type)),
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as chars from '../chars';
|
import * as chars from '../chars';
|
||||||
import {NumberWrapper, isPresent} from '../facade/lang';
|
import {NumberWrapper} from '../facade/lang';
|
||||||
import {CompilerInjectable} from '../injectable';
|
import {CompilerInjectable} from '../injectable';
|
||||||
|
|
||||||
export enum TokenType {
|
export enum TokenType {
|
||||||
@ -241,7 +241,7 @@ class _Scanner {
|
|||||||
this.advance();
|
this.advance();
|
||||||
str += two;
|
str += two;
|
||||||
}
|
}
|
||||||
if (isPresent(threeCode) && this.peek == threeCode) {
|
if (threeCode != null && this.peek == threeCode) {
|
||||||
this.advance();
|
this.advance();
|
||||||
str += three;
|
str += three;
|
||||||
}
|
}
|
||||||
|
@ -53,20 +53,22 @@ enum _VisitorMode {
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
class _Visitor implements html.Visitor {
|
class _Visitor implements html.Visitor {
|
||||||
|
private _depth: number;
|
||||||
|
|
||||||
// <el i18n>...</el>
|
// <el i18n>...</el>
|
||||||
private _inI18nNode: boolean;
|
private _inI18nNode: boolean;
|
||||||
private _depth: number;
|
|
||||||
private _inImplicitNode: boolean;
|
private _inImplicitNode: boolean;
|
||||||
|
|
||||||
// <!--i18n-->...<!--/i18n-->
|
// <!--i18n-->...<!--/i18n-->
|
||||||
|
private _inI18nBlock: boolean;
|
||||||
private _blockMeaningAndDesc: string;
|
private _blockMeaningAndDesc: string;
|
||||||
private _blockChildren: html.Node[];
|
private _blockChildren: html.Node[];
|
||||||
private _blockStartDepth: number;
|
private _blockStartDepth: number;
|
||||||
private _inI18nBlock: boolean;
|
|
||||||
|
|
||||||
// {<icu message>}
|
// {<icu message>}
|
||||||
private _inIcu: boolean;
|
private _inIcu: boolean;
|
||||||
|
|
||||||
|
// set to void 0 when not in a section
|
||||||
private _msgCountAtSectionStart: number;
|
private _msgCountAtSectionStart: number;
|
||||||
private _errors: I18nError[];
|
private _errors: I18nError[];
|
||||||
private _mode: _VisitorMode;
|
private _mode: _VisitorMode;
|
||||||
@ -208,50 +210,31 @@ class _Visitor implements html.Visitor {
|
|||||||
this._depth++;
|
this._depth++;
|
||||||
const wasInI18nNode = this._inI18nNode;
|
const wasInI18nNode = this._inI18nNode;
|
||||||
const wasInImplicitNode = this._inImplicitNode;
|
const wasInImplicitNode = this._inImplicitNode;
|
||||||
let childNodes: html.Node[];
|
let childNodes: html.Node[] = [];
|
||||||
|
let translatedChildNodes: html.Node[];
|
||||||
|
|
||||||
// Extract only top level nodes with the (implicit) "i18n" attribute if not in a block or an ICU
|
// Extract:
|
||||||
// message
|
// - top level nodes with the (implicit) "i18n" attribute if not already in a section
|
||||||
|
// - ICU messages
|
||||||
const i18nAttr = _getI18nAttr(el);
|
const i18nAttr = _getI18nAttr(el);
|
||||||
|
const i18nMeta = i18nAttr ? i18nAttr.value : '';
|
||||||
const isImplicit = this._implicitTags.some(tag => el.name === tag) && !this._inIcu &&
|
const isImplicit = this._implicitTags.some(tag => el.name === tag) && !this._inIcu &&
|
||||||
!this._isInTranslatableSection;
|
!this._isInTranslatableSection;
|
||||||
const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
|
const isTopLevelImplicit = !wasInImplicitNode && isImplicit;
|
||||||
this._inImplicitNode = this._inImplicitNode || isImplicit;
|
this._inImplicitNode = wasInImplicitNode || isImplicit;
|
||||||
|
|
||||||
if (!this._isInTranslatableSection && !this._inIcu) {
|
if (!this._isInTranslatableSection && !this._inIcu) {
|
||||||
if (i18nAttr) {
|
if (i18nAttr || isTopLevelImplicit) {
|
||||||
// explicit translation
|
|
||||||
this._inI18nNode = true;
|
this._inI18nNode = true;
|
||||||
const message = this._addMessage(el.children, i18nAttr.value);
|
const message = this._addMessage(el.children, i18nMeta);
|
||||||
childNodes = this._translateMessage(el, message);
|
translatedChildNodes = this._translateMessage(el, message);
|
||||||
} else if (isTopLevelImplicit) {
|
|
||||||
// implicit translation
|
|
||||||
this._inI18nNode = true;
|
|
||||||
const message = this._addMessage(el.children);
|
|
||||||
childNodes = this._translateMessage(el, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._mode == _VisitorMode.Extract) {
|
if (this._mode == _VisitorMode.Extract) {
|
||||||
const isTranslatable = i18nAttr || isTopLevelImplicit;
|
const isTranslatable = i18nAttr || isTopLevelImplicit;
|
||||||
if (isTranslatable) {
|
if (isTranslatable) this._openTranslatableSection(el);
|
||||||
this._openTranslatableSection(el);
|
|
||||||
}
|
|
||||||
html.visitAll(this, el.children);
|
html.visitAll(this, el.children);
|
||||||
if (isTranslatable) {
|
if (isTranslatable) this._closeTranslatableSection(el, el.children);
|
||||||
this._closeTranslatableSection(el, el.children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._mode === _VisitorMode.Merge && !i18nAttr && !isTopLevelImplicit) {
|
|
||||||
childNodes = [];
|
|
||||||
el.children.forEach(child => {
|
|
||||||
const visited = child.visit(this, context);
|
|
||||||
if (visited && !this._isInTranslatableSection) {
|
|
||||||
// Do not add the children from translatable sections (= i18n blocks here)
|
|
||||||
// They will be added when the section is close (i.e. on `<!-- /i18n -->`)
|
|
||||||
childNodes = childNodes.concat(visited);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i18nAttr || isTopLevelImplicit) {
|
if (i18nAttr || isTopLevelImplicit) {
|
||||||
@ -263,20 +246,19 @@ class _Visitor implements html.Visitor {
|
|||||||
// Descend into child nodes for extraction
|
// Descend into child nodes for extraction
|
||||||
html.visitAll(this, el.children);
|
html.visitAll(this, el.children);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this._mode == _VisitorMode.Merge) {
|
if (this._mode === _VisitorMode.Merge) {
|
||||||
// Translate attributes in ICU messages
|
const visitNodes = translatedChildNodes || el.children;
|
||||||
childNodes = [];
|
visitNodes.forEach(child => {
|
||||||
el.children.forEach(child => {
|
|
||||||
const visited = child.visit(this, context);
|
const visited = child.visit(this, context);
|
||||||
if (visited && !this._isInTranslatableSection) {
|
if (visited && !this._isInTranslatableSection) {
|
||||||
// Do not add the children from translatable sections (= i18n blocks here)
|
// Do not add the children from translatable sections (= i18n blocks here)
|
||||||
// They will be added when the section is close (i.e. on `<!-- /i18n -->`)
|
// They will be added later in this loop when the block closes (i.e. on `<!-- /i18n -->`)
|
||||||
childNodes = childNodes.concat(visited);
|
childNodes = childNodes.concat(visited);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this._visitAttributesOf(el);
|
this._visitAttributesOf(el);
|
||||||
|
|
||||||
@ -285,7 +267,6 @@ class _Visitor implements html.Visitor {
|
|||||||
this._inImplicitNode = wasInImplicitNode;
|
this._inImplicitNode = wasInImplicitNode;
|
||||||
|
|
||||||
if (this._mode === _VisitorMode.Merge) {
|
if (this._mode === _VisitorMode.Merge) {
|
||||||
// There are no childNodes in translatable sections - those nodes will be replace anyway
|
|
||||||
const translatedAttrs = this._translateAttributes(el);
|
const translatedAttrs = this._translateAttributes(el);
|
||||||
return new html.Element(
|
return new html.Element(
|
||||||
el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan,
|
el.name, translatedAttrs, childNodes, el.sourceSpan, el.startSourceSpan,
|
||||||
@ -432,7 +413,7 @@ class _Visitor implements html.Visitor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A translatable section could be:
|
* A translatable section could be:
|
||||||
* - a translatable element,
|
* - the content of translatable element,
|
||||||
* - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments
|
* - nodes between `<!-- i18n -->` and `<!-- /i18n -->` comments
|
||||||
*/
|
*/
|
||||||
private get _isInTranslatableSection(): boolean {
|
private get _isInTranslatableSection(): boolean {
|
||||||
|
@ -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 {ANALYZE_FOR_ENTRY_COMPONENTS, AnimationTransitionEvent, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {StaticSymbol} from './aot/static_symbol';
|
import {StaticSymbol} from './aot/static_symbol';
|
||||||
import {CompileIdentifierMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
|
import {CompileIdentifierMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
|
||||||
|
@ -283,7 +283,7 @@ class _TreeBuilder {
|
|||||||
const tagDef = this.getTagDefinition(el.name);
|
const tagDef = this.getTagDefinition(el.name);
|
||||||
const {parent, container} = this._getParentElementSkippingContainers();
|
const {parent, container} = this._getParentElementSkippingContainers();
|
||||||
|
|
||||||
if (isPresent(parent) && tagDef.requireExtraParent(parent.name)) {
|
if (parent && tagDef.requireExtraParent(parent.name)) {
|
||||||
const newParent = new html.Element(
|
const newParent = new html.Element(
|
||||||
tagDef.parentToAdd, [], [], el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
|
tagDef.parentToAdd, [], [], el.sourceSpan, el.startSourceSpan, el.endSourceSpan);
|
||||||
this._insertBeforeContainer(parent, container, newParent);
|
this._insertBeforeContainer(parent, container, newParent);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName, tokenName, tokenReference} from './compile_metadata';
|
import {CompileDiDependencyMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompileProviderMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName, tokenName, tokenReference} from './compile_metadata';
|
||||||
import {createDiTokenExpression} from './compiler_util/identifier_util';
|
import {createDiTokenExpression} from './compiler_util/identifier_util';
|
||||||
import {isPresent} from './facade/lang';
|
import {isPresent} from './facade/lang';
|
||||||
import {Identifiers, createIdentifier, createIdentifierToken, resolveIdentifier} from './identifiers';
|
import {Identifiers, createIdentifier, resolveIdentifier} from './identifiers';
|
||||||
import {CompilerInjectable} from './injectable';
|
import {CompilerInjectable} from './injectable';
|
||||||
import {ClassBuilder, createClassStmt} from './output/class_builder';
|
import {ClassBuilder, createClassStmt} from './output/class_builder';
|
||||||
import * as o from './output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {NgModule, Type} from '@angular/core';
|
import {NgModule, Type} from '@angular/core';
|
||||||
|
|
||||||
import {ListWrapper} from './facade/collection';
|
import {ListWrapper} from './facade/collection';
|
||||||
import {isPresent, stringify} from './facade/lang';
|
import {stringify} from './facade/lang';
|
||||||
import {CompilerInjectable} from './injectable';
|
import {CompilerInjectable} from './injectable';
|
||||||
import {ReflectorReader, reflector} from './private_import_core';
|
import {ReflectorReader, reflector} from './private_import_core';
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export class NgModuleResolver {
|
|||||||
const ngModuleMeta: NgModule =
|
const ngModuleMeta: NgModule =
|
||||||
ListWrapper.findLast(this._reflector.annotations(type), _isNgModuleMetadata);
|
ListWrapper.findLast(this._reflector.annotations(type), _isNgModuleMetadata);
|
||||||
|
|
||||||
if (isPresent(ngModuleMeta)) {
|
if (ngModuleMeta) {
|
||||||
return ngModuleMeta;
|
return ngModuleMeta;
|
||||||
} else {
|
} else {
|
||||||
if (throwIfNotFound) {
|
if (throwIfNotFound) {
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {CompileIdentifierMetadata} from '../compile_metadata';
|
|
||||||
import {ValueTransformer, visitValue} from '../util';
|
import {ValueTransformer, visitValue} from '../util';
|
||||||
|
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {Pipe, Type, resolveForwardRef} from '@angular/core';
|
import {Pipe, Type, resolveForwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {ListWrapper} from './facade/collection';
|
import {ListWrapper} from './facade/collection';
|
||||||
import {isPresent, stringify} from './facade/lang';
|
import {stringify} from './facade/lang';
|
||||||
import {CompilerInjectable} from './injectable';
|
import {CompilerInjectable} from './injectable';
|
||||||
import {ReflectorReader, reflector} from './private_import_core';
|
import {ReflectorReader, reflector} from './private_import_core';
|
||||||
|
|
||||||
@ -38,9 +38,9 @@ export class PipeResolver {
|
|||||||
*/
|
*/
|
||||||
resolve(type: Type<any>, throwIfNotFound = true): Pipe {
|
resolve(type: Type<any>, throwIfNotFound = true): Pipe {
|
||||||
const metas = this._reflector.annotations(resolveForwardRef(type));
|
const metas = this._reflector.annotations(resolveForwardRef(type));
|
||||||
if (isPresent(metas)) {
|
if (metas) {
|
||||||
const annotation = ListWrapper.findLast(metas, _isPipeMetadata);
|
const annotation = ListWrapper.findLast(metas, _isPipeMetadata);
|
||||||
if (isPresent(annotation)) {
|
if (annotation) {
|
||||||
return annotation;
|
return annotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenName, tokenReference} from './compile_metadata';
|
import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenName, tokenReference} from './compile_metadata';
|
||||||
import {isBlank, isPresent} from './facade/lang';
|
import {isBlank, isPresent} from './facade/lang';
|
||||||
import {Identifiers, createIdentifierToken, resolveIdentifier} from './identifiers';
|
import {Identifiers, resolveIdentifier} from './identifiers';
|
||||||
import {ParseError, ParseSourceSpan} from './parse_util';
|
import {ParseError, ParseSourceSpan} from './parse_util';
|
||||||
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst} from './template_parser/template_ast';
|
import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, ReferenceAst} from './template_parser/template_ast';
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ export class ProviderElementContext {
|
|||||||
let queries: CompileQueryMetadata[];
|
let queries: CompileQueryMetadata[];
|
||||||
while (currentEl !== null) {
|
while (currentEl !== null) {
|
||||||
queries = currentEl._contentQueries.get(tokenReference(token));
|
queries = currentEl._contentQueries.get(tokenReference(token));
|
||||||
if (isPresent(queries)) {
|
if (queries) {
|
||||||
result.push(...queries.filter((query) => query.descendants || distance <= 1));
|
result.push(...queries.filter((query) => query.descendants || distance <= 1));
|
||||||
}
|
}
|
||||||
if (currentEl._directiveAsts.length > 0) {
|
if (currentEl._directiveAsts.length > 0) {
|
||||||
@ -123,7 +123,7 @@ export class ProviderElementContext {
|
|||||||
currentEl = currentEl._parent;
|
currentEl = currentEl._parent;
|
||||||
}
|
}
|
||||||
queries = this.viewContext.viewQueries.get(tokenReference(token));
|
queries = this.viewContext.viewQueries.get(tokenReference(token));
|
||||||
if (isPresent(queries)) {
|
if (queries) {
|
||||||
result.push(...queries);
|
result.push(...queries);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -143,7 +143,7 @@ export class ProviderElementContext {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
|
let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
|
||||||
if (isPresent(transformedProviderAst)) {
|
if (transformedProviderAst) {
|
||||||
return transformedProviderAst;
|
return transformedProviderAst;
|
||||||
}
|
}
|
||||||
if (isPresent(this._seenProviders.get(tokenReference(token)))) {
|
if (isPresent(this._seenProviders.get(tokenReference(token)))) {
|
||||||
@ -165,11 +165,11 @@ export class ProviderElementContext {
|
|||||||
transformedUseExisting = null;
|
transformedUseExisting = null;
|
||||||
transformedUseValue = existingDiDep.value;
|
transformedUseValue = existingDiDep.value;
|
||||||
}
|
}
|
||||||
} else if (isPresent(provider.useFactory)) {
|
} else if (provider.useFactory) {
|
||||||
const deps = provider.deps || provider.useFactory.diDeps;
|
const deps = provider.deps || provider.useFactory.diDeps;
|
||||||
transformedDeps =
|
transformedDeps =
|
||||||
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
|
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
|
||||||
} else if (isPresent(provider.useClass)) {
|
} else if (provider.useClass) {
|
||||||
const deps = provider.deps || provider.useClass.diDeps;
|
const deps = provider.deps || provider.useClass.diDeps;
|
||||||
transformedDeps =
|
transformedDeps =
|
||||||
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
|
deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager));
|
||||||
@ -235,7 +235,7 @@ export class ProviderElementContext {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check parent elements
|
// check parent elements
|
||||||
while (!result && isPresent(currElement._parent)) {
|
while (!result && currElement._parent) {
|
||||||
const prevElement = currElement;
|
const prevElement = currElement;
|
||||||
currElement = currElement._parent;
|
currElement = currElement._parent;
|
||||||
if (prevElement._isViewRoot) {
|
if (prevElement._isViewRoot) {
|
||||||
@ -301,7 +301,7 @@ export class NgModuleProviderAnalyzer {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
|
let transformedProviderAst = this._transformedProviders.get(tokenReference(token));
|
||||||
if (isPresent(transformedProviderAst)) {
|
if (transformedProviderAst) {
|
||||||
return transformedProviderAst;
|
return transformedProviderAst;
|
||||||
}
|
}
|
||||||
if (isPresent(this._seenProviders.get(tokenReference(token)))) {
|
if (isPresent(this._seenProviders.get(tokenReference(token)))) {
|
||||||
@ -324,11 +324,11 @@ export class NgModuleProviderAnalyzer {
|
|||||||
transformedUseExisting = null;
|
transformedUseExisting = null;
|
||||||
transformedUseValue = existingDiDep.value;
|
transformedUseValue = existingDiDep.value;
|
||||||
}
|
}
|
||||||
} else if (isPresent(provider.useFactory)) {
|
} else if (provider.useFactory) {
|
||||||
const deps = provider.deps || provider.useFactory.diDeps;
|
const deps = provider.deps || provider.useFactory.diDeps;
|
||||||
transformedDeps =
|
transformedDeps =
|
||||||
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
|
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
|
||||||
} else if (isPresent(provider.useClass)) {
|
} else if (provider.useClass) {
|
||||||
const deps = provider.deps || provider.useClass.diDeps;
|
const deps = provider.deps || provider.useClass.diDeps;
|
||||||
transformedDeps =
|
transformedDeps =
|
||||||
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
|
deps.map((dep) => this._getDependency(dep, eager, resolvedProvider.sourceSpan));
|
||||||
@ -454,7 +454,7 @@ function _resolveProviders(
|
|||||||
|
|
||||||
function _getViewQueries(component: CompileDirectiveMetadata): Map<any, CompileQueryMetadata[]> {
|
function _getViewQueries(component: CompileDirectiveMetadata): Map<any, CompileQueryMetadata[]> {
|
||||||
const viewQueries = new Map<any, CompileQueryMetadata[]>();
|
const viewQueries = new Map<any, CompileQueryMetadata[]>();
|
||||||
if (isPresent(component.viewQueries)) {
|
if (component.viewQueries) {
|
||||||
component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, query));
|
component.viewQueries.forEach((query) => _addQueryToTokenMap(viewQueries, query));
|
||||||
}
|
}
|
||||||
return viewQueries;
|
return viewQueries;
|
||||||
@ -464,7 +464,7 @@ function _getContentQueries(directives: CompileDirectiveSummary[]):
|
|||||||
Map<any, CompileQueryMetadata[]> {
|
Map<any, CompileQueryMetadata[]> {
|
||||||
const contentQueries = new Map<any, CompileQueryMetadata[]>();
|
const contentQueries = new Map<any, CompileQueryMetadata[]>();
|
||||||
directives.forEach(directive => {
|
directives.forEach(directive => {
|
||||||
if (isPresent(directive.queries)) {
|
if (directive.queries) {
|
||||||
directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, query));
|
directive.queries.forEach((query) => _addQueryToTokenMap(contentQueries, query));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,6 @@ import {SecurityContext} from '@angular/core';
|
|||||||
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
|
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
|
||||||
import {ASTWithSource, BindingPipe, EmptyExpr, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
|
import {ASTWithSource, BindingPipe, EmptyExpr, ParserError, RecursiveAstVisitor, TemplateBinding} from '../expression_parser/ast';
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from '../expression_parser/parser';
|
||||||
import {isPresent} from '../facade/lang';
|
|
||||||
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
||||||
import {mergeNsAndName} from '../ml_parser/tags';
|
import {mergeNsAndName} from '../ml_parser/tags';
|
||||||
import {ParseError, ParseErrorLevel, ParseSourceSpan} from '../parse_util';
|
import {ParseError, ParseErrorLevel, ParseSourceSpan} from '../parse_util';
|
||||||
@ -111,14 +110,14 @@ export class BindingParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseInlineTemplateBinding(
|
parseInlineTemplateBinding(
|
||||||
name: string, prefixToken: string, value: string, sourceSpan: ParseSourceSpan,
|
prefixToken: string, value: string, sourceSpan: ParseSourceSpan,
|
||||||
targetMatchableAttrs: string[][], targetProps: BoundProperty[], targetVars: VariableAst[]) {
|
targetMatchableAttrs: string[][], targetProps: BoundProperty[], targetVars: VariableAst[]) {
|
||||||
const bindings = this._parseTemplateBindings(prefixToken, value, sourceSpan);
|
const bindings = this._parseTemplateBindings(prefixToken, value, sourceSpan);
|
||||||
for (let i = 0; i < bindings.length; i++) {
|
for (let i = 0; i < bindings.length; i++) {
|
||||||
const binding = bindings[i];
|
const binding = bindings[i];
|
||||||
if (binding.keyIsVar) {
|
if (binding.keyIsVar) {
|
||||||
targetVars.push(new VariableAst(binding.key, binding.name, sourceSpan));
|
targetVars.push(new VariableAst(binding.key, binding.name, sourceSpan));
|
||||||
} else if (isPresent(binding.expression)) {
|
} else if (binding.expression) {
|
||||||
this._parsePropertyAst(
|
this._parsePropertyAst(
|
||||||
binding.key, binding.expression, sourceSpan, targetMatchableAttrs, targetProps);
|
binding.key, binding.expression, sourceSpan, targetMatchableAttrs, targetProps);
|
||||||
} else {
|
} else {
|
||||||
@ -136,7 +135,7 @@ export class BindingParser {
|
|||||||
const bindingsResult = this._exprParser.parseTemplateBindings(prefixToken, value, sourceInfo);
|
const bindingsResult = this._exprParser.parseTemplateBindings(prefixToken, value, sourceInfo);
|
||||||
this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
|
this._reportExpressionParserErrors(bindingsResult.errors, sourceSpan);
|
||||||
bindingsResult.templateBindings.forEach((binding) => {
|
bindingsResult.templateBindings.forEach((binding) => {
|
||||||
if (isPresent(binding.expression)) {
|
if (binding.expression) {
|
||||||
this._checkPipes(binding.expression, sourceSpan);
|
this._checkPipes(binding.expression, sourceSpan);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -193,7 +192,7 @@ export class BindingParser {
|
|||||||
name: string, value: string, sourceSpan: ParseSourceSpan, targetMatchableAttrs: string[][],
|
name: string, value: string, sourceSpan: ParseSourceSpan, targetMatchableAttrs: string[][],
|
||||||
targetProps: BoundProperty[]): boolean {
|
targetProps: BoundProperty[]): boolean {
|
||||||
const expr = this.parseInterpolation(value, sourceSpan);
|
const expr = this.parseInterpolation(value, sourceSpan);
|
||||||
if (isPresent(expr)) {
|
if (expr) {
|
||||||
this._parsePropertyAst(name, expr, sourceSpan, targetMatchableAttrs, targetProps);
|
this._parsePropertyAst(name, expr, sourceSpan, targetMatchableAttrs, targetProps);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -374,7 +373,7 @@ export class BindingParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan) {
|
private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan) {
|
||||||
if (isPresent(ast)) {
|
if (ast) {
|
||||||
const collector = new PipeCollector();
|
const collector = new PipeCollector();
|
||||||
ast.visit(collector);
|
ast.visit(collector);
|
||||||
collector.pipes.forEach((ast, pipeName) => {
|
collector.pipes.forEach((ast, pipeName) => {
|
||||||
|
@ -276,7 +276,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
templateBindingsSource = attr.value;
|
templateBindingsSource = attr.value;
|
||||||
} else if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
} else if (normalizedName.startsWith(TEMPLATE_ATTR_PREFIX)) {
|
||||||
templateBindingsSource = attr.value;
|
templateBindingsSource = attr.value;
|
||||||
prefixToken = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length);
|
prefixToken = normalizedName.substring(TEMPLATE_ATTR_PREFIX.length) + ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasTemplateBinding = isPresent(templateBindingsSource);
|
const hasTemplateBinding = isPresent(templateBindingsSource);
|
||||||
@ -288,7 +288,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
}
|
}
|
||||||
hasInlineTemplates = true;
|
hasInlineTemplates = true;
|
||||||
this._bindingParser.parseInlineTemplateBinding(
|
this._bindingParser.parseInlineTemplateBinding(
|
||||||
attr.name, prefixToken, templateBindingsSource, attr.sourceSpan, templateMatchableAttrs,
|
prefixToken, templateBindingsSource, attr.sourceSpan, templateMatchableAttrs,
|
||||||
templateElementOrDirectiveProps, templateElementVars);
|
templateElementOrDirectiveProps, templateElementVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,9 +309,11 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
const elementProps: BoundElementPropertyAst[] =
|
const elementProps: BoundElementPropertyAst[] =
|
||||||
this._createElementPropertyAsts(element.name, elementOrDirectiveProps, directiveAsts);
|
this._createElementPropertyAsts(element.name, elementOrDirectiveProps, directiveAsts);
|
||||||
const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
const isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
||||||
|
|
||||||
const providerContext = new ProviderElementContext(
|
const providerContext = new ProviderElementContext(
|
||||||
this.providerViewContext, parent.providerContext, isViewRoot, directiveAsts, attrs,
|
this.providerViewContext, parent.providerContext, isViewRoot, directiveAsts, attrs,
|
||||||
references, element.sourceSpan);
|
references, element.sourceSpan);
|
||||||
|
|
||||||
const children = html.visitAll(
|
const children = html.visitAll(
|
||||||
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
||||||
ElementContext.create(
|
ElementContext.create(
|
||||||
|
@ -19,7 +19,7 @@ import {ProviderAst, ProviderAstType, ReferenceAst, TemplateAst} from '../templa
|
|||||||
import {CompileMethod} from './compile_method';
|
import {CompileMethod} from './compile_method';
|
||||||
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
import {CompileQuery, addQueryToTokenMap, createQueryList} from './compile_query';
|
||||||
import {CompileView, CompileViewRootNode} from './compile_view';
|
import {CompileView, CompileViewRootNode} from './compile_view';
|
||||||
import {InjectMethodVars, ViewProperties} from './constants';
|
import {InjectMethodVars} from './constants';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency} from './deps';
|
import {ComponentFactoryDependency, DirectiveWrapperDependency} from './deps';
|
||||||
import {getPropertyInView, injectFromViewParentInjector} from './util';
|
import {getPropertyInView, injectFromViewParentInjector} from './util';
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ export class CompileElement extends CompileNode {
|
|||||||
const propName =
|
const propName =
|
||||||
`_${tokenName(resolvedProvider.token)}_${this.nodeIndex}_${this.instances.size}`;
|
`_${tokenName(resolvedProvider.token)}_${this.nodeIndex}_${this.instances.size}`;
|
||||||
const instance = createProviderProperty(
|
const instance = createProviderProperty(
|
||||||
propName, resolvedProvider, providerValueExpressions, resolvedProvider.multiProvider,
|
propName, providerValueExpressions, resolvedProvider.multiProvider,
|
||||||
resolvedProvider.eager, this);
|
resolvedProvider.eager, this);
|
||||||
if (isDirectiveWrapper) {
|
if (isDirectiveWrapper) {
|
||||||
this.directiveWrapperInstance.set(tokenReference(resolvedProvider.token), instance);
|
this.directiveWrapperInstance.set(tokenReference(resolvedProvider.token), instance);
|
||||||
@ -289,7 +289,7 @@ export class CompileElement extends CompileNode {
|
|||||||
CompileQuery {
|
CompileQuery {
|
||||||
const propName =
|
const propName =
|
||||||
`_query_${tokenName(queryMeta.selectors[0])}_${this.nodeIndex}_${this._queryCount++}`;
|
`_query_${tokenName(queryMeta.selectors[0])}_${this.nodeIndex}_${this._queryCount++}`;
|
||||||
const queryList = createQueryList(queryMeta, directiveInstance, propName, this.view);
|
const queryList = createQueryList(propName, this.view);
|
||||||
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this.view);
|
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this.view);
|
||||||
addQueryToTokenMap(this._queries, query);
|
addQueryToTokenMap(this._queries, query);
|
||||||
return query;
|
return query;
|
||||||
@ -369,8 +369,8 @@ function createInjectInternalCondition(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createProviderProperty(
|
function createProviderProperty(
|
||||||
propName: string, provider: ProviderAst, providerValueExpressions: o.Expression[],
|
propName: string, providerValueExpressions: o.Expression[], isMulti: boolean, isEager: boolean,
|
||||||
isMulti: boolean, isEager: boolean, compileElement: CompileElement): o.Expression {
|
compileElement: CompileElement): o.Expression {
|
||||||
const view = compileElement.view;
|
const view = compileElement.view;
|
||||||
let resolvedProviderValueExpr: o.Expression;
|
let resolvedProviderValueExpr: o.Expression;
|
||||||
let type: o.Type;
|
let type: o.Type;
|
||||||
|
@ -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 {isPresent} from '../facade/lang';
|
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {TemplateAst} from '../template_parser/template_ast';
|
import {TemplateAst} from '../template_parser/template_ast';
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ export class CompileMethod {
|
|||||||
if (this._newState.nodeIndex !== this._currState.nodeIndex ||
|
if (this._newState.nodeIndex !== this._currState.nodeIndex ||
|
||||||
this._newState.sourceAst !== this._currState.sourceAst) {
|
this._newState.sourceAst !== this._currState.sourceAst) {
|
||||||
const expr = this._updateDebugContext(this._newState);
|
const expr = this._updateDebugContext(this._newState);
|
||||||
if (isPresent(expr)) {
|
if (expr) {
|
||||||
this._bodyStatements.push(expr.toStmt());
|
this._bodyStatements.push(expr.toStmt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,13 +42,12 @@ export class CompileMethod {
|
|||||||
private _updateDebugContext(newState: _DebugState): o.Expression {
|
private _updateDebugContext(newState: _DebugState): o.Expression {
|
||||||
this._currState = this._newState = newState;
|
this._currState = this._newState = newState;
|
||||||
if (this._debugEnabled) {
|
if (this._debugEnabled) {
|
||||||
const sourceLocation =
|
const sourceLocation = newState.sourceAst ? newState.sourceAst.sourceSpan.start : null;
|
||||||
isPresent(newState.sourceAst) ? newState.sourceAst.sourceSpan.start : null;
|
|
||||||
|
|
||||||
return o.THIS_EXPR.callMethod('debug', [
|
return o.THIS_EXPR.callMethod('debug', [
|
||||||
o.literal(newState.nodeIndex),
|
o.literal(newState.nodeIndex),
|
||||||
isPresent(sourceLocation) ? o.literal(sourceLocation.line) : o.NULL_EXPR,
|
sourceLocation ? o.literal(sourceLocation.line) : o.NULL_EXPR,
|
||||||
isPresent(sourceLocation) ? o.literal(sourceLocation.col) : o.NULL_EXPR
|
sourceLocation ? o.literal(sourceLocation.col) : o.NULL_EXPR
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {CompileQueryMetadata, tokenReference} from '../compile_metadata';
|
import {CompileQueryMetadata, tokenReference} from '../compile_metadata';
|
||||||
import {ListWrapper} from '../facade/collection';
|
import {ListWrapper} from '../facade/collection';
|
||||||
import {isPresent} from '../facade/lang';
|
|
||||||
import {Identifiers, createIdentifier} from '../identifiers';
|
import {Identifiers, createIdentifier} from '../identifiers';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
@ -33,7 +32,7 @@ export class CompileQuery {
|
|||||||
addValue(value: o.Expression, view: CompileView) {
|
addValue(value: o.Expression, view: CompileView) {
|
||||||
let currentView = view;
|
let currentView = view;
|
||||||
const elPath: CompileElement[] = [];
|
const elPath: CompileElement[] = [];
|
||||||
while (isPresent(currentView) && currentView !== this.view) {
|
while (currentView && currentView !== this.view) {
|
||||||
const parentEl = currentView.declarationElement;
|
const parentEl = currentView.declarationElement;
|
||||||
elPath.unshift(parentEl);
|
elPath.unshift(parentEl);
|
||||||
currentView = parentEl.view;
|
currentView = parentEl.view;
|
||||||
@ -67,7 +66,7 @@ export class CompileQuery {
|
|||||||
generateStatements(targetStaticMethod: CompileMethod, targetDynamicMethod: CompileMethod) {
|
generateStatements(targetStaticMethod: CompileMethod, targetDynamicMethod: CompileMethod) {
|
||||||
const values = createQueryValues(this._values);
|
const values = createQueryValues(this._values);
|
||||||
const updateStmts = [this.queryList.callMethod('reset', [o.literalArr(values)]).toStmt()];
|
const updateStmts = [this.queryList.callMethod('reset', [o.literalArr(values)]).toStmt()];
|
||||||
if (isPresent(this.ownerDirectiveExpression)) {
|
if (this.ownerDirectiveExpression) {
|
||||||
const valueExpr = this.meta.first ? this.queryList.prop('first') : this.queryList;
|
const valueExpr = this.meta.first ? this.queryList.prop('first') : this.queryList;
|
||||||
updateStmts.push(
|
updateStmts.push(
|
||||||
this.ownerDirectiveExpression.prop(this.meta.propertyName).set(valueExpr).toStmt());
|
this.ownerDirectiveExpression.prop(this.meta.propertyName).set(valueExpr).toStmt());
|
||||||
@ -110,9 +109,7 @@ function mapNestedViews(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createQueryList(
|
export function createQueryList(propertyName: string, compileView: CompileView): o.Expression {
|
||||||
query: CompileQueryMetadata, directiveInstance: o.Expression, propertyName: string,
|
|
||||||
compileView: CompileView): o.Expression {
|
|
||||||
compileView.fields.push(new o.ClassField(
|
compileView.fields.push(new o.ClassField(
|
||||||
propertyName, o.importType(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE])));
|
propertyName, o.importType(createIdentifier(Identifiers.QueryList), [o.DYNAMIC_TYPE])));
|
||||||
const expr = o.THIS_EXPR.prop(propertyName);
|
const expr = o.THIS_EXPR.prop(propertyName);
|
||||||
|
@ -12,7 +12,6 @@ import {EventHandlerVars, NameResolver} from '../compiler_util/expression_conver
|
|||||||
import {createPureProxy} from '../compiler_util/identifier_util';
|
import {createPureProxy} from '../compiler_util/identifier_util';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from '../config';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {Identifiers, createIdentifier} from '../identifiers';
|
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {ViewType} from '../private_import_core';
|
import {ViewType} from '../private_import_core';
|
||||||
|
|
||||||
@ -119,7 +118,7 @@ export class CompileView implements NameResolver {
|
|||||||
const directiveInstance = o.THIS_EXPR.prop('context');
|
const directiveInstance = o.THIS_EXPR.prop('context');
|
||||||
this.component.viewQueries.forEach((queryMeta, queryIndex) => {
|
this.component.viewQueries.forEach((queryMeta, queryIndex) => {
|
||||||
const propName = `_viewQuery_${tokenName(queryMeta.selectors[0])}_${queryIndex}`;
|
const propName = `_viewQuery_${tokenName(queryMeta.selectors[0])}_${queryIndex}`;
|
||||||
const queryList = createQueryList(queryMeta, directiveInstance, propName, this);
|
const queryList = createQueryList(propName, this);
|
||||||
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this);
|
const query = new CompileQuery(queryMeta, queryList, directiveInstance, this);
|
||||||
addQueryToTokenMap(viewQueries, query);
|
addQueryToTokenMap(viewQueries, query);
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core';
|
|||||||
import {createEnumExpression} from '../compiler_util/identifier_util';
|
import {createEnumExpression} from '../compiler_util/identifier_util';
|
||||||
import {Identifiers} from '../identifiers';
|
import {Identifiers} from '../identifiers';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {ChangeDetectorStatus, ViewType} from '../private_import_core';
|
import {ViewType} from '../private_import_core';
|
||||||
|
|
||||||
export class ViewTypeEnum {
|
export class ViewTypeEnum {
|
||||||
static fromValue(value: ViewType): o.Expression {
|
static fromValue(value: ViewType): o.Expression {
|
||||||
@ -25,12 +25,6 @@ export class ViewEncapsulationEnum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChangeDetectionStrategyEnum {
|
|
||||||
static fromValue(value: ChangeDetectionStrategy): o.Expression {
|
|
||||||
return createEnumExpression(Identifiers.ChangeDetectionStrategy, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ChangeDetectorStatusEnum {
|
export class ChangeDetectorStatusEnum {
|
||||||
static fromValue(value: ChangeDetectorStatusEnum): o.Expression {
|
static fromValue(value: ChangeDetectorStatusEnum): o.Expression {
|
||||||
return createEnumExpression(Identifiers.ChangeDetectorStatus, value);
|
return createEnumExpression(Identifiers.ChangeDetectorStatus, value);
|
||||||
|
@ -15,7 +15,6 @@ import {BoundEventAst, DirectiveAst} from '../template_parser/template_ast';
|
|||||||
|
|
||||||
import {CompileElement} from './compile_element';
|
import {CompileElement} from './compile_element';
|
||||||
import {CompileMethod} from './compile_method';
|
import {CompileMethod} from './compile_method';
|
||||||
import {ViewProperties} from './constants';
|
|
||||||
import {getHandleEventMethodName} from './util';
|
import {getHandleEventMethodName} from './util';
|
||||||
|
|
||||||
export function bindOutputs(
|
export function bindOutputs(
|
||||||
|
@ -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 {CompileQueryMetadata, CompileTokenMetadata, tokenReference} from '../compile_metadata';
|
import {CompileTokenMetadata, tokenReference} from '../compile_metadata';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
|
|
||||||
import {CompileElement} from './compile_element';
|
import {CompileElement} from './compile_element';
|
||||||
@ -17,16 +17,18 @@ import {CompileQuery} from './compile_query';
|
|||||||
// as we create embedded views before the <template> elements themselves.
|
// as we create embedded views before the <template> elements themselves.
|
||||||
export function bindQueryValues(ce: CompileElement) {
|
export function bindQueryValues(ce: CompileElement) {
|
||||||
const queriesWithReads: _QueryWithRead[] = [];
|
const queriesWithReads: _QueryWithRead[] = [];
|
||||||
|
|
||||||
ce.getProviderTokens().forEach((token) => {
|
ce.getProviderTokens().forEach((token) => {
|
||||||
const queriesForProvider = ce.getQueriesFor(token);
|
const queriesForProvider = ce.getQueriesFor(token);
|
||||||
queriesWithReads.push(...queriesForProvider.map(query => new _QueryWithRead(query, token)));
|
queriesWithReads.push(...queriesForProvider.map(query => new _QueryWithRead(query, token)));
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.keys(ce.referenceTokens).forEach(varName => {
|
Object.keys(ce.referenceTokens).forEach(varName => {
|
||||||
const token = ce.referenceTokens[varName];
|
|
||||||
const varToken = {value: varName};
|
const varToken = {value: varName};
|
||||||
queriesWithReads.push(
|
queriesWithReads.push(
|
||||||
...ce.getQueriesFor(varToken).map(query => new _QueryWithRead(query, varToken)));
|
...ce.getQueriesFor(varToken).map(query => new _QueryWithRead(query, varToken)));
|
||||||
});
|
});
|
||||||
|
|
||||||
queriesWithReads.forEach((queryWithRead) => {
|
queriesWithReads.forEach((queryWithRead) => {
|
||||||
let value: o.Expression;
|
let value: o.Expression;
|
||||||
if (queryWithRead.read.identifier) {
|
if (queryWithRead.read.identifier) {
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
|
|
||||||
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileTokenMetadata, identifierName} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, CompileTokenMetadata, identifierName} from '../compile_metadata';
|
||||||
import {createDiTokenExpression} from '../compiler_util/identifier_util';
|
import {createDiTokenExpression} from '../compiler_util/identifier_util';
|
||||||
import {isPresent} from '../facade/lang';
|
|
||||||
import {Identifiers, createIdentifier} from '../identifiers';
|
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {ViewType} from '../private_import_core';
|
import {ViewType} from '../private_import_core';
|
||||||
|
|
||||||
@ -23,7 +21,7 @@ export function getPropertyInView(
|
|||||||
} else {
|
} else {
|
||||||
let viewProp: o.Expression = o.THIS_EXPR;
|
let viewProp: o.Expression = o.THIS_EXPR;
|
||||||
let currView: CompileView = callingView;
|
let currView: CompileView = callingView;
|
||||||
while (currView !== definedView && isPresent(currView.declarationElement.view)) {
|
while (currView !== definedView && currView.declarationElement.view) {
|
||||||
currView = currView.declarationElement.view;
|
currView = currView.declarationElement.view;
|
||||||
viewProp = viewProp.prop('parentView');
|
viewProp = viewProp.prop('parentView');
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import {isPresent} from '../facade/lang';
|
|||||||
import {Identifiers, createIdentifier, identifierToken} from '../identifiers';
|
import {Identifiers, createIdentifier, identifierToken} from '../identifiers';
|
||||||
import {createClassStmt} from '../output/class_builder';
|
import {createClassStmt} from '../output/class_builder';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from '../output/output_ast';
|
||||||
import {ParseSourceSpan} from '../parse_util';
|
|
||||||
import {ChangeDetectorStatus, ViewType, isDefaultChangeDetectionStrategy} from '../private_import_core';
|
import {ChangeDetectorStatus, ViewType, isDefaultChangeDetectionStrategy} from '../private_import_core';
|
||||||
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
|
import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast';
|
||||||
|
|
||||||
@ -405,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))));
|
||||||
}
|
}
|
||||||
@ -695,7 +695,6 @@ function generateCreateEmbeddedViewsMethod(view: CompileView): o.ClassMethod {
|
|||||||
view.nodes.forEach((node) => {
|
view.nodes.forEach((node) => {
|
||||||
if (node instanceof CompileElement) {
|
if (node instanceof CompileElement) {
|
||||||
if (node.embeddedView) {
|
if (node.embeddedView) {
|
||||||
const parentNodeIndex = node.isRootElement() ? null : node.parent.nodeIndex;
|
|
||||||
stmts.push(new o.IfStmt(
|
stmts.push(new o.IfStmt(
|
||||||
nodeIndexVar.equals(o.literal(node.nodeIndex)),
|
nodeIndexVar.equals(o.literal(node.nodeIndex)),
|
||||||
[new o.ReturnStatement(node.embeddedView.classExpr.instantiate([
|
[new o.ReturnStatement(node.embeddedView.classExpr.instantiate([
|
||||||
|
@ -449,6 +449,40 @@ describe('StaticReflector', () => {
|
|||||||
expect(annotations[0].providers[0].useValue.members[0]).toEqual('staticMethod');
|
expect(annotations[0].providers[0].useValue.members[0]).toEqual('staticMethod');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// #13605
|
||||||
|
it('should not throw on unknown decorators', () => {
|
||||||
|
const data = Object.create(DEFAULT_TEST_DATA);
|
||||||
|
const file = '/tmp/src/app.component.ts';
|
||||||
|
data[file] = `
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
export const enum TypeEnum {
|
||||||
|
type
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MyValidationDecorator(p1: any, p2: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ValidationFunction(a1: any): any {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-app',
|
||||||
|
template: "<h1>Hello {{name}}</h1>",
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
name = 'Angular';
|
||||||
|
|
||||||
|
@MyValidationDecorator( TypeEnum.type, ValidationFunction({option: 'value'}))
|
||||||
|
myClassProp: number;
|
||||||
|
}`;
|
||||||
|
init(data);
|
||||||
|
const appComponent = reflector.getStaticSymbol(file, 'AppComponent');
|
||||||
|
expect(() => reflector.propMetadata(appComponent)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
describe('inheritance', () => {
|
describe('inheritance', () => {
|
||||||
class ClassDecorator {
|
class ClassDecorator {
|
||||||
constructor(public value: any) {}
|
constructor(public value: any) {}
|
||||||
|
@ -210,5 +210,56 @@ const XMB = `
|
|||||||
<ph name="START_TAG_DIV_1"><ex><div></ex></ph><ph name="ICU"/><ph name="CLOSE_TAG_DIV"><ex></div></ex></ph>
|
<ph name="START_TAG_DIV_1"><ex><div></ex></ph><ph name="ICU"/><ph name="CLOSE_TAG_DIV"><ex></div></ex></ph>
|
||||||
</msg>
|
</msg>
|
||||||
<msg id="1491627405349178954">it <ph name="START_BOLD_TEXT"><ex><b></ex></ph>should<ph name="CLOSE_BOLD_TEXT"><ex></b></ex></ph> work</msg>
|
<msg id="1491627405349178954">it <ph name="START_BOLD_TEXT"><ex><b></ex></ph>should<ph name="CLOSE_BOLD_TEXT"><ex></b></ex></ph> work</msg>
|
||||||
</messagebundle>
|
</messagebundle>`;
|
||||||
|
|
||||||
|
const HTML = `
|
||||||
|
<div>
|
||||||
|
<h1 i18n>i18n attribute on tags</h1>
|
||||||
|
|
||||||
|
<div id="i18n-1"><p i18n>nested</p></div>
|
||||||
|
|
||||||
|
<div id="i18n-2"><p i18n="different meaning|">nested</p></div>
|
||||||
|
|
||||||
|
<div id="i18n-3"><p i18n><i>with placeholders</i></p></div>
|
||||||
|
<div id="i18n-3b"><p i18n><i class="preserved-on-placeholders">with placeholders</i></p></div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p id="i18n-4" i18n-title title="on not translatable node"></p>
|
||||||
|
<p id="i18n-5" i18n i18n-title title="on translatable node"></p>
|
||||||
|
<p id="i18n-6" i18n-title title></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- no ph below because the ICU node is the only child of the div, i.e. no text nodes -->
|
||||||
|
<div i18n id="i18n-7">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||||
|
|
||||||
|
<div i18n id="i18n-8">
|
||||||
|
{sex, select, m {male} f {female}}
|
||||||
|
</div>
|
||||||
|
<div i18n id="i18n-8b">
|
||||||
|
{sexB, select, m {male} f {female}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div i18n id="i18n-9">{{ "count = " + count }}</div>
|
||||||
|
<div i18n id="i18n-10">sex = {{ sex }}</div>
|
||||||
|
<div i18n id="i18n-11">{{ "custom name" //i18n(ph="CUSTOM_NAME") }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- i18n -->
|
||||||
|
<h1 id="i18n-12" >Markers in html comments</h1>
|
||||||
|
<div id="i18n-13" i18n-title title="in a translatable section"></div>
|
||||||
|
<div id="i18n-14">{count, plural, =0 {zero} =1 {one} =2 {two} other {<b>many</b>}}</div>
|
||||||
|
<!-- /i18n -->
|
||||||
|
|
||||||
|
<div id="i18n-15"><ng-container i18n>it <b>should</b> work</ng-container></div>
|
||||||
|
|
||||||
|
<!-- make sure that ICU messages are not treated as text nodes -->
|
||||||
|
<div i18n="desc">{
|
||||||
|
response.getItemsList().length,
|
||||||
|
plural,
|
||||||
|
=0 {Found no results}
|
||||||
|
=1 {Found one result}
|
||||||
|
other {Found {{response.getItemsList().length}} results}
|
||||||
|
}</div>
|
||||||
|
|
||||||
|
<div i18n id="i18n-18">foo<a i18n-title title="in a translatable section">bar</a></div>
|
||||||
`;
|
`;
|
||||||
|
@ -1323,17 +1323,30 @@ Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should work with *... and use the attribute name as property binding name', () => {
|
it('should work with *... and use the attribute name as property binding name', () => {
|
||||||
expect(humanizeTplAst(parse('<div *ngIf="test">', [ngIf]))).toEqual([
|
expect(humanizeTplAst(parse('<div *ngIf="test">', [ngIf]))).toEqual([
|
||||||
[EmbeddedTemplateAst], [DirectiveAst, ngIf],
|
[EmbeddedTemplateAst],
|
||||||
[BoundDirectivePropertyAst, 'ngIf', 'test'], [ElementAst, 'div']
|
[DirectiveAst, ngIf],
|
||||||
|
[BoundDirectivePropertyAst, 'ngIf', 'test'],
|
||||||
|
[ElementAst, 'div'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// https://github.com/angular/angular/issues/13800
|
||||||
|
expect(humanizeTplAst(parse('<div *ngIf="-1">', [ngIf]))).toEqual([
|
||||||
|
[EmbeddedTemplateAst],
|
||||||
|
[DirectiveAst, ngIf],
|
||||||
|
[BoundDirectivePropertyAst, 'ngIf', '0 - 1'],
|
||||||
|
[ElementAst, 'div'],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work with *... and empty value', () => {
|
it('should work with *... and empty value', () => {
|
||||||
expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([
|
expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([
|
||||||
[EmbeddedTemplateAst], [DirectiveAst, ngIf],
|
[EmbeddedTemplateAst],
|
||||||
[BoundDirectivePropertyAst, 'ngIf', 'null'], [ElementAst, 'div']
|
[DirectiveAst, ngIf],
|
||||||
|
[BoundDirectivePropertyAst, 'ngIf', 'null'],
|
||||||
|
[ElementAst, 'div'],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -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';
|
||||||
|
@ -13,7 +13,6 @@ import {Type} from '../type';
|
|||||||
|
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
import {ViewContainer} from './view_container';
|
|
||||||
import {ViewRef} from './view_ref';
|
import {ViewRef} from './view_ref';
|
||||||
import {ViewUtils} from './view_utils';
|
import {ViewUtils} from './view_utils';
|
||||||
|
|
||||||
@ -86,11 +85,6 @@ export class ComponentRef_<C> extends ComponentRef<C> {
|
|||||||
onDestroy(callback: Function): void { this.hostView.onDestroy(callback); }
|
onDestroy(callback: Function): void { this.hostView.onDestroy(callback); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
const EMPTY_CONTEXT = new Object();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
import {ViewContainer} from './view_container';
|
|
||||||
import {EmbeddedViewRef} from './view_ref';
|
import {EmbeddedViewRef} from './view_ref';
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import {ChangeDetectorRef, ChangeDetectorStatus} from '../change_detection/chang
|
|||||||
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
import {Injector, THROW_IF_NOT_FOUND} from '../di/injector';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
import {WtfScopeFn, wtfCreateScope, wtfLeave} from '../profile/profile';
|
||||||
import {DirectRenderer, RenderComponentType, RenderDebugInfo, Renderer} from '../render/api';
|
import {DirectRenderer, RenderComponentType, Renderer} from '../render/api';
|
||||||
|
|
||||||
import {AnimationViewContext} from './animation_view_context';
|
import {AnimationViewContext} from './animation_view_context';
|
||||||
import {ComponentRef} from './component_factory';
|
import {ComponentRef} from './component_factory';
|
||||||
|
@ -7,10 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injector} from '../di/injector';
|
import {Injector} from '../di/injector';
|
||||||
import {isPresent} from '../facade/lang';
|
|
||||||
|
|
||||||
import {ElementRef} from './element_ref';
|
import {ElementRef} from './element_ref';
|
||||||
import {QueryList} from './query_list';
|
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
import {ViewContainerRef_} from './view_container_ref';
|
import {ViewContainerRef_} from './view_container_ref';
|
||||||
import {ViewType} from './view_type';
|
import {ViewType} from './view_type';
|
||||||
|
@ -15,7 +15,6 @@ import {ViewEncapsulation} from '../metadata/view';
|
|||||||
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
import {RenderComponentType, RenderDebugInfo, Renderer, RootRenderer} from '../render/api';
|
||||||
import {Sanitizer} from '../security';
|
import {Sanitizer} from '../security';
|
||||||
import {VERSION} from '../version';
|
import {VERSION} from '../version';
|
||||||
import {NgZone} from '../zone/ng_zone';
|
|
||||||
|
|
||||||
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
import {ExpressionChangedAfterItHasBeenCheckedError} from './errors';
|
||||||
import {AppView} from './view';
|
import {AppView} from './view';
|
||||||
@ -23,7 +22,6 @@ import {AppView} from './view';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class ViewUtils {
|
export class ViewUtils {
|
||||||
sanitizer: Sanitizer;
|
sanitizer: Sanitizer;
|
||||||
private _nextCompTypeId: number = 0;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _renderer: RootRenderer, sanitizer: Sanitizer,
|
private _renderer: RootRenderer, sanitizer: Sanitizer,
|
||||||
|
@ -138,7 +138,7 @@ export function main() {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'child',
|
selector: 'child',
|
||||||
template:
|
template:
|
||||||
'(<template [ngTemplateOutlet]="templateRef" [ngOutletContext]="templateCtx"></template>)'
|
'(<ng-container [ngTemplateOutlet]="templateRef" [ngOutletContext]="templateCtx"></ng-container>)'
|
||||||
})
|
})
|
||||||
class Child {
|
class Child {
|
||||||
@Input()
|
@Input()
|
||||||
|
@ -23,8 +23,15 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureCompiler({useJit: useJit});
|
TestBed.configureCompiler({useJit: useJit});
|
||||||
TestBed.configureTestingModule(
|
TestBed.configureTestingModule({
|
||||||
{declarations: [MyComp, NeedsContentChildren, NeedsViewChildren, TextDirective, Simple]});
|
declarations: [
|
||||||
|
MyComp,
|
||||||
|
NeedsContentChildren,
|
||||||
|
NeedsViewChildren,
|
||||||
|
TextDirective,
|
||||||
|
Simple,
|
||||||
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support the "i18n" attribute', () => {
|
it('should support the "i18n" attribute', () => {
|
||||||
|
@ -421,7 +421,7 @@ export function main() {
|
|||||||
TestBed.overrideDirective(
|
TestBed.overrideDirective(
|
||||||
SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}});
|
SimpleDirective, {set: {providers: [{provide: 'service', useValue: 'parentService'}]}});
|
||||||
const el = createComponent(
|
const el = createComponent(
|
||||||
'<div simpleDirective><template [ngIf]="true"><div *ngIf="true" needsService></div></template></div>');
|
'<div simpleDirective><ng-container *ngIf="true"><div *ngIf="true" needsService></div></ng-container></div>');
|
||||||
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
expect(el.children[0].children[0].injector.get(NeedsService).service)
|
||||||
.toEqual('parentService');
|
.toEqual('parentService');
|
||||||
});
|
});
|
||||||
|
@ -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 {Component, ComponentRef, Injectable, Injector} from '@angular/core';
|
import {Component, ComponentRef, Injectable} from '@angular/core';
|
||||||
import {DebugDomRootRenderer} from '@angular/core/src/debug/debug_renderer';
|
import {DebugDomRootRenderer} from '@angular/core/src/debug/debug_renderer';
|
||||||
import {RootRenderer} from '@angular/core/src/render/api';
|
import {RootRenderer} from '@angular/core/src/render/api';
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
@ -152,7 +152,7 @@ export function main() {
|
|||||||
it('should update any template comment property/attributes', () => {
|
it('should update any template comment property/attributes', () => {
|
||||||
|
|
||||||
TestBed.overrideComponent(
|
TestBed.overrideComponent(
|
||||||
MyComp2, {set: {template: '<template [ngIf]="ctxBoolProp"></template>'}});
|
MyComp2, {set: {template: '<ng-container *ngIf="ctxBoolProp"></ng-container>'}});
|
||||||
const fixture = TestBed.createComponent(MyComp2);
|
const fixture = TestBed.createComponent(MyComp2);
|
||||||
|
|
||||||
(<MyComp2>fixture.componentInstance).ctxBoolProp = true;
|
(<MyComp2>fixture.componentInstance).ctxBoolProp = true;
|
||||||
@ -163,7 +163,7 @@ export function main() {
|
|||||||
|
|
||||||
it('should add and remove fragments', () => {
|
it('should add and remove fragments', () => {
|
||||||
TestBed.overrideComponent(
|
TestBed.overrideComponent(
|
||||||
MyComp2, {set: {template: '<template [ngIf]="ctxBoolProp">hello</template>'}});
|
MyComp2, {set: {template: '<ng-container *ngIf="ctxBoolProp">hello</ng-container>'}});
|
||||||
const fixture = TestBed.createComponent(MyComp2);
|
const fixture = TestBed.createComponent(MyComp2);
|
||||||
|
|
||||||
const rootEl = getRenderElement(fixture.nativeElement);
|
const rootEl = getRenderElement(fixture.nativeElement);
|
||||||
|
@ -71,4 +71,4 @@ Promise
|
|||||||
return Promise.all(
|
return Promise.all(
|
||||||
allSpecFiles.map(function(moduleName) { return System.import(moduleName); }));
|
allSpecFiles.map(function(moduleName) { return System.import(moduleName); }));
|
||||||
})
|
})
|
||||||
.then(__karma__.start, __karma__.error);
|
.then(__karma__.start, (v) => console.error(v));
|
||||||
|
@ -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`.
|
||||||
|
@ -133,7 +133,7 @@ export class RouterLink {
|
|||||||
*/
|
*/
|
||||||
@Directive({selector: 'a[routerLink]'})
|
@Directive({selector: 'a[routerLink]'})
|
||||||
export class RouterLinkWithHref implements OnChanges, OnDestroy {
|
export class RouterLinkWithHref implements OnChanges, OnDestroy {
|
||||||
@Input() target: string;
|
@HostBinding('attr.target') @Input() target: string;
|
||||||
@Input() queryParams: {[k: string]: any};
|
@Input() queryParams: {[k: string]: any};
|
||||||
@Input() fragment: string;
|
@Input() fragment: string;
|
||||||
@Input() preserveQueryParams: boolean;
|
@Input() preserveQueryParams: boolean;
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -526,6 +526,7 @@ export class Router {
|
|||||||
*/
|
*/
|
||||||
navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
|
navigate(commands: any[], extras: NavigationExtras = {skipLocationChange: false}):
|
||||||
Promise<boolean> {
|
Promise<boolean> {
|
||||||
|
validateCommands(commands);
|
||||||
if (typeof extras.queryParams === 'object' && extras.queryParams !== null) {
|
if (typeof extras.queryParams === 'object' && extras.queryParams !== null) {
|
||||||
extras.queryParams = this.removeEmptyProps(extras.queryParams);
|
extras.queryParams = this.removeEmptyProps(extras.queryParams);
|
||||||
}
|
}
|
||||||
@ -1237,3 +1238,12 @@ function getOutlet(outletMap: RouterOutletMap, route: ActivatedRoute): RouterOut
|
|||||||
}
|
}
|
||||||
return outlet;
|
return outlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateCommands(commands: string[]): void {
|
||||||
|
for (let i = 0; i < commands.length; i++) {
|
||||||
|
const cmd = commands[i];
|
||||||
|
if (cmd == null) {
|
||||||
|
throw new Error(`The requested path contains ${cmd} segment at index ${i}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -40,7 +40,7 @@ function equalSegmentGroups(container: UrlSegmentGroup, containee: UrlSegmentGro
|
|||||||
|
|
||||||
function containsQueryParams(
|
function containsQueryParams(
|
||||||
container: {[k: string]: string}, containee: {[k: string]: string}): boolean {
|
container: {[k: string]: string}, containee: {[k: string]: string}): boolean {
|
||||||
return Object.keys(containee) <= Object.keys(container) &&
|
return Object.keys(containee).length <= Object.keys(container).length &&
|
||||||
Object.keys(containee).every(key => containee[key] === container[key]);
|
Object.keys(containee).every(key => containee[key] === container[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -536,6 +536,17 @@ describe('Integration', () => {
|
|||||||
expect(cmp.recordedParams).toEqual([{name: '1'}]);
|
expect(cmp.recordedParams).toEqual([{name: '1'}]);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
it('should throw an error when one of the commands is null/undefined',
|
||||||
|
fakeAsync(inject([Router], (router: Router) => {
|
||||||
|
createRoot(router, RootCmp);
|
||||||
|
|
||||||
|
router.resetConfig([{path: 'query', component: EmptyQueryParamsCmp}]);
|
||||||
|
|
||||||
|
expect(() => router.navigate([
|
||||||
|
undefined, 'query'
|
||||||
|
])).toThrowError(`The requested path contains undefined segment at index 0`);
|
||||||
|
})));
|
||||||
|
|
||||||
it('should push params only when they change', fakeAsync(inject([Router], (router: Router) => {
|
it('should push params only when they change', fakeAsync(inject([Router], (router: Router) => {
|
||||||
const fixture = createRoot(router, RootCmp);
|
const fixture = createRoot(router, RootCmp);
|
||||||
|
|
||||||
@ -998,6 +1009,7 @@ describe('Integration', () => {
|
|||||||
|
|
||||||
const native = fixture.nativeElement.querySelector('a');
|
const native = fixture.nativeElement.querySelector('a');
|
||||||
expect(native.getAttribute('href')).toEqual('/team/33/simple');
|
expect(native.getAttribute('href')).toEqual('/team/33/simple');
|
||||||
|
expect(native.getAttribute('target')).toEqual('_self');
|
||||||
native.click();
|
native.click();
|
||||||
advance(fixture);
|
advance(fixture);
|
||||||
|
|
||||||
@ -2020,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 {
|
||||||
@ -2039,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');
|
||||||
}));
|
}));
|
||||||
@ -2646,7 +2660,8 @@ function expectEvents(events: Event[], pairs: any[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({selector: 'link-cmp', template: `<a routerLink="/team/33/simple">link</a>`})
|
@Component(
|
||||||
|
{selector: 'link-cmp', template: `<a routerLink="/team/33/simple" [target]="'_self'">link</a>`})
|
||||||
class StringLinkCmp {
|
class StringLinkCmp {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,8 +102,8 @@ describe('UrlTree', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when container contains containees queryParams', () => {
|
it('should return true when container contains containees queryParams', () => {
|
||||||
const t1 = serializer.parse('/one/two?test=1&page=5');
|
const t1 = serializer.parse('/one/two?test=1&u=5');
|
||||||
const t2 = serializer.parse('/one/two?test=1');
|
const t2 = serializer.parse('/one/two?u=5');
|
||||||
expect(containsTree(t1, t2, false)).toBe(true);
|
expect(containsTree(t1, t2, false)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -29,7 +29,7 @@ export function init(moduleRef: NgModuleRef<AppModule>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function detectChanges() {
|
function detectChanges() {
|
||||||
for (var i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
appRef.tick();
|
appRef.tick();
|
||||||
}
|
}
|
||||||
detectChangesRuns += 10;
|
detectChangesRuns += 10;
|
||||||
|
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.2",
|
"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",
|
||||||
|
@ -82,9 +82,7 @@ System.import('@angular/core/testing')
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
.then(
|
.then(function() { __karma__.start(); }, function(error) { console.error(error); });
|
||||||
function() { __karma__.start(); },
|
|
||||||
function(error) { __karma__.error(error.stack || error); });
|
|
||||||
|
|
||||||
|
|
||||||
function onlySpecFiles(path) {
|
function onlySpecFiles(path) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@angular/tsc-wrapped",
|
"name": "@angular/tsc-wrapped",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"description": "Wraps the tsc CLI, allowing extensions.",
|
"description": "Wraps the tsc CLI, allowing extensions.",
|
||||||
"homepage": "https://github.com/angular/angular/tree/master/tools/tsc-wrapped",
|
"homepage": "https://github.com/angular/angular/tree/master/tools/tsc-wrapped",
|
||||||
"bugs": "https://github.com/angular/angular/issues",
|
"bugs": "https://github.com/angular/angular/issues",
|
||||||
|
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