Compare commits
16 Commits
7.0.0-beta
...
2.0.1
Author | SHA1 | Date | |
---|---|---|---|
712d1a7c37 | |||
16601f9359 | |||
b81e2e7a31 | |||
98fac36706 | |||
3e780c032e | |||
e09882180e | |||
0e18c57a17 | |||
51e2b9c073 | |||
f218e240d3 | |||
af6b219f8e | |||
20addf5f9f | |||
2860418a3c | |||
39e251eea7 | |||
d7d716d5db | |||
a95d65241c | |||
fdb22bd185 |
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -20,7 +20,7 @@
|
|||||||
**Please tell us about your environment:**
|
**Please tell us about your environment:**
|
||||||
<!-- Operating system, IDE, package manager, HTTP server, ... -->
|
<!-- Operating system, IDE, package manager, HTTP server, ... -->
|
||||||
|
|
||||||
* **Angular version:** 2.0.0-rc.X
|
* **Angular version:** 2.0.X
|
||||||
<!-- Check whether this is still an issue in the most recent Angular version -->
|
<!-- Check whether this is still an issue in the most recent Angular version -->
|
||||||
|
|
||||||
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
|
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
|
||||||
|
19
CHANGELOG.md
19
CHANGELOG.md
@ -1,3 +1,22 @@
|
|||||||
|
<a name="2.0.1"></a>
|
||||||
|
## [2.0.1](https://github.com/angular/angular/compare/2.0.0...2.0.1) (2016-09-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **common:** fix ngOnChanges signature of NgTemplateOutlet directive ([14ee759](https://github.com/angular/angular/commit/14ee759))
|
||||||
|
* **compiler:** `[attribute~=value]` selector ([#11696](https://github.com/angular/angular/issues/11696)) ([734b8b8](https://github.com/angular/angular/commit/734b8b8)), closes [#9644](https://github.com/angular/angular/issues/9644)
|
||||||
|
* **compiler:** safe property access expressions work in event bindings ([#11724](https://github.com/angular/angular/issues/11724)) ([a95d652](https://github.com/angular/angular/commit/a95d652))
|
||||||
|
* **compiler:** throw when Component.moduleId is not a string ([bd4045b](https://github.com/angular/angular/commit/bd4045b)), closes [#11590](https://github.com/angular/angular/issues/11590)
|
||||||
|
* **compiler:** do not provide I18N values when they're not specified ([03aedbe](https://github.com/angular/angular/commit/03aedbe)), closes [#11643](https://github.com/angular/angular/issues/11643)
|
||||||
|
* **core:** ContentChild descendants should be queried by default ([0dc15eb](https://github.com/angular/angular/commit/0dc15eb)), closes [#1645](https://github.com/angular/angular/issues/1645)
|
||||||
|
* **forms:** disable all radios with disable() ([2860418](https://github.com/angular/angular/commit/2860418))
|
||||||
|
* **forms:** make setDisabledState optional for reactive form directives ([#11731](https://github.com/angular/angular/issues/11731)) ([51d73d3](https://github.com/angular/angular/commit/51d73d3)), closes [#11719](https://github.com/angular/angular/issues/11719)
|
||||||
|
* **forms:** support unbound disabled in ngModel ([#11736](https://github.com/angular/angular/issues/11736)) ([39e251e](https://github.com/angular/angular/commit/39e251e))
|
||||||
|
* **upgrade:** allow attribute selectors for components in ng2 which are not part of upgrade ([#11808](https://github.com/angular/angular/issues/11808)) ([b81e2e7](https://github.com/angular/angular/commit/b81e2e7)), closes [#11280](https://github.com/angular/angular/issues/11280)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="2.0.0"></a>
|
<a name="2.0.0"></a>
|
||||||
# [2.0.0](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
|
# [2.0.0](https://github.com/angular/angular/compare/2.0.0-rc.7...2.0.0) (2016-09-14)
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
|
|||||||
## <a name="question"></a> Got a Question or Problem?
|
## <a name="question"></a> Got a Question or Problem?
|
||||||
|
|
||||||
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
|
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
|
||||||
discussion list or [StackOverflow][stackoverflow]. Please note that Angular 2 is still in early developer preview, and the core team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
discussion list or [StackOverflow][stackoverflow]. Please note that the Angular team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
||||||
|
|
||||||
## <a name="issue"></a> Found an Issue?
|
## <a name="issue"></a> Found an Issue?
|
||||||
If you find a bug in the source code, you can help us by
|
If you find a bug in the source code, you can help us by
|
||||||
@ -28,8 +28,7 @@ If you find a bug in the source code, you can help us by
|
|||||||
## <a name="feature"></a> Want a Feature?
|
## <a name="feature"></a> Want a Feature?
|
||||||
You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub
|
You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub
|
||||||
Repository][github]. If you would like to *implement* a new feature, please submit an issue with
|
Repository][github]. If you would like to *implement* a new feature, please submit an issue with
|
||||||
a proposal for your work first, to be sure that we can use it. Angular 2 is in developer preview
|
a proposal for your work first, to be sure that we can use it.
|
||||||
and we are not ready to accept major contributions ahead of the full release.
|
|
||||||
Please consider what kind of change it is:
|
Please consider what kind of change it is:
|
||||||
|
|
||||||
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
||||||
|
@ -22,9 +22,11 @@ var CIconfiguration = {
|
|||||||
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
|
'Safari10': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
||||||
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'iOS9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
'iOS9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
|
'iOS10': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||||
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
|
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,6 +85,12 @@ var customLaunchers = {
|
|||||||
platform: 'OS X 10.11',
|
platform: 'OS X 10.11',
|
||||||
version: '9.0'
|
version: '9.0'
|
||||||
},
|
},
|
||||||
|
'SL_SAFARI10': {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'safari',
|
||||||
|
platform: 'OS X 10.12',
|
||||||
|
version: '10.0'
|
||||||
|
},
|
||||||
'SL_IOS7': {
|
'SL_IOS7': {
|
||||||
base: 'SauceLabs',
|
base: 'SauceLabs',
|
||||||
browserName: 'iphone',
|
browserName: 'iphone',
|
||||||
@ -101,6 +109,12 @@ var customLaunchers = {
|
|||||||
platform: 'OS X 10.10',
|
platform: 'OS X 10.10',
|
||||||
version: '9.3'
|
version: '9.3'
|
||||||
},
|
},
|
||||||
|
'SL_IOS10': {
|
||||||
|
base: 'SauceLabs',
|
||||||
|
browserName: 'iphone',
|
||||||
|
platform: 'OS X 10.10',
|
||||||
|
version: '10.0'
|
||||||
|
},
|
||||||
'SL_IE9': {
|
'SL_IE9': {
|
||||||
base: 'SauceLabs',
|
base: 'SauceLabs',
|
||||||
browserName: 'internet explorer',
|
browserName: 'internet explorer',
|
||||||
@ -186,6 +200,12 @@ var customLaunchers = {
|
|||||||
os: 'OS X',
|
os: 'OS X',
|
||||||
os_version: 'El Capitan'
|
os_version: 'El Capitan'
|
||||||
},
|
},
|
||||||
|
'BS_SAFARI10': {
|
||||||
|
base: 'BrowserStack',
|
||||||
|
browser: 'safari',
|
||||||
|
os: 'OS X',
|
||||||
|
os_version: 'Sierra'
|
||||||
|
},
|
||||||
'BS_IOS7': {
|
'BS_IOS7': {
|
||||||
base: 'BrowserStack',
|
base: 'BrowserStack',
|
||||||
device: 'iPhone 5S',
|
device: 'iPhone 5S',
|
||||||
@ -204,6 +224,12 @@ var customLaunchers = {
|
|||||||
os: 'ios',
|
os: 'ios',
|
||||||
os_version: '9.1'
|
os_version: '9.1'
|
||||||
},
|
},
|
||||||
|
'BS_IOS10': {
|
||||||
|
base: 'BrowserStack',
|
||||||
|
device: 'iPhone SE',
|
||||||
|
os: 'ios',
|
||||||
|
os_version: '10.0'
|
||||||
|
},
|
||||||
'BS_IE9': {
|
'BS_IE9': {
|
||||||
base: 'BrowserStack',
|
base: 'BrowserStack',
|
||||||
browser: 'ie',
|
browser: 'ie',
|
||||||
@ -271,12 +297,12 @@ var customLaunchers = {
|
|||||||
|
|
||||||
var sauceAliases = {
|
var sauceAliases = {
|
||||||
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
|
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
|
||||||
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
|
||||||
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
|
||||||
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
|
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
|
||||||
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
|
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
|
||||||
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
|
||||||
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
|
||||||
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
|
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
|
||||||
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
|
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
|
||||||
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
|
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
|
||||||
@ -285,12 +311,12 @@ var sauceAliases = {
|
|||||||
|
|
||||||
var browserstackAliases = {
|
var browserstackAliases = {
|
||||||
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
|
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'BrowserStack';}),
|
||||||
'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
|
'DESKTOP': ['BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
|
||||||
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
|
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10', 'BS_WINDOWSPHONE'],
|
||||||
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
|
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
|
||||||
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
|
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
|
||||||
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
|
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10'],
|
||||||
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
|
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
|
||||||
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
|
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
|
||||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
|
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
|
||||||
};
|
};
|
||||||
|
@ -6,18 +6,15 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Map} from './facade/collection';
|
|
||||||
import {Date, DateWrapper} from './facade/lang';
|
|
||||||
|
|
||||||
export class MeasureValues {
|
export class MeasureValues {
|
||||||
constructor(
|
constructor(
|
||||||
public runIndex: number, public timeStamp: Date, public values: {[key: string]: any}) {}
|
public runIndex: number, public timeStamp: Date, public values: {[key: string]: any}) {}
|
||||||
|
|
||||||
toJson() {
|
toJson() {
|
||||||
return {
|
return {
|
||||||
'timeStamp': DateWrapper.toJson(this.timeStamp),
|
'timeStamp': this.timeStamp.toJSON(),
|
||||||
'runIndex': this.runIndex,
|
'runIndex': this.runIndex,
|
||||||
'values': this.values
|
'values': this.values,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {Inject, Injectable, OpaqueToken, Provider} from '@angular/core';
|
import {Inject, Injectable} from '@angular/core';
|
||||||
|
|
||||||
import {Options} from '../common_options';
|
import {Options} from '../common_options';
|
||||||
import {StringMapWrapper} from '../facade/collection';
|
import {StringMapWrapper} from '../facade/collection';
|
||||||
@ -48,9 +48,9 @@ export class UserMetric extends Metric {
|
|||||||
if (values.every(isNumber)) {
|
if (values.every(isNumber)) {
|
||||||
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
|
Promise.all(names.map(name => adapter.executeScript(`delete window.${name}`)))
|
||||||
.then((_: any[]) => {
|
.then((_: any[]) => {
|
||||||
let map = StringMapWrapper.create();
|
let map: {[k: string]: any} = {};
|
||||||
for (let i = 0, n = names.length; i < n; i++) {
|
for (let i = 0, n = names.length; i < n; i++) {
|
||||||
StringMapWrapper.set(map, names[i], values[i]);
|
map[names[i]] = values[i];
|
||||||
}
|
}
|
||||||
resolve(map);
|
resolve(map);
|
||||||
}, reject);
|
}, reject);
|
||||||
|
@ -33,7 +33,7 @@ export function main() {
|
|||||||
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
|
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
|
||||||
}
|
}
|
||||||
if (isBlank(microMetrics)) {
|
if (isBlank(microMetrics)) {
|
||||||
microMetrics = StringMapWrapper.create();
|
microMetrics = {};
|
||||||
}
|
}
|
||||||
var providers: Provider[] = [
|
var providers: Provider[] = [
|
||||||
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
|
Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS,
|
||||||
|
@ -24,7 +24,7 @@ export function main() {
|
|||||||
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
|
new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true});
|
||||||
}
|
}
|
||||||
if (isBlank(userMetrics)) {
|
if (isBlank(userMetrics)) {
|
||||||
userMetrics = StringMapWrapper.create();
|
userMetrics = {};
|
||||||
}
|
}
|
||||||
wdAdapter = new MockDriverAdapter();
|
wdAdapter = new MockDriverAdapter();
|
||||||
var providers: Provider[] = [
|
var providers: Provider[] = [
|
||||||
|
@ -61,8 +61,7 @@ export class NgPlural {
|
|||||||
|
|
||||||
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
|
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
|
||||||
|
|
||||||
/** @internal */
|
private _updateView(): void {
|
||||||
_updateView(): void {
|
|
||||||
this._clearViews();
|
this._clearViews();
|
||||||
|
|
||||||
const cases = Object.keys(this._caseViews);
|
const cases = Object.keys(this._caseViews);
|
||||||
@ -70,13 +69,11 @@ export class NgPlural {
|
|||||||
this._activateView(this._caseViews[key]);
|
this._activateView(this._caseViews[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
private _clearViews() {
|
||||||
_clearViews() {
|
|
||||||
if (this._activeView) this._activeView.destroy();
|
if (this._activeView) this._activeView.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
private _activateView(view: SwitchView) {
|
||||||
_activateView(view: SwitchView) {
|
|
||||||
if (view) {
|
if (view) {
|
||||||
this._activeView = view;
|
this._activeView = view;
|
||||||
this._activeView.create();
|
this._activeView.create();
|
||||||
|
@ -32,10 +32,8 @@ import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDif
|
|||||||
*/
|
*/
|
||||||
@Directive({selector: '[ngStyle]'})
|
@Directive({selector: '[ngStyle]'})
|
||||||
export class NgStyle implements DoCheck {
|
export class NgStyle implements DoCheck {
|
||||||
/** @internal */
|
private _ngStyle: {[key: string]: string};
|
||||||
_ngStyle: {[key: string]: string};
|
private _differ: KeyValueDiffer;
|
||||||
/** @internal */
|
|
||||||
_differ: KeyValueDiffer;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {}
|
private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {}
|
||||||
|
@ -111,8 +111,7 @@ export class NgSwitch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
private _emptyAllActiveViews(): void {
|
||||||
_emptyAllActiveViews(): void {
|
|
||||||
const activeContainers = this._activeViews;
|
const activeContainers = this._activeViews;
|
||||||
for (var i = 0; i < activeContainers.length; i++) {
|
for (var i = 0; i < activeContainers.length; i++) {
|
||||||
activeContainers[i].destroy();
|
activeContainers[i].destroy();
|
||||||
@ -120,9 +119,7 @@ export class NgSwitch {
|
|||||||
this._activeViews = [];
|
this._activeViews = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
private _activateViews(views: SwitchView[]): void {
|
||||||
_activateViews(views: SwitchView[]): void {
|
|
||||||
// TODO(vicb): assert(this._activeViews.length === 0);
|
|
||||||
if (views) {
|
if (views) {
|
||||||
for (var i = 0; i < views.length; i++) {
|
for (var i = 0; i < views.length; i++) {
|
||||||
views[i].create();
|
views[i].create();
|
||||||
@ -141,8 +138,7 @@ export class NgSwitch {
|
|||||||
views.push(view);
|
views.push(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
private _deregisterView(value: any, view: SwitchView): void {
|
||||||
_deregisterView(value: any, view: SwitchView): void {
|
|
||||||
// `_CASE_DEFAULT` is used a marker for non-registered cases
|
// `_CASE_DEFAULT` is used a marker for non-registered cases
|
||||||
if (value === _CASE_DEFAULT) return;
|
if (value === _CASE_DEFAULT) return;
|
||||||
const views = this._valueViews.get(value);
|
const views = this._valueViews.get(value);
|
||||||
@ -181,10 +177,8 @@ export class NgSwitch {
|
|||||||
@Directive({selector: '[ngSwitchCase]'})
|
@Directive({selector: '[ngSwitchCase]'})
|
||||||
export class NgSwitchCase {
|
export class NgSwitchCase {
|
||||||
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
|
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
|
||||||
/** @internal */
|
private _value: any = _CASE_DEFAULT;
|
||||||
_value: any = _CASE_DEFAULT;
|
private _view: SwitchView;
|
||||||
/** @internal */
|
|
||||||
_view: SwitchView;
|
|
||||||
private _switch: NgSwitch;
|
private _switch: NgSwitch;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -67,7 +67,7 @@ export enum Plural {
|
|||||||
Two,
|
Two,
|
||||||
Few,
|
Few,
|
||||||
Many,
|
Many,
|
||||||
Other
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,16 +49,20 @@ export class Location {
|
|||||||
_subject: EventEmitter<any> = new EventEmitter();
|
_subject: EventEmitter<any> = new EventEmitter();
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_baseHref: string;
|
_baseHref: string;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_platformStrategy: LocationStrategy;
|
_platformStrategy: LocationStrategy;
|
||||||
|
|
||||||
constructor(platformStrategy: LocationStrategy) {
|
constructor(platformStrategy: LocationStrategy) {
|
||||||
this._platformStrategy = platformStrategy;
|
this._platformStrategy = platformStrategy;
|
||||||
var browserBaseHref = this._platformStrategy.getBaseHref();
|
const browserBaseHref = this._platformStrategy.getBaseHref();
|
||||||
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
|
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
|
||||||
this._platformStrategy.onPopState(
|
this._platformStrategy.onPopState((ev) => {
|
||||||
(ev) => { this._subject.emit({'url': this.path(true), 'pop': true, 'type': ev.type}); });
|
this._subject.emit({
|
||||||
|
'url': this.path(true),
|
||||||
|
'pop': true,
|
||||||
|
'type': ev.type,
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,9 +18,7 @@ import {EventEmitter, Injectable} from '@angular/core';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class SpyLocation implements Location {
|
export class SpyLocation implements Location {
|
||||||
urlChanges: string[] = [];
|
urlChanges: string[] = [];
|
||||||
/** @internal */
|
|
||||||
private _history: LocationState[] = [new LocationState('', '')];
|
private _history: LocationState[] = [new LocationState('', '')];
|
||||||
/** @internal */
|
|
||||||
private _historyIndex: number = 0;
|
private _historyIndex: number = 0;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_subject: EventEmitter<any> = new EventEmitter();
|
_subject: EventEmitter<any> = new EventEmitter();
|
||||||
|
@ -115,27 +115,27 @@ export class DirectiveNormalizer {
|
|||||||
const templateStyles = this.normalizeStylesheet(new CompileStylesheetMetadata(
|
const templateStyles = this.normalizeStylesheet(new CompileStylesheetMetadata(
|
||||||
{styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl}));
|
{styles: visitor.styles, styleUrls: visitor.styleUrls, moduleUrl: templateAbsUrl}));
|
||||||
|
|
||||||
const allStyles = templateMetadataStyles.styles.concat(templateStyles.styles);
|
|
||||||
const allStyleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
|
|
||||||
|
|
||||||
let encapsulation = templateMeta.encapsulation;
|
let encapsulation = templateMeta.encapsulation;
|
||||||
if (isBlank(encapsulation)) {
|
if (isBlank(encapsulation)) {
|
||||||
encapsulation = this._config.defaultEncapsulation;
|
encapsulation = this._config.defaultEncapsulation;
|
||||||
}
|
}
|
||||||
if (encapsulation === ViewEncapsulation.Emulated && allStyles.length === 0 &&
|
|
||||||
allStyleUrls.length === 0) {
|
const styles = templateMetadataStyles.styles.concat(templateStyles.styles);
|
||||||
|
const styleUrls = templateMetadataStyles.styleUrls.concat(templateStyles.styleUrls);
|
||||||
|
|
||||||
|
if (encapsulation === ViewEncapsulation.Emulated && styles.length === 0 &&
|
||||||
|
styleUrls.length === 0) {
|
||||||
encapsulation = ViewEncapsulation.None;
|
encapsulation = ViewEncapsulation.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CompileTemplateMetadata({
|
return new CompileTemplateMetadata({
|
||||||
encapsulation,
|
encapsulation,
|
||||||
template: template,
|
template,
|
||||||
templateUrl: templateAbsUrl,
|
templateUrl: templateAbsUrl, styles, styleUrls,
|
||||||
styles: allStyles,
|
|
||||||
styleUrls: allStyleUrls,
|
|
||||||
externalStylesheets: templateMeta.externalStylesheets,
|
externalStylesheets: templateMeta.externalStylesheets,
|
||||||
ngContentSelectors: visitor.ngContentSelectors,
|
ngContentSelectors: visitor.ngContentSelectors,
|
||||||
animations: templateMeta.animations,
|
animations: templateMeta.animations,
|
||||||
interpolation: templateMeta.interpolation
|
interpolation: templateMeta.interpolation,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +251,6 @@ function _cloneDirectiveWithTemplate(
|
|||||||
viewProviders: directive.viewProviders,
|
viewProviders: directive.viewProviders,
|
||||||
queries: directive.queries,
|
queries: directive.queries,
|
||||||
viewQueries: directive.viewQueries,
|
viewQueries: directive.viewQueries,
|
||||||
entryComponents: directive.entryComponents,
|
entryComponents: directive.entryComponents, template,
|
||||||
template: template
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,7 @@ export class AstTransformer implements AstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitAll(asts: any[]): any[] {
|
visitAll(asts: any[]): any[] {
|
||||||
var res = ListWrapper.createFixedSize(asts.length);
|
var res = new Array(asts.length);
|
||||||
for (var i = 0; i < asts.length; ++i) {
|
for (var i = 0; i < asts.length; ++i) {
|
||||||
res[i] = asts[i].visit(this);
|
res[i] = asts[i].visit(this);
|
||||||
}
|
}
|
||||||
|
@ -854,7 +854,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
boundPropertyName = this._schemaRegistry.getMappedPropName(partValue);
|
boundPropertyName = this._schemaRegistry.getMappedPropName(partValue);
|
||||||
securityContext = this._schemaRegistry.securityContext(elementName, boundPropertyName);
|
securityContext = this._schemaRegistry.securityContext(elementName, boundPropertyName);
|
||||||
bindingType = PropertyBindingType.Property;
|
bindingType = PropertyBindingType.Property;
|
||||||
this._assertNoEventBinding(boundPropertyName, sourceSpan);
|
this._assertNoEventBinding(boundPropertyName, sourceSpan, false);
|
||||||
if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName, this._schemas)) {
|
if (!this._schemaRegistry.hasProperty(elementName, boundPropertyName, this._schemas)) {
|
||||||
let errorMsg =
|
let errorMsg =
|
||||||
`Can't bind to '${boundPropertyName}' since it isn't a known property of '${elementName}'.`;
|
`Can't bind to '${boundPropertyName}' since it isn't a known property of '${elementName}'.`;
|
||||||
@ -869,7 +869,7 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
} else {
|
} else {
|
||||||
if (parts[0] == ATTRIBUTE_PREFIX) {
|
if (parts[0] == ATTRIBUTE_PREFIX) {
|
||||||
boundPropertyName = parts[1];
|
boundPropertyName = parts[1];
|
||||||
this._assertNoEventBinding(boundPropertyName, sourceSpan);
|
this._assertNoEventBinding(boundPropertyName, sourceSpan, true);
|
||||||
// NB: For security purposes, use the mapped property name, not the attribute name.
|
// NB: For security purposes, use the mapped property name, not the attribute name.
|
||||||
const mapPropName = this._schemaRegistry.getMappedPropName(boundPropertyName);
|
const mapPropName = this._schemaRegistry.getMappedPropName(boundPropertyName);
|
||||||
securityContext = this._schemaRegistry.securityContext(elementName, mapPropName);
|
securityContext = this._schemaRegistry.securityContext(elementName, mapPropName);
|
||||||
@ -902,12 +902,23 @@ class TemplateParseVisitor implements html.Visitor {
|
|||||||
boundPropertyName, bindingType, securityContext, ast, unit, sourceSpan);
|
boundPropertyName, bindingType, securityContext, ast, unit, sourceSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _assertNoEventBinding(propName: string, sourceSpan: ParseSourceSpan): void {
|
/**
|
||||||
|
* @param propName the name of the property / attribute
|
||||||
|
* @param sourceSpan
|
||||||
|
* @param isAttr true when binding to an attribute
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private _assertNoEventBinding(propName: string, sourceSpan: ParseSourceSpan, isAttr: boolean):
|
||||||
|
void {
|
||||||
if (propName.toLowerCase().startsWith('on')) {
|
if (propName.toLowerCase().startsWith('on')) {
|
||||||
this._reportError(
|
let msg = `Binding to event attribute '${propName}' is disallowed for security reasons, ` +
|
||||||
`Binding to event attribute '${propName}' is disallowed ` +
|
`please use (${propName.slice(2)})=...`;
|
||||||
`for security reasons, please use (${propName.slice(2)})=...`,
|
if (!isAttr) {
|
||||||
sourceSpan, ParseErrorLevel.FATAL);
|
msg +=
|
||||||
|
`\nIf '${propName}' is a directive input, make sure the directive is imported by the` +
|
||||||
|
` current module.`;
|
||||||
|
}
|
||||||
|
this._reportError(msg, sourceSpan, ParseErrorLevel.FATAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ export class CompileElement extends CompileNode {
|
|||||||
setComponentView(compViewExpr: o.Expression) {
|
setComponentView(compViewExpr: o.Expression) {
|
||||||
this._compViewExpr = compViewExpr;
|
this._compViewExpr = compViewExpr;
|
||||||
this.contentNodesByNgContentIndex =
|
this.contentNodesByNgContentIndex =
|
||||||
ListWrapper.createFixedSize(this.component.template.ngContentSelectors.length);
|
new Array(this.component.template.ngContentSelectors.length);
|
||||||
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
|
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
|
||||||
this.contentNodesByNgContentIndex[i] = [];
|
this.contentNodesByNgContentIndex[i] = [];
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
// Notice that the first guard condition is the left hand of the left most safe access node
|
// Notice that the first guard condition is the left hand of the left most safe access node
|
||||||
// which comes in as leftMostSafe to this routine.
|
// which comes in as leftMostSafe to this routine.
|
||||||
|
|
||||||
let guardedExpression = this.visit(leftMostSafe.receiver, mode);
|
let guardedExpression = this.visit(leftMostSafe.receiver, _Mode.Expression);
|
||||||
let temporary: o.ReadVarExpr;
|
let temporary: o.ReadVarExpr;
|
||||||
if (this.needsTemporary(leftMostSafe.receiver)) {
|
if (this.needsTemporary(leftMostSafe.receiver)) {
|
||||||
// If the expression has method calls or pipes then we need to save the result into a
|
// If the expression has method calls or pipes then we need to save the result into a
|
||||||
@ -369,7 +369,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recursively convert the node now without the guarded member access.
|
// Recursively convert the node now without the guarded member access.
|
||||||
const access = this.visit(ast, mode);
|
const access = this.visit(ast, _Mode.Expression);
|
||||||
|
|
||||||
// Remove the mapping. This is not strictly required as the converter only traverses each node
|
// Remove the mapping. This is not strictly required as the converter only traverses each node
|
||||||
// once but is safer if the conversion is changed to traverse the nodes more than once.
|
// once but is safer if the conversion is changed to traverse the nodes more than once.
|
||||||
@ -381,7 +381,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Produce the conditional
|
// Produce the conditional
|
||||||
return condition.conditional(o.literal(null), access);
|
return convertToStatementIfNeeded(mode, condition.conditional(o.literal(null), access));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a expression of the form a?.b.c?.d.e the the left most safe node is
|
// Given a expression of the form a?.b.c?.d.e the the left most safe node is
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
import {DirectiveResolver} from '@angular/compiler';
|
import {DirectiveResolver} from '@angular/compiler';
|
||||||
import {AnimationEntryMetadata, Compiler, Component, Directive, Injectable, Injector, Provider, Type, resolveForwardRef} from '@angular/core';
|
import {AnimationEntryMetadata, Compiler, Component, Directive, Injectable, Injector, Provider, Type, resolveForwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {Map} from './facade/collection';
|
import {isPresent} from './facade/lang';
|
||||||
import {isArray, isPresent} from './facade/lang';
|
|
||||||
import {ViewMetadata} from './private_import_core';
|
import {ViewMetadata} from './private_import_core';
|
||||||
|
|
||||||
|
|
||||||
@ -156,7 +155,7 @@ function flattenArray(tree: any[], out: Array<Type<any>|any[]>): void {
|
|||||||
if (!isPresent(tree)) return;
|
if (!isPresent(tree)) return;
|
||||||
for (var i = 0; i < tree.length; i++) {
|
for (var i = 0; i < tree.length; i++) {
|
||||||
var item = resolveForwardRef(tree[i]);
|
var item = resolveForwardRef(tree[i]);
|
||||||
if (isArray(item)) {
|
if (Array.isArray(item)) {
|
||||||
flattenArray(item, out);
|
flattenArray(item, out);
|
||||||
} else {
|
} else {
|
||||||
out.push(item);
|
out.push(item);
|
||||||
|
@ -9,18 +9,12 @@
|
|||||||
import {NgModuleResolver} from '@angular/compiler';
|
import {NgModuleResolver} from '@angular/compiler';
|
||||||
import {Compiler, Injectable, Injector, NgModule, Type} from '@angular/core';
|
import {Compiler, Injectable, Injector, NgModule, Type} from '@angular/core';
|
||||||
|
|
||||||
import {Map} from './facade/collection';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MockNgModuleResolver extends NgModuleResolver {
|
export class MockNgModuleResolver extends NgModuleResolver {
|
||||||
private _ngModules = new Map<Type<any>, NgModule>();
|
private _ngModules = new Map<Type<any>, NgModule>();
|
||||||
|
|
||||||
constructor(private _injector: Injector) { super(); }
|
constructor(private _injector: Injector) { super(); }
|
||||||
|
|
||||||
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
|
||||||
|
|
||||||
private _clearCacheFor(component: Type<any>) { this._compiler.clearCacheFor(component); }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides the {@link NgModule} for a module.
|
* Overrides the {@link NgModule} for a module.
|
||||||
*/
|
*/
|
||||||
@ -36,10 +30,10 @@ export class MockNgModuleResolver extends NgModuleResolver {
|
|||||||
* `NgModuleResolver`, see `setNgModule`.
|
* `NgModuleResolver`, see `setNgModule`.
|
||||||
*/
|
*/
|
||||||
resolve(type: Type<any>, throwIfNotFound = true): NgModule {
|
resolve(type: Type<any>, throwIfNotFound = true): NgModule {
|
||||||
var metadata = this._ngModules.get(type);
|
return this._ngModules.get(type) || super.resolve(type, throwIfNotFound);
|
||||||
if (!metadata) {
|
|
||||||
metadata = super.resolve(type, throwIfNotFound);
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get _compiler(): Compiler { return this._injector.get(Compiler); }
|
||||||
|
|
||||||
|
private _clearCacheFor(component: Type<any>) { this._compiler.clearCacheFor(component); }
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
import {PipeResolver} from '@angular/compiler';
|
import {PipeResolver} from '@angular/compiler';
|
||||||
import {Compiler, Injectable, Injector, Pipe, Type} from '@angular/core';
|
import {Compiler, Injectable, Injector, Pipe, Type} from '@angular/core';
|
||||||
|
|
||||||
import {Map} from './facade/collection';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MockPipeResolver extends PipeResolver {
|
export class MockPipeResolver extends PipeResolver {
|
||||||
private _pipes = new Map<Type<any>, Pipe>();
|
private _pipes = new Map<Type<any>, Pipe>();
|
||||||
|
@ -7,11 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {ResourceLoader} from '@angular/compiler';
|
import {ResourceLoader} from '@angular/compiler';
|
||||||
import {ListWrapper, Map} from './facade/collection';
|
import {ListWrapper} from './facade/collection';
|
||||||
import {isBlank, normalizeBlank} from './facade/lang';
|
import {isBlank, normalizeBlank} from './facade/lang';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mock implementation of {@link ResourceLoader} that allows outgoing requests to be mocked
|
* A mock implementation of {@link ResourceLoader} that allows outgoing requests to be mocked
|
||||||
* and responded to within a single test, without going to the network.
|
* and responded to within a single test, without going to the network.
|
||||||
|
@ -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 {ListWrapper, Map, StringMapWrapper} from '../facade/collection';
|
import {ListWrapper, StringMapWrapper} from '../facade/collection';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
import {AnimationPlayer} from './animation_player';
|
import {AnimationPlayer} from './animation_player';
|
||||||
@ -47,12 +47,12 @@ export class ViewAnimationMap {
|
|||||||
getAllPlayers(): AnimationPlayer[] { return this._allPlayers; }
|
getAllPlayers(): AnimationPlayer[] { return this._allPlayers; }
|
||||||
|
|
||||||
remove(element: any, animationName: string): void {
|
remove(element: any, animationName: string): void {
|
||||||
var playersByAnimation = this._map.get(element);
|
const playersByAnimation = this._map.get(element);
|
||||||
if (isPresent(playersByAnimation)) {
|
if (playersByAnimation) {
|
||||||
var player = playersByAnimation[animationName];
|
const player = playersByAnimation[animationName];
|
||||||
delete playersByAnimation[animationName];
|
delete playersByAnimation[animationName];
|
||||||
var index = this._allPlayers.indexOf(player);
|
const index = this._allPlayers.indexOf(player);
|
||||||
ListWrapper.removeAt(this._allPlayers, index);
|
this._allPlayers.splice(index, 1);
|
||||||
|
|
||||||
if (StringMapWrapper.isEmpty(playersByAnimation)) {
|
if (StringMapWrapper.isEmpty(playersByAnimation)) {
|
||||||
this._map.delete(element);
|
this._map.delete(element);
|
||||||
|
@ -14,7 +14,6 @@ import {LOCALE_ID} from './i18n/tokens';
|
|||||||
import {Compiler} from './linker/compiler';
|
import {Compiler} from './linker/compiler';
|
||||||
import {ViewUtils} from './linker/view_utils';
|
import {ViewUtils} from './linker/view_utils';
|
||||||
import {NgModule} from './metadata';
|
import {NgModule} from './metadata';
|
||||||
import {Type} from './type';
|
|
||||||
|
|
||||||
export function _iterableDiffersFactory() {
|
export function _iterableDiffersFactory() {
|
||||||
return defaultIterableDiffers;
|
return defaultIterableDiffers;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {ErrorHandler} from '../src/error_handler';
|
import {ErrorHandler} from '../src/error_handler';
|
||||||
import {ListWrapper} from '../src/facade/collection';
|
import {ListWrapper} from '../src/facade/collection';
|
||||||
import {unimplemented} from '../src/facade/errors';
|
import {unimplemented} from '../src/facade/errors';
|
||||||
import {isBlank, isPresent, stringify} from '../src/facade/lang';
|
import {stringify} from '../src/facade/lang';
|
||||||
import {isPromise} from '../src/util/lang';
|
import {isPromise} from '../src/util/lang';
|
||||||
|
|
||||||
import {ApplicationInitStatus} from './application_init';
|
import {ApplicationInitStatus} from './application_init';
|
||||||
@ -26,9 +26,9 @@ import {Testability, TestabilityRegistry} from './testability/testability';
|
|||||||
import {Type} from './type';
|
import {Type} from './type';
|
||||||
import {NgZone} from './zone/ng_zone';
|
import {NgZone} from './zone/ng_zone';
|
||||||
|
|
||||||
var _devMode: boolean = true;
|
let _devMode: boolean = true;
|
||||||
var _runModeLocked: boolean = false;
|
let _runModeLocked: boolean = false;
|
||||||
var _platform: PlatformRef;
|
let _platform: PlatformRef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable Angular's development mode, which turns off assertions and other
|
* Disable Angular's development mode, which turns off assertions and other
|
||||||
@ -67,13 +67,13 @@ export function isDevMode(): boolean {
|
|||||||
* @experimental APIs related to application bootstrap are currently under review.
|
* @experimental APIs related to application bootstrap are currently under review.
|
||||||
*/
|
*/
|
||||||
export function createPlatform(injector: Injector): PlatformRef {
|
export function createPlatform(injector: Injector): PlatformRef {
|
||||||
if (isPresent(_platform) && !_platform.destroyed) {
|
if (_platform && !_platform.destroyed) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'There can be only one platform. Destroy the previous one to create a new one.');
|
'There can be only one platform. Destroy the previous one to create a new one.');
|
||||||
}
|
}
|
||||||
_platform = injector.get(PlatformRef);
|
_platform = injector.get(PlatformRef);
|
||||||
const inits: Function[] = <Function[]>injector.get(PLATFORM_INITIALIZER, null);
|
const inits: Function[] = <Function[]>injector.get(PLATFORM_INITIALIZER, null);
|
||||||
if (isPresent(inits)) inits.forEach(init => init());
|
if (inits) inits.forEach(init => init());
|
||||||
return _platform;
|
return _platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,14 +107,17 @@ export function createPlatformFactory(
|
|||||||
* @experimental APIs related to application bootstrap are currently under review.
|
* @experimental APIs related to application bootstrap are currently under review.
|
||||||
*/
|
*/
|
||||||
export function assertPlatform(requiredToken: any): PlatformRef {
|
export function assertPlatform(requiredToken: any): PlatformRef {
|
||||||
var platform = getPlatform();
|
const platform = getPlatform();
|
||||||
if (isBlank(platform)) {
|
|
||||||
|
if (!platform) {
|
||||||
throw new Error('No platform exists!');
|
throw new Error('No platform exists!');
|
||||||
}
|
}
|
||||||
if (isPresent(platform) && isBlank(platform.injector.get(requiredToken, null))) {
|
|
||||||
|
if (!platform.injector.get(requiredToken, null)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'A platform with a different configuration has been created. Please destroy it first.');
|
'A platform with a different configuration has been created. Please destroy it first.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return platform;
|
return platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +127,7 @@ export function assertPlatform(requiredToken: any): PlatformRef {
|
|||||||
* @experimental APIs related to application bootstrap are currently under review.
|
* @experimental APIs related to application bootstrap are currently under review.
|
||||||
*/
|
*/
|
||||||
export function destroyPlatform(): void {
|
export function destroyPlatform(): void {
|
||||||
if (isPresent(_platform) && !_platform.destroyed) {
|
if (_platform && !_platform.destroyed) {
|
||||||
_platform.destroy();
|
_platform.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +138,7 @@ export function destroyPlatform(): void {
|
|||||||
* @experimental APIs related to application bootstrap are currently under review.
|
* @experimental APIs related to application bootstrap are currently under review.
|
||||||
*/
|
*/
|
||||||
export function getPlatform(): PlatformRef {
|
export function getPlatform(): PlatformRef {
|
||||||
return isPresent(_platform) && !_platform.destroyed ? _platform : null;
|
return _platform && !_platform.destroyed ? _platform : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,9 +227,9 @@ function _callAndReportToErrorHandler(errorHandler: ErrorHandler, callback: () =
|
|||||||
// rethrow as the exception handler might not do it
|
// rethrow as the exception handler might not do it
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorHandler.handleError(e);
|
errorHandler.handleError(e);
|
||||||
// rethrow as the exception handler might not do it
|
// rethrow as the exception handler might not do it
|
||||||
@ -238,7 +241,6 @@ function _callAndReportToErrorHandler(errorHandler: ErrorHandler, callback: () =
|
|||||||
export class PlatformRef_ extends PlatformRef {
|
export class PlatformRef_ extends PlatformRef {
|
||||||
private _modules: NgModuleRef<any>[] = [];
|
private _modules: NgModuleRef<any>[] = [];
|
||||||
private _destroyListeners: Function[] = [];
|
private _destroyListeners: Function[] = [];
|
||||||
|
|
||||||
private _destroyed: boolean = false;
|
private _destroyed: boolean = false;
|
||||||
|
|
||||||
constructor(private _injector: Injector) { super(); }
|
constructor(private _injector: Injector) { super(); }
|
||||||
@ -253,8 +255,8 @@ export class PlatformRef_ extends PlatformRef {
|
|||||||
if (this._destroyed) {
|
if (this._destroyed) {
|
||||||
throw new Error('The platform has already been destroyed!');
|
throw new Error('The platform has already been destroyed!');
|
||||||
}
|
}
|
||||||
ListWrapper.clone(this._modules).forEach((app) => app.destroy());
|
this._modules.slice().forEach(module => module.destroy());
|
||||||
this._destroyListeners.forEach((dispose) => dispose());
|
this._destroyListeners.forEach(listener => listener());
|
||||||
this._destroyed = true;
|
this._destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +303,7 @@ export class PlatformRef_ extends PlatformRef {
|
|||||||
componentFactoryCallback?: any): Promise<NgModuleRef<M>> {
|
componentFactoryCallback?: any): Promise<NgModuleRef<M>> {
|
||||||
const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);
|
const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);
|
||||||
const compiler = compilerFactory.createCompiler(
|
const compiler = compilerFactory.createCompiler(
|
||||||
compilerOptions instanceof Array ? compilerOptions : [compilerOptions]);
|
Array.isArray(compilerOptions) ? compilerOptions : [compilerOptions]);
|
||||||
|
|
||||||
// ugly internal api hack: generate host component factories for all declared components and
|
// ugly internal api hack: generate host component factories for all declared components and
|
||||||
// pass the factories into the callback - this is used by UpdateAdapter to get hold of all
|
// pass the factories into the callback - this is used by UpdateAdapter to get hold of all
|
||||||
@ -424,10 +426,10 @@ export class ApplicationRef_ extends ApplicationRef {
|
|||||||
componentFactory = this._componentFactoryResolver.resolveComponentFactory(componentOrFactory);
|
componentFactory = this._componentFactoryResolver.resolveComponentFactory(componentOrFactory);
|
||||||
}
|
}
|
||||||
this._rootComponentTypes.push(componentFactory.componentType);
|
this._rootComponentTypes.push(componentFactory.componentType);
|
||||||
var compRef = componentFactory.create(this._injector, [], componentFactory.selector);
|
const compRef = componentFactory.create(this._injector, [], componentFactory.selector);
|
||||||
compRef.onDestroy(() => { this._unloadComponent(compRef); });
|
compRef.onDestroy(() => { this._unloadComponent(compRef); });
|
||||||
var testability = compRef.injector.get(Testability, null);
|
const testability = compRef.injector.get(Testability, null);
|
||||||
if (isPresent(testability)) {
|
if (testability) {
|
||||||
compRef.injector.get(TestabilityRegistry)
|
compRef.injector.get(TestabilityRegistry)
|
||||||
.registerApplication(compRef.location.nativeElement, testability);
|
.registerApplication(compRef.location.nativeElement, testability);
|
||||||
}
|
}
|
||||||
@ -454,7 +456,7 @@ export class ApplicationRef_ extends ApplicationRef {
|
|||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_unloadComponent(componentRef: ComponentRef<any>): void {
|
_unloadComponent(componentRef: ComponentRef<any>): void {
|
||||||
if (!ListWrapper.contains(this._rootComponents, componentRef)) {
|
if (this._rootComponents.indexOf(componentRef) == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.unregisterChangeDetector(componentRef.changeDetectorRef);
|
this.unregisterChangeDetector(componentRef.changeDetectorRef);
|
||||||
@ -466,7 +468,7 @@ export class ApplicationRef_ extends ApplicationRef {
|
|||||||
throw new Error('ApplicationRef.tick is called recursively');
|
throw new Error('ApplicationRef.tick is called recursively');
|
||||||
}
|
}
|
||||||
|
|
||||||
var s = ApplicationRef_._tickScope();
|
const scope = ApplicationRef_._tickScope();
|
||||||
try {
|
try {
|
||||||
this._runningTick = true;
|
this._runningTick = true;
|
||||||
this._changeDetectorRefs.forEach((detector) => detector.detectChanges());
|
this._changeDetectorRefs.forEach((detector) => detector.detectChanges());
|
||||||
@ -475,13 +477,13 @@ export class ApplicationRef_ extends ApplicationRef {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this._runningTick = false;
|
this._runningTick = false;
|
||||||
wtfLeave(s);
|
wtfLeave(scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
// TODO(alxhub): Dispose of the NgZone.
|
// TODO(alxhub): Dispose of the NgZone.
|
||||||
ListWrapper.clone(this._rootComponents).forEach((ref) => ref.destroy());
|
this._rootComponents.slice().forEach((component) => component.destroy());
|
||||||
}
|
}
|
||||||
|
|
||||||
get componentTypes(): Type<any>[] { return this._rootComponentTypes; }
|
get componentTypes(): Type<any>[] { return this._rootComponentTypes; }
|
||||||
|
@ -34,7 +34,7 @@ export function _appIdRandomProviderFactory() {
|
|||||||
export const APP_ID_RANDOM_PROVIDER = {
|
export const APP_ID_RANDOM_PROVIDER = {
|
||||||
provide: APP_ID,
|
provide: APP_ID,
|
||||||
useFactory: _appIdRandomProviderFactory,
|
useFactory: _appIdRandomProviderFactory,
|
||||||
deps: <any[]>[]
|
deps: <any[]>[],
|
||||||
};
|
};
|
||||||
|
|
||||||
function _randomChar(): string {
|
function _randomChar(): string {
|
||||||
|
@ -121,7 +121,7 @@ export class ReflectiveProtoInjectorDynamicStrategy implements ReflectiveProtoIn
|
|||||||
constructor(protoInj: ReflectiveProtoInjector, public providers: ResolvedReflectiveProvider[]) {
|
constructor(protoInj: ReflectiveProtoInjector, public providers: ResolvedReflectiveProvider[]) {
|
||||||
var len = providers.length;
|
var len = providers.length;
|
||||||
|
|
||||||
this.keyIds = ListWrapper.createFixedSize(len);
|
this.keyIds = new Array(len);
|
||||||
|
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
this.keyIds[i] = providers[i].key.id;
|
this.keyIds[i] = providers[i].key.id;
|
||||||
@ -286,7 +286,7 @@ export class ReflectiveInjectorDynamicStrategy implements ReflectiveInjectorStra
|
|||||||
constructor(
|
constructor(
|
||||||
public protoStrategy: ReflectiveProtoInjectorDynamicStrategy,
|
public protoStrategy: ReflectiveProtoInjectorDynamicStrategy,
|
||||||
public injector: ReflectiveInjector_) {
|
public injector: ReflectiveInjector_) {
|
||||||
this.objs = ListWrapper.createFixedSize(protoStrategy.providers.length);
|
this.objs = new Array(protoStrategy.providers.length);
|
||||||
ListWrapper.fill(this.objs, UNDEFINED);
|
ListWrapper.fill(this.objs, UNDEFINED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +648,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
|
|||||||
|
|
||||||
private _instantiateProvider(provider: ResolvedReflectiveProvider): any {
|
private _instantiateProvider(provider: ResolvedReflectiveProvider): any {
|
||||||
if (provider.multiProvider) {
|
if (provider.multiProvider) {
|
||||||
var res = ListWrapper.createFixedSize(provider.resolvedFactories.length);
|
var res = new Array(provider.resolvedFactories.length);
|
||||||
for (var i = 0; i < provider.resolvedFactories.length; ++i) {
|
for (var i = 0; i < provider.resolvedFactories.length; ++i) {
|
||||||
res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
|
res[i] = this._instantiate(provider, provider.resolvedFactories[i]);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import {APP_ID} from '../application_tokens';
|
|||||||
import {devModeEqual} from '../change_detection/change_detection';
|
import {devModeEqual} from '../change_detection/change_detection';
|
||||||
import {UNINITIALIZED} from '../change_detection/change_detection_util';
|
import {UNINITIALIZED} from '../change_detection/change_detection_util';
|
||||||
import {Inject, Injectable} from '../di';
|
import {Inject, Injectable} from '../di';
|
||||||
import {ListWrapper} from '../facade/collection';
|
|
||||||
import {isBlank, isPresent, looseIdentical} from '../facade/lang';
|
import {isBlank, isPresent, looseIdentical} from '../facade/lang';
|
||||||
import {ViewEncapsulation} from '../metadata/view';
|
import {ViewEncapsulation} from '../metadata/view';
|
||||||
import {RenderComponentType, Renderer, RootRenderer} from '../render/api';
|
import {RenderComponentType, Renderer, RootRenderer} from '../render/api';
|
||||||
@ -77,7 +76,7 @@ export function ensureSlotCount(projectableNodes: any[][], expectedSlotCount: nu
|
|||||||
res = EMPTY_ARR;
|
res = EMPTY_ARR;
|
||||||
} else if (projectableNodes.length < expectedSlotCount) {
|
} else if (projectableNodes.length < expectedSlotCount) {
|
||||||
var givenSlotCount = projectableNodes.length;
|
var givenSlotCount = projectableNodes.length;
|
||||||
res = ListWrapper.createFixedSize(expectedSlotCount);
|
res = new Array(expectedSlotCount);
|
||||||
for (var i = 0; i < expectedSlotCount; i++) {
|
for (var i = 0; i < expectedSlotCount; i++) {
|
||||||
res[i] = (i < givenSlotCount) ? projectableNodes[i] : EMPTY_ARR;
|
res[i] = (i < givenSlotCount) ? projectableNodes[i] : EMPTY_ARR;
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,6 @@ import {Attribute, ContentChild, ContentChildren, Query, ViewChild, ViewChildren
|
|||||||
import {Component, Directive, HostBinding, HostListener, Input, Output, Pipe} from './metadata/directives';
|
import {Component, Directive, HostBinding, HostListener, Input, Output, Pipe} from './metadata/directives';
|
||||||
import {ModuleWithProviders, NgModule, SchemaMetadata} from './metadata/ng_module';
|
import {ModuleWithProviders, NgModule, SchemaMetadata} from './metadata/ng_module';
|
||||||
import {ViewEncapsulation} from './metadata/view';
|
import {ViewEncapsulation} from './metadata/view';
|
||||||
import {Type} from './type';
|
|
||||||
import {TypeDecorator, makeParamDecorator, makePropDecorator} from './util/decorators';
|
|
||||||
|
|
||||||
export {ANALYZE_FOR_ENTRY_COMPONENTS, Attribute, ContentChild, ContentChildDecorator, ContentChildren, ContentChildrenDecorator, Query, ViewChild, ViewChildDecorator, ViewChildren, ViewChildrenDecorator} from './metadata/di';
|
export {ANALYZE_FOR_ENTRY_COMPONENTS, Attribute, ContentChild, ContentChildDecorator, ContentChildren, ContentChildrenDecorator, Query, ViewChild, ViewChildDecorator, ViewChildren, ViewChildrenDecorator} from './metadata/di';
|
||||||
export {Component, ComponentDecorator, Directive, DirectiveDecorator, HostBinding, HostListener, Input, Output, Pipe} from './metadata/directives';
|
export {Component, ComponentDecorator, Directive, DirectiveDecorator, HostBinding, HostListener, Input, Output, Pipe} from './metadata/directives';
|
||||||
|
@ -448,15 +448,15 @@ export interface ComponentDecorator {
|
|||||||
* * **changeDetection** - change detection strategy used by this component
|
* * **changeDetection** - change detection strategy used by this component
|
||||||
* * **encapsulation** - style encapsulation strategy used by this component
|
* * **encapsulation** - style encapsulation strategy used by this component
|
||||||
* * **entryComponents** - list of components that are dynamically inserted into the view of this
|
* * **entryComponents** - list of components that are dynamically inserted into the view of this
|
||||||
* component
|
* component
|
||||||
* * **exportAs** - name under which the component instance is exported in a template
|
* * **exportAs** - name under which the component instance is exported in a template
|
||||||
* * **host** - map of class property to host element bindings for events, properties and
|
* * **host** - map of class property to host element bindings for events, properties and
|
||||||
* attributes
|
* attributes
|
||||||
* * **inputs** - list of class property names to data-bind as component inputs
|
* * **inputs** - list of class property names to data-bind as component inputs
|
||||||
* * **interpolation** - custom interpolation markers used in this component's template
|
* * **interpolation** - custom interpolation markers used in this component's template
|
||||||
* * **moduleId** - ES/CommonJS module id of the file in which this component is defined
|
* * **moduleId** - ES/CommonJS module id of the file in which this component is defined
|
||||||
* * **outputs** - list of class property names that expose output events that others can
|
* * **outputs** - list of class property names that expose output events that others can
|
||||||
* subscribe to
|
* subscribe to
|
||||||
* * **providers** - list of providers available to this component and its children
|
* * **providers** - list of providers available to this component and its children
|
||||||
* * **queries** - configure queries that can be injected into the component
|
* * **queries** - configure queries that can be injected into the component
|
||||||
* * **selector** - css selector that identifies this component in a template
|
* * **selector** - css selector that identifies this component in a template
|
||||||
@ -655,20 +655,33 @@ export interface Component extends Directive {
|
|||||||
animations?: AnimationEntryMetadata[];
|
animations?: AnimationEntryMetadata[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify how the template and the styles should be encapsulated.
|
* Specifies how the template and the styles should be encapsulated:
|
||||||
* The default is {@link ViewEncapsulation#Emulated `ViewEncapsulation.Emulated`} if the view
|
* - {@link ViewEncapsulation#Native `ViewEncapsulation.Native`} to use shadow roots - only works
|
||||||
* has styles,
|
* if natively available on the platform,
|
||||||
* otherwise {@link ViewEncapsulation#None `ViewEncapsulation.None`}.
|
* - {@link ViewEncapsulation#Emulated `ViewEncapsulation.Emulated`} to use shimmed CSS that
|
||||||
|
* emulates the native behavior,
|
||||||
|
* - {@link ViewEncapsulation#None `ViewEncapsulation.None`} to use global CSS without any
|
||||||
|
* encapsulation.
|
||||||
|
*
|
||||||
|
* When no `encapsulation` is defined for the component, the default value from the
|
||||||
|
* {@link CompilerConfig} is used. The default is `ViewEncapsulation.Emulated`}. Provide a new
|
||||||
|
* `CompilerConfig` to override this value.
|
||||||
|
*
|
||||||
|
* If the encapsulation is set to `ViewEncapsulation.Emulated` and the component has no `styles`
|
||||||
|
* nor `styleUrls` the encapsulation will automatically be switched to `ViewEncapsulation.None`.
|
||||||
*/
|
*/
|
||||||
encapsulation?: ViewEncapsulation;
|
encapsulation?: ViewEncapsulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the default encapsulation start and end delimiters (respectively `{{` and `}}`)
|
||||||
|
*/
|
||||||
interpolation?: [string, string];
|
interpolation?: [string, string];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the components that should be compiled as well when
|
* Defines the components that should be compiled as well when
|
||||||
* this component is defined. For each components listed here,
|
* this component is defined. For each components listed here,
|
||||||
* Angular will create a {@link ComponentFactory ComponentFactory} and store it in the
|
* Angular will create a {@link ComponentFactory} and store it in the
|
||||||
* {@link ComponentFactoryResolver ComponentFactoryResolver}.
|
* {@link ComponentFactoryResolver}.
|
||||||
*/
|
*/
|
||||||
entryComponents?: Array<Type<any>|any[]>;
|
entryComponents?: Array<Type<any>|any[]>;
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {AnimationEntryMetadata} from '../animation/metadata';
|
import {AnimationEntryMetadata} from '../animation/metadata';
|
||||||
import {Type} from '../type';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines template and style encapsulation options available for Component's {@link Component}.
|
* Defines template and style encapsulation options available for Component's {@link Component}.
|
||||||
@ -46,13 +44,6 @@ export var VIEW_ENCAPSULATION_VALUES =
|
|||||||
/**
|
/**
|
||||||
* Metadata properties available for configuring Views.
|
* Metadata properties available for configuring Views.
|
||||||
*
|
*
|
||||||
* Each Angular component requires a single `@Component` and at least one `@View` annotation. The
|
|
||||||
* `@View` annotation specifies the HTML template to use, and lists the directives that are active
|
|
||||||
* within the template.
|
|
||||||
*
|
|
||||||
* When a component is instantiated, the template is loaded into the component's shadow root, and
|
|
||||||
* the expressions and statements in the template are evaluated against the component.
|
|
||||||
*
|
|
||||||
* For details on the `@Component` annotation, see {@link Component}.
|
* For details on the `@Component` annotation, see {@link Component}.
|
||||||
*
|
*
|
||||||
* ### Example
|
* ### Example
|
||||||
@ -61,7 +52,6 @@ export var VIEW_ENCAPSULATION_VALUES =
|
|||||||
* @Component({
|
* @Component({
|
||||||
* selector: 'greet',
|
* selector: 'greet',
|
||||||
* template: 'Hello {{name}}!',
|
* template: 'Hello {{name}}!',
|
||||||
* directives: [GreetUser, Bold]
|
|
||||||
* })
|
* })
|
||||||
* class Greet {
|
* class Greet {
|
||||||
* name: string;
|
* name: string;
|
||||||
@ -73,46 +63,23 @@ export var VIEW_ENCAPSULATION_VALUES =
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @deprecated Use Component instead.
|
* @deprecated Use Component instead.
|
||||||
|
*
|
||||||
|
* {@link Component}
|
||||||
*/
|
*/
|
||||||
export class ViewMetadata {
|
export class ViewMetadata {
|
||||||
/**
|
/** {@link Component.templateUrl} */
|
||||||
* Specifies a template URL for an Angular component.
|
|
||||||
*
|
|
||||||
* NOTE: Only one of `templateUrl` or `template` can be defined per View.
|
|
||||||
*
|
|
||||||
* <!-- TODO: what's the url relative to? -->
|
|
||||||
*/
|
|
||||||
templateUrl: string;
|
templateUrl: string;
|
||||||
|
/** {@link Component.template} */
|
||||||
/**
|
|
||||||
* Specifies an inline template for an Angular component.
|
|
||||||
*
|
|
||||||
* NOTE: Only one of `templateUrl` or `template` can be defined per View.
|
|
||||||
*/
|
|
||||||
template: string;
|
template: string;
|
||||||
|
/** {@link Component.stylesUrl} */
|
||||||
/**
|
|
||||||
* Specifies stylesheet URLs for an Angular component.
|
|
||||||
*
|
|
||||||
* <!-- TODO: what's the url relative to? -->
|
|
||||||
*/
|
|
||||||
styleUrls: string[];
|
styleUrls: string[];
|
||||||
|
/** {@link Component.styles} */
|
||||||
/**
|
|
||||||
* Specifies an inline stylesheet for an Angular component.
|
|
||||||
*/
|
|
||||||
styles: string[];
|
styles: string[];
|
||||||
|
/** {@link Component.encapsulation} */
|
||||||
/**
|
|
||||||
* Specify how the template and the styles should be encapsulated.
|
|
||||||
* The default is {@link ViewEncapsulation#Emulated `ViewEncapsulation.Emulated`} if the view
|
|
||||||
* has styles,
|
|
||||||
* otherwise {@link ViewEncapsulation#None `ViewEncapsulation.None`}.
|
|
||||||
*/
|
|
||||||
encapsulation: ViewEncapsulation;
|
encapsulation: ViewEncapsulation;
|
||||||
|
/** {@link Component.animation} */
|
||||||
animations: AnimationEntryMetadata[];
|
animations: AnimationEntryMetadata[];
|
||||||
|
/** {@link Component.interpolation} */
|
||||||
interpolation: [string, string];
|
interpolation: [string, string];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import {PlatformRef, PlatformRef_, createPlatformFactory} from './application_ref';
|
import {PlatformRef, PlatformRef_, createPlatformFactory} from './application_ref';
|
||||||
import {Console} from './console';
|
import {Console} from './console';
|
||||||
import {ClassProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ValueProvider} from './di';
|
import {Provider} from './di';
|
||||||
import {Reflector, reflector} from './reflection/reflection';
|
import {Reflector, reflector} from './reflection/reflection';
|
||||||
import {ReflectorReader} from './reflection/reflector_reader';
|
import {ReflectorReader} from './reflection/reflector_reader';
|
||||||
import {TestabilityRegistry} from './testability/testability';
|
import {TestabilityRegistry} from './testability/testability';
|
||||||
@ -18,9 +18,12 @@ function _reflector(): Reflector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _CORE_PLATFORM_PROVIDERS: Provider[] = [
|
const _CORE_PLATFORM_PROVIDERS: Provider[] = [
|
||||||
PlatformRef_, {provide: PlatformRef, useExisting: PlatformRef_},
|
PlatformRef_,
|
||||||
|
{provide: PlatformRef, useExisting: PlatformRef_},
|
||||||
{provide: Reflector, useFactory: _reflector, deps: []},
|
{provide: Reflector, useFactory: _reflector, deps: []},
|
||||||
{provide: ReflectorReader, useExisting: Reflector}, TestabilityRegistry, Console
|
{provide: ReflectorReader, useExisting: Reflector},
|
||||||
|
TestabilityRegistry,
|
||||||
|
Console,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 {Map, MapWrapper, Set, SetWrapper, StringMapWrapper} from '../facade/collection';
|
import {MapWrapper, SetWrapper, StringMapWrapper} from '../facade/collection';
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
import {PlatformReflectionCapabilities} from './platform_reflection_capabilities';
|
import {PlatformReflectionCapabilities} from './platform_reflection_capabilities';
|
||||||
@ -40,14 +40,9 @@ export class Reflector extends ReflectorReader {
|
|||||||
/** @internal */
|
/** @internal */
|
||||||
_methods = new Map<string, MethodFn>();
|
_methods = new Map<string, MethodFn>();
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_usedKeys: Set<any>;
|
_usedKeys: Set<any> = null;
|
||||||
reflectionCapabilities: PlatformReflectionCapabilities;
|
|
||||||
|
|
||||||
constructor(reflectionCapabilities: PlatformReflectionCapabilities) {
|
constructor(public reflectionCapabilities: PlatformReflectionCapabilities) { super(); }
|
||||||
super();
|
|
||||||
this._usedKeys = null;
|
|
||||||
this.reflectionCapabilities = reflectionCapabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCapabilities(caps: PlatformReflectionCapabilities) { this.reflectionCapabilities = caps; }
|
updateCapabilities(caps: PlatformReflectionCapabilities) { this.reflectionCapabilities = caps; }
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Injectable} from '../di';
|
import {Injectable} from '../di';
|
||||||
import {Map, MapWrapper} from '../facade/collection';
|
import {MapWrapper} from '../facade/collection';
|
||||||
import {scheduleMicroTask} from '../facade/lang';
|
import {scheduleMicroTask} from '../facade/lang';
|
||||||
import {NgZone} from '../zone/ng_zone';
|
import {NgZone} from '../zone/ng_zone';
|
||||||
|
|
||||||
@ -110,6 +110,7 @@ export class Testability implements PublicTestability {
|
|||||||
|
|
||||||
getPendingRequestCount(): number { return this._pendingCount; }
|
getPendingRequestCount(): number { return this._pendingCount; }
|
||||||
|
|
||||||
|
/** @deprecated use findProviders */
|
||||||
findBindings(using: any, provider: string, exactMatch: boolean): any[] {
|
findBindings(using: any, provider: string, exactMatch: boolean): any[] {
|
||||||
// TODO(juliemr): implement.
|
// TODO(juliemr): implement.
|
||||||
return [];
|
return [];
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export var Type = Function;
|
export const Type = Function;
|
||||||
|
|
||||||
|
|
||||||
export interface Type<T> extends Function { new (...args: any[]): T; }
|
export interface Type<T> extends Function { new (...args: any[]): T; }
|
||||||
|
@ -79,6 +79,24 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
expect(fixture.nativeElement).toHaveText('counting method value');
|
expect(fixture.nativeElement).toHaveText('counting method value');
|
||||||
expect(MyCountingComp.calls).toBe(1);
|
expect(MyCountingComp.calls).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should evalute a conditional in a statement binding', () => {
|
||||||
|
@Component({selector: 'some-comp', template: '<p (click)="nullValue?.click()"></p>'})
|
||||||
|
class SomeComponent {
|
||||||
|
nullValue: SomeReferencedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SomeReferencedClass {
|
||||||
|
click() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
const fixture = TestBed.configureTestingModule({declarations: [SomeComponent]})
|
||||||
|
.createComponent(SomeComponent);
|
||||||
|
|
||||||
|
fixture.detectChanges(/* checkNoChanges */ false);
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('providers', () => {
|
describe('providers', () => {
|
||||||
|
@ -6,9 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '@angular/core';
|
import {Component, Directive, Input, NO_ERRORS_SCHEMA} from '@angular/core';
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing';
|
||||||
import {TestBed, getTestBed} from '@angular/core/testing';
|
|
||||||
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
|
import {afterEach, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
|
||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service';
|
import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service';
|
||||||
@ -24,12 +23,22 @@ class SecuredComponent {
|
|||||||
ctxProp: any = 'some value';
|
ctxProp: any = 'some value';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Directive({selector: '[onPrefixedProp]'})
|
||||||
|
class OnPrefixDir {
|
||||||
|
@Input() onPrefixedProp: any;
|
||||||
|
@Input() onclick: any;
|
||||||
|
}
|
||||||
|
|
||||||
function declareTests({useJit}: {useJit: boolean}) {
|
function declareTests({useJit}: {useJit: boolean}) {
|
||||||
describe('security integration tests', function() {
|
describe('security integration tests', function() {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureCompiler({useJit: useJit});
|
TestBed.configureCompiler({useJit: useJit}).configureTestingModule({
|
||||||
TestBed.configureTestingModule({declarations: [SecuredComponent]});
|
declarations: [
|
||||||
|
SecuredComponent,
|
||||||
|
OnPrefixDir,
|
||||||
|
]
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let originalLog: (msg: any) => any;
|
let originalLog: (msg: any) => any;
|
||||||
@ -43,15 +52,10 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
it('should disallow binding to attr.on*', () => {
|
it('should disallow binding to attr.on*', () => {
|
||||||
const template = `<div [attr.onclick]="ctxProp"></div>`;
|
const template = `<div [attr.onclick]="ctxProp"></div>`;
|
||||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||||
try {
|
|
||||||
TestBed.createComponent(SecuredComponent);
|
expect(() => TestBed.createComponent(SecuredComponent))
|
||||||
throw 'Should throw';
|
.toThrowError(
|
||||||
} catch (e) {
|
/Binding to event attribute 'onclick' is disallowed for security reasons, please use \(click\)=.../);
|
||||||
expect(e.message).toContain(
|
|
||||||
`Template parse errors:\n` +
|
|
||||||
`Binding to event attribute 'onclick' is disallowed ` +
|
|
||||||
`for security reasons, please use (click)=... `);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disallow binding to on* with NO_ERRORS_SCHEMA', () => {
|
it('should disallow binding to on* with NO_ERRORS_SCHEMA', () => {
|
||||||
@ -59,17 +63,31 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({
|
TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
});
|
});
|
||||||
;
|
|
||||||
try {
|
expect(() => TestBed.createComponent(SecuredComponent))
|
||||||
TestBed.createComponent(SecuredComponent);
|
.toThrowError(
|
||||||
throw 'Should throw';
|
/Binding to event attribute 'onclick' is disallowed for security reasons, please use \(click\)=.../);
|
||||||
} catch (e) {
|
|
||||||
expect(e.message).toContain(
|
|
||||||
`Template parse errors:\n` +
|
|
||||||
`Binding to event attribute 'onclick' is disallowed ` +
|
|
||||||
`for security reasons, please use (click)=... `);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should disallow binding to on* unless it is consumed by a directive', () => {
|
||||||
|
const template = `<div [onPrefixedProp]="ctxProp" [onclick]="ctxProp"></div>`;
|
||||||
|
TestBed.overrideComponent(SecuredComponent, {set: {template}}).configureTestingModule({
|
||||||
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
|
});
|
||||||
|
|
||||||
|
// should not throw for inputs starting with "on"
|
||||||
|
let cmp: ComponentFixture<SecuredComponent>;
|
||||||
|
expect(() => cmp = TestBed.createComponent(SecuredComponent)).not.toThrow();
|
||||||
|
|
||||||
|
// must bind to the directive not to the property of the div
|
||||||
|
const value = cmp.componentInstance.ctxProp = {};
|
||||||
|
cmp.detectChanges();
|
||||||
|
const div = cmp.debugElement.children[0];
|
||||||
|
expect(div.injector.get(OnPrefixDir).onclick).toBe(value);
|
||||||
|
expect(getDOM().getProperty(div.nativeElement, 'onclick')).not.toBe(value);
|
||||||
|
expect(getDOM().hasAttribute(div.nativeElement, 'onclick')).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('safe HTML values', function() {
|
describe('safe HTML values', function() {
|
||||||
@ -157,12 +175,8 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||||||
const template = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
|
const template = `<svg:circle [xlink:href]="ctxProp">Text</svg:circle>`;
|
||||||
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
TestBed.overrideComponent(SecuredComponent, {set: {template}});
|
||||||
|
|
||||||
try {
|
expect(() => TestBed.createComponent(SecuredComponent))
|
||||||
TestBed.createComponent(SecuredComponent);
|
.toThrowError(/Can't bind to 'xlink:href'/);
|
||||||
throw 'Should throw';
|
|
||||||
} catch (e) {
|
|
||||||
expect(e.message).toContain(`Can't bind to 'xlink:href'`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should escape unsafe HTML values', () => {
|
it('should escape unsafe HTML values', () => {
|
||||||
|
@ -47,7 +47,13 @@ export type TestModuleMetadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @experimental
|
* @whatItDoes Configures and initializes environment for unit testing and provides methods for
|
||||||
|
* creating components and services in unit tests.
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* TestBed is the primary api for writing unit tests for Angular applications and libraries.
|
||||||
|
*
|
||||||
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class TestBed implements Injector {
|
export class TestBed implements Injector {
|
||||||
/**
|
/**
|
||||||
|
@ -8,12 +8,9 @@
|
|||||||
|
|
||||||
import {getSymbolIterator, global, isArray, isBlank, isJsObject, isPresent} from './lang';
|
import {getSymbolIterator, global, isArray, isBlank, isJsObject, isPresent} from './lang';
|
||||||
|
|
||||||
export var Map = global.Map;
|
|
||||||
export var Set = global.Set;
|
|
||||||
|
|
||||||
// Safari and Internet Explorer do not support the iterable parameter to the
|
// Safari and Internet Explorer do not support the iterable parameter to the
|
||||||
// Map constructor. We work around that by manually adding the items.
|
// Map constructor. We work around that by manually adding the items.
|
||||||
var createMapFromPairs: {(pairs: any[]): Map<any, any>} = (function() {
|
const createMapFromPairs: {(pairs: any[]): Map<any, any>} = (function() {
|
||||||
try {
|
try {
|
||||||
if (new Map(<any>[[1, 2]]).size === 1) {
|
if (new Map(<any>[[1, 2]]).size === 1) {
|
||||||
return function createMapFromPairs(pairs: any[]): Map<any, any> { return new Map(pairs); };
|
return function createMapFromPairs(pairs: any[]): Map<any, any> { return new Map(pairs); };
|
||||||
@ -29,7 +26,7 @@ var createMapFromPairs: {(pairs: any[]): Map<any, any>} = (function() {
|
|||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
var createMapFromMap: {(m: Map<any, any>): Map<any, any>} = (function() {
|
const createMapFromMap: {(m: Map<any, any>): Map<any, any>} = (function() {
|
||||||
try {
|
try {
|
||||||
if (new Map(<any>new Map())) {
|
if (new Map(<any>new Map())) {
|
||||||
return function createMapFromMap(m: Map<any, any>): Map<any, any> { return new Map(<any>m); };
|
return function createMapFromMap(m: Map<any, any>): Map<any, any> { return new Map(<any>m); };
|
||||||
@ -42,7 +39,7 @@ var createMapFromMap: {(m: Map<any, any>): Map<any, any>} = (function() {
|
|||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
var _clearValues: {(m: Map<any, any>): void} = (function() {
|
const _clearValues: {(m: Map<any, any>): void} = (function() {
|
||||||
if ((<any>(new Map()).keys()).next) {
|
if ((<any>(new Map()).keys()).next) {
|
||||||
return function _clearValues(m: Map<any, any>) {
|
return function _clearValues(m: Map<any, any>) {
|
||||||
var keyIterator = m.keys();
|
var keyIterator = m.keys();
|
||||||
@ -69,7 +66,7 @@ var _arrayFromMap: {(m: Map<any, any>, getValues: boolean): any[]} = (function()
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
return function createArrayFromMapWithForeach(m: Map<any, any>, getValues: boolean): any[] {
|
return function createArrayFromMapWithForeach(m: Map<any, any>, getValues: boolean): any[] {
|
||||||
var res = ListWrapper.createFixedSize(m.size), i = 0;
|
var res = new Array(m.size), i = 0;
|
||||||
m.forEach((v, k) => {
|
m.forEach((v, k) => {
|
||||||
res[i] = getValues ? v : k;
|
res[i] = getValues ? v : k;
|
||||||
i++;
|
i++;
|
||||||
@ -79,7 +76,6 @@ var _arrayFromMap: {(m: Map<any, any>, getValues: boolean): any[]} = (function()
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
export class MapWrapper {
|
export class MapWrapper {
|
||||||
static clone<K, V>(m: Map<K, V>): Map<K, V> { return createMapFromMap(m); }
|
|
||||||
static createFromStringMap<T>(stringMap: {[key: string]: T}): Map<string, T> {
|
static createFromStringMap<T>(stringMap: {[key: string]: T}): Map<string, T> {
|
||||||
var result = new Map<string, T>();
|
var result = new Map<string, T>();
|
||||||
for (var prop in stringMap) {
|
for (var prop in stringMap) {
|
||||||
@ -93,7 +89,6 @@ export class MapWrapper {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
static createFromPairs(pairs: any[]): Map<any, any> { return createMapFromPairs(pairs); }
|
static createFromPairs(pairs: any[]): Map<any, any> { return createMapFromPairs(pairs); }
|
||||||
static clearValues(m: Map<any, any>) { _clearValues(m); }
|
|
||||||
static iterable<T>(m: T): T { return m; }
|
static iterable<T>(m: T): T { return m; }
|
||||||
static keys<K>(m: Map<K, any>): K[] { return _arrayFromMap(m, false); }
|
static keys<K>(m: Map<K, any>): K[] { return _arrayFromMap(m, false); }
|
||||||
static values<V>(m: Map<any, V>): V[] { return _arrayFromMap(m, true); }
|
static values<V>(m: Map<any, V>): V[] { return _arrayFromMap(m, true); }
|
||||||
@ -103,15 +98,6 @@ export class MapWrapper {
|
|||||||
* Wraps Javascript Objects
|
* Wraps Javascript Objects
|
||||||
*/
|
*/
|
||||||
export class StringMapWrapper {
|
export class StringMapWrapper {
|
||||||
static create(): {[k: /*any*/ string]: any} {
|
|
||||||
// Note: We are not using Object.create(null) here due to
|
|
||||||
// performance!
|
|
||||||
// http://jsperf.com/ng2-object-create-null
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
static contains(map: {[key: string]: any}, key: string): boolean {
|
|
||||||
return map.hasOwnProperty(key);
|
|
||||||
}
|
|
||||||
static get<V>(map: {[key: string]: V}, key: string): V {
|
static get<V>(map: {[key: string]: V}, key: string): V {
|
||||||
return map.hasOwnProperty(key) ? map[key] : undefined;
|
return map.hasOwnProperty(key) ? map[key] : undefined;
|
||||||
}
|
}
|
||||||
@ -127,7 +113,6 @@ export class StringMapWrapper {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static delete (map: {[key: string]: any}, key: string) { delete map[key]; }
|
|
||||||
static forEach<K, V>(map: {[key: string]: V}, callback: (v: V, K: string) => void) {
|
static forEach<K, V>(map: {[key: string]: V}, callback: (v: V, K: string) => void) {
|
||||||
for (let k of Object.keys(map)) {
|
for (let k of Object.keys(map)) {
|
||||||
callback(map[k], k);
|
callback(map[k], k);
|
||||||
|
@ -14,15 +14,13 @@ export function unimplemented(): any {
|
|||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
export class BaseError extends Error {
|
export class BaseError extends Error {
|
||||||
/**
|
/** @internal **/
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
_nativeError: Error;
|
_nativeError: Error;
|
||||||
|
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
// Errors don't use current this, instead they create a new instance.
|
// Errors don't use current this, instead they create a new instance.
|
||||||
// We have to do forward all of our api to the nativeInstance.
|
// We have to do forward all of our api to the nativeInstance.
|
||||||
var nativeError = super(message) as any as Error;
|
const nativeError = super(message) as any as Error;
|
||||||
this._nativeError = nativeError;
|
this._nativeError = nativeError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,11 +38,6 @@ export class BaseError extends Error {
|
|||||||
export class WrappedError extends BaseError {
|
export class WrappedError extends BaseError {
|
||||||
originalError: any;
|
originalError: any;
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
_nativeError: Error;
|
|
||||||
|
|
||||||
constructor(message: string, error: any) {
|
constructor(message: string, error: any) {
|
||||||
super(`${message} caused by: ${error instanceof Error ? error.message: error }`);
|
super(`${message} caused by: ${error instanceof Error ? error.message: error }`);
|
||||||
this.originalError = error;
|
this.originalError = error;
|
||||||
|
@ -200,7 +200,9 @@ export class NgModel extends NgControl implements OnChanges,
|
|||||||
|
|
||||||
private _updateDisabled(changes: SimpleChanges) {
|
private _updateDisabled(changes: SimpleChanges) {
|
||||||
const disabledValue = changes['isDisabled'].currentValue;
|
const disabledValue = changes['isDisabled'].currentValue;
|
||||||
const isDisabled = disabledValue != null && disabledValue != false;
|
|
||||||
|
const isDisabled =
|
||||||
|
disabledValue === '' || (disabledValue && disabledValue !== 'false');
|
||||||
|
|
||||||
resolvedPromise.then(() => {
|
resolvedPromise.then(() => {
|
||||||
if (isDisabled && !this.control.disabled) {
|
if (isDisabled && !this.control.disabled) {
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {Directive, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
import {Directive, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {EventEmitter} from '../../facade/async';
|
import {EventEmitter} from '../../facade/async';
|
||||||
import {StringMapWrapper} from '../../facade/collection';
|
|
||||||
import {FormControl} from '../../model';
|
import {FormControl} from '../../model';
|
||||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
||||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '../control_value_accessor';
|
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '../control_value_accessor';
|
||||||
@ -117,6 +116,6 @@ export class FormControlDirective extends NgControl implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _isControlChanged(changes: {[key: string]: any}): boolean {
|
private _isControlChanged(changes: {[key: string]: any}): boolean {
|
||||||
return StringMapWrapper.contains(changes, 'form');
|
return changes.hasOwnProperty('form');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {Directive, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
import {Directive, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {EventEmitter} from '../../facade/async';
|
import {EventEmitter} from '../../facade/async';
|
||||||
import {ListWrapper, StringMapWrapper} from '../../facade/collection';
|
import {ListWrapper} from '../../facade/collection';
|
||||||
import {isBlank} from '../../facade/lang';
|
import {isBlank} from '../../facade/lang';
|
||||||
import {FormArray, FormControl, FormGroup} from '../../model';
|
import {FormArray, FormControl, FormGroup} from '../../model';
|
||||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators';
|
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators';
|
||||||
@ -80,7 +80,7 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
|||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
this._checkFormPresent();
|
this._checkFormPresent();
|
||||||
if (StringMapWrapper.contains(changes, 'form')) {
|
if (changes.hasOwnProperty('form')) {
|
||||||
this._updateValidators();
|
this._updateValidators();
|
||||||
this._updateDomValue();
|
this._updateDomValue();
|
||||||
this._updateRegistrations();
|
this._updateRegistrations();
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {ListWrapper, StringMapWrapper} from '../facade/collection';
|
import {ListWrapper} from '../facade/collection';
|
||||||
import {hasConstructor, isBlank, isPresent, looseIdentical} from '../facade/lang';
|
import {hasConstructor, isBlank, isPresent, looseIdentical} from '../facade/lang';
|
||||||
import {FormArray, FormControl, FormGroup} from '../model';
|
import {FormArray, FormControl, FormGroup} from '../model';
|
||||||
import {Validators} from '../validators';
|
import {Validators} from '../validators';
|
||||||
@ -120,8 +120,8 @@ export function composeAsyncValidators(validators: /* Array<Validator|Function>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean {
|
export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean {
|
||||||
if (!StringMapWrapper.contains(changes, 'model')) return false;
|
if (!changes.hasOwnProperty('model')) return false;
|
||||||
var change = changes['model'];
|
const change = changes['model'];
|
||||||
|
|
||||||
if (change.isFirstChange()) return true;
|
if (change.isFirstChange()) return true;
|
||||||
return !looseIdentical(viewModel, change.currentValue);
|
return !looseIdentical(viewModel, change.currentValue);
|
||||||
|
@ -16,7 +16,6 @@ import {isBlank, isPresent, isStringMap, normalizeBool} from './facade/lang';
|
|||||||
import {isPromise} from './private_import_core';
|
import {isPromise} from './private_import_core';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a FormControl is valid, i.e. that no errors exist in the input value.
|
* Indicates that a FormControl is valid, i.e. that no errors exist in the input value.
|
||||||
*/
|
*/
|
||||||
@ -335,7 +334,7 @@ export abstract class AbstractControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._updateAncestors(onlySelf);
|
this._updateAncestors(onlySelf);
|
||||||
this._onDisabledChange(true);
|
this._onDisabledChange.forEach((changeFn) => changeFn(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -351,7 +350,7 @@ export abstract class AbstractControl {
|
|||||||
this.updateValueAndValidity({onlySelf: true, emitEvent: emitEvent});
|
this.updateValueAndValidity({onlySelf: true, emitEvent: emitEvent});
|
||||||
|
|
||||||
this._updateAncestors(onlySelf);
|
this._updateAncestors(onlySelf);
|
||||||
this._onDisabledChange(false);
|
this._onDisabledChange.forEach((changeFn) => changeFn(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateAncestors(onlySelf: boolean) {
|
private _updateAncestors(onlySelf: boolean) {
|
||||||
@ -596,7 +595,7 @@ export abstract class AbstractControl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_onDisabledChange(isDisabled: boolean): void {}
|
_onDisabledChange: Function[] = [];
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_isBoxedValue(formState: any): boolean {
|
_isBoxedValue(formState: any): boolean {
|
||||||
@ -771,14 +770,16 @@ export class FormControl extends AbstractControl {
|
|||||||
*/
|
*/
|
||||||
_clearChangeFns(): void {
|
_clearChangeFns(): void {
|
||||||
this._onChange = [];
|
this._onChange = [];
|
||||||
this._onDisabledChange = null;
|
this._onDisabledChange = [];
|
||||||
this._onCollectionChange = () => {};
|
this._onCollectionChange = () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a listener for disabled events.
|
* Register a listener for disabled events.
|
||||||
*/
|
*/
|
||||||
registerOnDisabledChange(fn: (isDisabled: boolean) => void): void { this._onDisabledChange = fn; }
|
registerOnDisabledChange(fn: (isDisabled: boolean) => void): void {
|
||||||
|
this._onDisabledChange.push(fn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -886,7 +887,7 @@ export class FormGroup extends AbstractControl {
|
|||||||
*/
|
*/
|
||||||
removeControl(name: string): void {
|
removeControl(name: string): void {
|
||||||
if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => {});
|
if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => {});
|
||||||
StringMapWrapper.delete(this.controls, name);
|
delete (this.controls[name]);
|
||||||
this.updateValueAndValidity();
|
this.updateValueAndValidity();
|
||||||
this._onCollectionChange();
|
this._onCollectionChange();
|
||||||
}
|
}
|
||||||
@ -896,7 +897,7 @@ export class FormGroup extends AbstractControl {
|
|||||||
*/
|
*/
|
||||||
setControl(name: string, control: AbstractControl): void {
|
setControl(name: string, control: AbstractControl): void {
|
||||||
if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => {});
|
if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => {});
|
||||||
StringMapWrapper.delete(this.controls, name);
|
delete (this.controls[name]);
|
||||||
if (control) this.registerControl(name, control);
|
if (control) this.registerControl(name, control);
|
||||||
this.updateValueAndValidity();
|
this.updateValueAndValidity();
|
||||||
this._onCollectionChange();
|
this._onCollectionChange();
|
||||||
|
@ -485,7 +485,7 @@ export function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('NgModel', () => {
|
describe('NgModel', () => {
|
||||||
var ngModel: any /** TODO #9100 */;
|
let ngModel: NgModel;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ngModel = new NgModel(
|
ngModel = new NgModel(
|
||||||
@ -539,6 +539,45 @@ export function main() {
|
|||||||
|
|
||||||
expect(ngModel.control.errors).toEqual({'async': true});
|
expect(ngModel.control.errors).toEqual({'async': true});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should mark as disabled properly', fakeAsync(() => {
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange('', undefined)});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(false);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange('', null)});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(false);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange('', false)});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(false);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange('', 'false')});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(false);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange('', 0)});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(false);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange(null, '')});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(true);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange(null, 'true')});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(true);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange(null, true)});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(true);
|
||||||
|
|
||||||
|
ngModel.ngOnChanges({isDisabled: new SimpleChange(null, 'anything else')});
|
||||||
|
tick();
|
||||||
|
expect(ngModel.control.disabled).toEqual(true);
|
||||||
|
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('FormControlName', () => {
|
describe('FormControlName', () => {
|
||||||
|
@ -1022,6 +1022,54 @@ export function main() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should disable all radio buttons when disable() is called', () => {
|
||||||
|
const fixture = TestBed.createComponent(FormControlRadioButtons);
|
||||||
|
const form =
|
||||||
|
new FormGroup({food: new FormControl('fish'), drink: new FormControl('cola')});
|
||||||
|
fixture.componentInstance.form = form;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const inputs = fixture.debugElement.queryAll(By.css('input'));
|
||||||
|
expect(inputs[0].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toEqual(false);
|
||||||
|
|
||||||
|
form.get('food').disable();
|
||||||
|
expect(inputs[0].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toEqual(false);
|
||||||
|
|
||||||
|
form.disable();
|
||||||
|
expect(inputs[0].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toEqual(true);
|
||||||
|
|
||||||
|
form.enable();
|
||||||
|
expect(inputs[0].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disable all radio buttons when initially disabled', () => {
|
||||||
|
const fixture = TestBed.createComponent(FormControlRadioButtons);
|
||||||
|
const form = new FormGroup({
|
||||||
|
food: new FormControl({value: 'fish', disabled: true}),
|
||||||
|
drink: new FormControl('cola')
|
||||||
|
});
|
||||||
|
fixture.componentInstance.form = form;
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const inputs = fixture.debugElement.queryAll(By.css('input'));
|
||||||
|
expect(inputs[0].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toEqual(true);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toEqual(false);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('custom value accessors', () => {
|
describe('custom value accessors', () => {
|
||||||
|
@ -420,6 +420,64 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should disable a control with unbound disabled attr', fakeAsync(() => {
|
||||||
|
TestBed.overrideComponent(NgModelForm, {
|
||||||
|
set: {
|
||||||
|
template: `
|
||||||
|
<form>
|
||||||
|
<input name="name" [(ngModel)]="name" disabled>
|
||||||
|
</form>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const fixture = TestBed.createComponent(NgModelForm);
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
const form = fixture.debugElement.children[0].injector.get(NgForm);
|
||||||
|
expect(form.control.get('name').disabled).toBe(true);
|
||||||
|
|
||||||
|
const input = fixture.debugElement.query(By.css('input'));
|
||||||
|
expect(input.nativeElement.disabled).toEqual(true);
|
||||||
|
|
||||||
|
form.control.enable();
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
expect(input.nativeElement.disabled).toEqual(false);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should disable radio controls properly with programmatic call', fakeAsync(() => {
|
||||||
|
const fixture = TestBed.createComponent(NgModelRadioForm);
|
||||||
|
fixture.componentInstance.food = 'fish';
|
||||||
|
fixture.detectChanges();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
const form = fixture.debugElement.children[0].injector.get(NgForm);
|
||||||
|
form.control.get('food').disable();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
const inputs = fixture.debugElement.queryAll(By.css('input'));
|
||||||
|
expect(inputs[0].nativeElement.disabled).toBe(true);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toBe(true);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toBe(false);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toBe(false);
|
||||||
|
|
||||||
|
form.control.disable();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(inputs[0].nativeElement.disabled).toBe(true);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toBe(true);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toBe(true);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toBe(true);
|
||||||
|
|
||||||
|
form.control.enable();
|
||||||
|
tick();
|
||||||
|
|
||||||
|
expect(inputs[0].nativeElement.disabled).toBe(false);
|
||||||
|
expect(inputs[1].nativeElement.disabled).toBe(false);
|
||||||
|
expect(inputs[2].nativeElement.disabled).toBe(false);
|
||||||
|
expect(inputs[3].nativeElement.disabled).toBe(false);
|
||||||
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('radio controls', () => {
|
describe('radio controls', () => {
|
||||||
@ -903,7 +961,7 @@ class NgModelOptionsStandalone {
|
|||||||
<form>
|
<form>
|
||||||
<input type="radio" name="food" [(ngModel)]="food" value="chicken">
|
<input type="radio" name="food" [(ngModel)]="food" value="chicken">
|
||||||
<input type="radio" name="food" [(ngModel)]="food" value="fish">
|
<input type="radio" name="food" [(ngModel)]="food" value="fish">
|
||||||
|
|
||||||
<input type="radio" name="drink" [(ngModel)]="drink" value="cola">
|
<input type="radio" name="drink" [(ngModel)]="drink" value="cola">
|
||||||
<input type="radio" name="drink" [(ngModel)]="drink" value="sprite">
|
<input type="radio" name="drink" [(ngModel)]="drink" value="sprite">
|
||||||
</form>
|
</form>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {ListWrapper, Map, MapWrapper, StringMapWrapper, isListLikeIterable, iterateListLike} from '../src/facade/collection';
|
import {ListWrapper, MapWrapper, StringMapWrapper, isListLikeIterable, iterateListLike} from '../src/facade/collection';
|
||||||
import {isBlank} from '../src/facade/lang';
|
import {isBlank} from '../src/facade/lang';
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ListWrapper, Map, isListLikeIterable} from '../src/facade/collection';
|
|
||||||
import {isPresent} from '../src/facade/lang';
|
|
||||||
|
|
||||||
function paramParser(rawParams: string = ''): Map<string, string[]> {
|
function paramParser(rawParams: string = ''): Map<string, string[]> {
|
||||||
const map = new Map<string, string[]>();
|
const map = new Map<string, string[]>();
|
||||||
if (rawParams.length > 0) {
|
if (rawParams.length > 0) {
|
||||||
@ -97,23 +94,16 @@ export class URLSearchParams {
|
|||||||
has(param: string): boolean { return this.paramsMap.has(param); }
|
has(param: string): boolean { return this.paramsMap.has(param); }
|
||||||
|
|
||||||
get(param: string): string {
|
get(param: string): string {
|
||||||
var storedParam = this.paramsMap.get(param);
|
const storedParam = this.paramsMap.get(param);
|
||||||
if (isListLikeIterable(storedParam)) {
|
|
||||||
return ListWrapper.first(storedParam);
|
return Array.isArray(storedParam) ? storedParam[0] : null;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAll(param: string): string[] {
|
getAll(param: string): string[] { return this.paramsMap.get(param) || []; }
|
||||||
var mapParam = this.paramsMap.get(param);
|
|
||||||
return isPresent(mapParam) ? mapParam : [];
|
|
||||||
}
|
|
||||||
|
|
||||||
set(param: string, val: string) {
|
set(param: string, val: string) {
|
||||||
var mapParam = this.paramsMap.get(param);
|
const list = this.paramsMap.get(param) || [];
|
||||||
var list = isPresent(mapParam) ? mapParam : [];
|
list.length = 0;
|
||||||
ListWrapper.clear(list);
|
|
||||||
list.push(val);
|
list.push(val);
|
||||||
this.paramsMap.set(param, list);
|
this.paramsMap.set(param, list);
|
||||||
}
|
}
|
||||||
@ -126,17 +116,15 @@ export class URLSearchParams {
|
|||||||
// TODO(@caitp): document this better
|
// TODO(@caitp): document this better
|
||||||
setAll(searchParams: URLSearchParams) {
|
setAll(searchParams: URLSearchParams) {
|
||||||
searchParams.paramsMap.forEach((value, param) => {
|
searchParams.paramsMap.forEach((value, param) => {
|
||||||
var mapParam = this.paramsMap.get(param);
|
const list = this.paramsMap.get(param) || [];
|
||||||
var list = isPresent(mapParam) ? mapParam : [];
|
list.length = 0;
|
||||||
ListWrapper.clear(list);
|
|
||||||
list.push(value[0]);
|
list.push(value[0]);
|
||||||
this.paramsMap.set(param, list);
|
this.paramsMap.set(param, list);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
append(param: string, val: string): void {
|
append(param: string, val: string): void {
|
||||||
var mapParam = this.paramsMap.get(param);
|
const list = this.paramsMap.get(param) || [];
|
||||||
var list = isPresent(mapParam) ? mapParam : [];
|
|
||||||
list.push(val);
|
list.push(val);
|
||||||
this.paramsMap.set(param, list);
|
this.paramsMap.set(param, list);
|
||||||
}
|
}
|
||||||
@ -150,9 +138,8 @@ export class URLSearchParams {
|
|||||||
// TODO(@caitp): document this better
|
// TODO(@caitp): document this better
|
||||||
appendAll(searchParams: URLSearchParams) {
|
appendAll(searchParams: URLSearchParams) {
|
||||||
searchParams.paramsMap.forEach((value, param) => {
|
searchParams.paramsMap.forEach((value, param) => {
|
||||||
var mapParam = this.paramsMap.get(param);
|
const list = this.paramsMap.get(param) || [];
|
||||||
var list = isPresent(mapParam) ? mapParam : [];
|
for (let i = 0; i < value.length; ++i) {
|
||||||
for (var i = 0; i < value.length; ++i) {
|
|
||||||
list.push(value[i]);
|
list.push(value[i]);
|
||||||
}
|
}
|
||||||
this.paramsMap.set(param, list);
|
this.paramsMap.set(param, list);
|
||||||
@ -169,9 +156,8 @@ export class URLSearchParams {
|
|||||||
// TODO(@caitp): document this better
|
// TODO(@caitp): document this better
|
||||||
replaceAll(searchParams: URLSearchParams) {
|
replaceAll(searchParams: URLSearchParams) {
|
||||||
searchParams.paramsMap.forEach((value, param) => {
|
searchParams.paramsMap.forEach((value, param) => {
|
||||||
var mapParam = this.paramsMap.get(param);
|
const list = this.paramsMap.get(param) || [];
|
||||||
var list = isPresent(mapParam) ? mapParam : [];
|
list.length = 0;
|
||||||
ListWrapper.clear(list);
|
|
||||||
for (var i = 0; i < value.length; ++i) {
|
for (var i = 0; i < value.length; ++i) {
|
||||||
list.push(value[i]);
|
list.push(value[i]);
|
||||||
}
|
}
|
||||||
@ -180,7 +166,7 @@ export class URLSearchParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
var paramsList: string[] = [];
|
const paramsList: string[] = [];
|
||||||
this.paramsMap.forEach((values, k) => {
|
this.paramsMap.forEach((values, k) => {
|
||||||
values.forEach(
|
values.forEach(
|
||||||
v => paramsList.push(
|
v => paramsList.push(
|
||||||
|
@ -9,19 +9,16 @@
|
|||||||
import {ReflectiveInjector} from '@angular/core';
|
import {ReflectiveInjector} from '@angular/core';
|
||||||
import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
|
|
||||||
import {BrowserJsonp} from '../../src/backends/browser_jsonp';
|
import {BrowserJsonp} from '../../src/backends/browser_jsonp';
|
||||||
import {JSONPBackend, JSONPBackend_, JSONPConnection, JSONPConnection_} from '../../src/backends/jsonp_backend';
|
import {JSONPBackend, JSONPBackend_, JSONPConnection, JSONPConnection_} from '../../src/backends/jsonp_backend';
|
||||||
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
||||||
import {BaseResponseOptions, ResponseOptions} from '../../src/base_response_options';
|
import {BaseResponseOptions, ResponseOptions} from '../../src/base_response_options';
|
||||||
import {ReadyState, RequestMethod, ResponseType} from '../../src/enums';
|
import {ReadyState, RequestMethod, ResponseType} from '../../src/enums';
|
||||||
import {Map} from '../../src/facade/collection';
|
|
||||||
import {isPresent} from '../../src/facade/lang';
|
import {isPresent} from '../../src/facade/lang';
|
||||||
import {Request} from '../../src/static_request';
|
import {Request} from '../../src/static_request';
|
||||||
import {Response} from '../../src/static_response';
|
import {Response} from '../../src/static_response';
|
||||||
|
|
||||||
var existingScripts: MockBrowserJsonp[] = [];
|
var existingScripts: MockBrowserJsonp[] = [];
|
||||||
var unused: Response;
|
|
||||||
|
|
||||||
class MockBrowserJsonp extends BrowserJsonp {
|
class MockBrowserJsonp extends BrowserJsonp {
|
||||||
src: string;
|
src: string;
|
||||||
|
@ -15,7 +15,6 @@ import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '../../src/backends/
|
|||||||
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
import {BaseRequestOptions, RequestOptions} from '../../src/base_request_options';
|
||||||
import {BaseResponseOptions, ResponseOptions} from '../../src/base_response_options';
|
import {BaseResponseOptions, ResponseOptions} from '../../src/base_response_options';
|
||||||
import {ResponseContentType, ResponseType} from '../../src/enums';
|
import {ResponseContentType, ResponseType} from '../../src/enums';
|
||||||
import {Map} from '../../src/facade/collection';
|
|
||||||
import {Json} from '../../src/facade/lang';
|
import {Json} from '../../src/facade/lang';
|
||||||
import {Headers} from '../../src/headers';
|
import {Headers} from '../../src/headers';
|
||||||
import {XSRFStrategy} from '../../src/interfaces';
|
import {XSRFStrategy} from '../../src/interfaces';
|
||||||
@ -27,9 +26,7 @@ var abortSpy: any;
|
|||||||
var sendSpy: any;
|
var sendSpy: any;
|
||||||
var openSpy: any;
|
var openSpy: any;
|
||||||
var setRequestHeaderSpy: any;
|
var setRequestHeaderSpy: any;
|
||||||
var addEventListenerSpy: any;
|
|
||||||
var existingXHRs: MockBrowserXHR[] = [];
|
var existingXHRs: MockBrowserXHR[] = [];
|
||||||
var unused: Response;
|
|
||||||
|
|
||||||
class MockBrowserXHR extends BrowserXhr {
|
class MockBrowserXHR extends BrowserXhr {
|
||||||
abort: any;
|
abort: any;
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
|
||||||
|
|
||||||
import {Map, StringMapWrapper} from '../src/facade/collection';
|
|
||||||
import {Json} from '../src/facade/lang';
|
import {Json} from '../src/facade/lang';
|
||||||
import {Headers} from '../src/headers';
|
import {Headers} from '../src/headers';
|
||||||
|
|
||||||
@ -24,21 +22,20 @@ export function main() {
|
|||||||
// Spec at https://tools.ietf.org/html/rfc2616
|
// Spec at https://tools.ietf.org/html/rfc2616
|
||||||
expect(firstHeaders.get('content-type')).toBe('image/jpeg');
|
expect(firstHeaders.get('content-type')).toBe('image/jpeg');
|
||||||
expect(firstHeaders.get('content-Type')).toBe('image/jpeg');
|
expect(firstHeaders.get('content-Type')).toBe('image/jpeg');
|
||||||
var httpHeaders = StringMapWrapper.create();
|
const httpHeaders = {
|
||||||
StringMapWrapper.set(httpHeaders, 'Content-Type', 'image/jpeg');
|
'Content-Type': 'image/jpeg',
|
||||||
StringMapWrapper.set(httpHeaders, 'Accept-Charset', 'utf-8');
|
'Accept-Charset': 'utf-8',
|
||||||
StringMapWrapper.set(httpHeaders, 'X-My-Custom-Header', 'Zeke are cool');
|
'X-My-Custom-Header': 'Zeke are cool',
|
||||||
var secondHeaders = new Headers(httpHeaders);
|
};
|
||||||
var secondHeadersObj = new Headers(secondHeaders);
|
const secondHeaders = new Headers(httpHeaders);
|
||||||
|
const secondHeadersObj = new Headers(secondHeaders);
|
||||||
expect(secondHeadersObj.get('Content-Type')).toBe('image/jpeg');
|
expect(secondHeadersObj.get('Content-Type')).toBe('image/jpeg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('initialization', () => {
|
describe('initialization', () => {
|
||||||
it('should merge values in provided dictionary', () => {
|
it('should merge values in provided dictionary', () => {
|
||||||
var map = StringMapWrapper.create();
|
var headers = new Headers({'foo': 'bar'});
|
||||||
StringMapWrapper.set(map, 'foo', 'bar');
|
|
||||||
var headers = new Headers(map);
|
|
||||||
expect(headers.get('foo')).toBe('bar');
|
expect(headers.get('foo')).toBe('bar');
|
||||||
expect(headers.getAll('foo')).toEqual(['bar']);
|
expect(headers.getAll('foo')).toEqual(['bar']);
|
||||||
});
|
});
|
||||||
@ -55,9 +52,7 @@ export function main() {
|
|||||||
|
|
||||||
describe('.set()', () => {
|
describe('.set()', () => {
|
||||||
it('should clear all values and re-set for the provided key', () => {
|
it('should clear all values and re-set for the provided key', () => {
|
||||||
var map = StringMapWrapper.create();
|
var headers = new Headers({'foo': 'bar'});
|
||||||
StringMapWrapper.set(map, 'foo', 'bar');
|
|
||||||
var headers = new Headers(map);
|
|
||||||
expect(headers.get('foo')).toBe('bar');
|
expect(headers.get('foo')).toBe('bar');
|
||||||
expect(headers.getAll('foo')).toEqual(['bar']);
|
expect(headers.getAll('foo')).toEqual(['bar']);
|
||||||
headers.set('foo', 'baz');
|
headers.set('foo', 'baz');
|
||||||
|
@ -164,7 +164,7 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||||||
childNodes(el: any /** TODO #9100 */): Node[] { return el.childNodes; }
|
childNodes(el: any /** TODO #9100 */): Node[] { return el.childNodes; }
|
||||||
childNodesAsList(el: any /** TODO #9100 */): any[] {
|
childNodesAsList(el: any /** TODO #9100 */): any[] {
|
||||||
var childNodes = el.childNodes;
|
var childNodes = el.childNodes;
|
||||||
var res = ListWrapper.createFixedSize(childNodes.length);
|
var res = new Array(childNodes.length);
|
||||||
for (var i = 0; i < childNodes.length; i++) {
|
for (var i = 0; i < childNodes.length; i++) {
|
||||||
res[i] = childNodes[i];
|
res[i] = childNodes[i];
|
||||||
}
|
}
|
||||||
|
@ -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 {StringMapWrapper} from '../../facade/collection';
|
|
||||||
|
|
||||||
import {EventManagerPlugin} from './event_manager';
|
import {EventManagerPlugin} from './event_manager';
|
||||||
|
|
||||||
var _eventNames = {
|
var _eventNames = {
|
||||||
@ -53,7 +51,6 @@ export class HammerGesturesPluginCommon extends EventManagerPlugin {
|
|||||||
constructor() { super(); }
|
constructor() { super(); }
|
||||||
|
|
||||||
supports(eventName: string): boolean {
|
supports(eventName: string): boolean {
|
||||||
eventName = eventName.toLowerCase();
|
return _eventNames.hasOwnProperty(eventName.toLowerCase());
|
||||||
return StringMapWrapper.contains(_eventNames, eventName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ export class KeyEventsPlugin extends EventManagerPlugin {
|
|||||||
// returning null instead of throwing to let another plugin process the event
|
// returning null instead of throwing to let another plugin process the event
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var result = StringMapWrapper.create();
|
var result = {};
|
||||||
StringMapWrapper.set(result, 'domEventName', domEventName);
|
StringMapWrapper.set(result, 'domEventName', domEventName);
|
||||||
StringMapWrapper.set(result, 'fullKey', fullKey);
|
StringMapWrapper.set(result, 'fullKey', fullKey);
|
||||||
return result;
|
return result;
|
||||||
|
@ -11,12 +11,10 @@ import {beforeEach, ddescribe, describe, expect, iit, it, xdescribe, xit} from '
|
|||||||
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
|
||||||
import {DomEventsPlugin} from '@angular/platform-browser/src/dom/events/dom_events';
|
import {DomEventsPlugin} from '@angular/platform-browser/src/dom/events/dom_events';
|
||||||
import {EventManager, EventManagerPlugin} from '@angular/platform-browser/src/dom/events/event_manager';
|
import {EventManager, EventManagerPlugin} from '@angular/platform-browser/src/dom/events/event_manager';
|
||||||
|
|
||||||
import {ListWrapper, Map} from '../../../src/facade/collection';
|
|
||||||
import {el} from '../../../testing/browser_util';
|
import {el} from '../../../testing/browser_util';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
var domEventPlugin: any /** TODO #9100 */;
|
var domEventPlugin: DomEventsPlugin;
|
||||||
|
|
||||||
describe('EventManager', () => {
|
describe('EventManager', () => {
|
||||||
|
|
||||||
@ -29,7 +27,7 @@ export function main() {
|
|||||||
var plugin = new FakeEventManagerPlugin(['click']);
|
var plugin = new FakeEventManagerPlugin(['click']);
|
||||||
var manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
|
var manager = new EventManager([domEventPlugin, plugin], new FakeNgZone());
|
||||||
manager.addEventListener(element, 'click', handler);
|
manager.addEventListener(element, 'click', handler);
|
||||||
expect(plugin._eventHandler.get('click')).toBe(handler);
|
expect(plugin.eventHandler['click']).toBe(handler);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delegate event bindings to the first plugin supporting the event', () => {
|
it('should delegate event bindings to the first plugin supporting the event', () => {
|
||||||
@ -41,10 +39,8 @@ export function main() {
|
|||||||
var manager = new EventManager([plugin2, plugin1], new FakeNgZone());
|
var manager = new EventManager([plugin2, plugin1], new FakeNgZone());
|
||||||
manager.addEventListener(element, 'click', clickHandler);
|
manager.addEventListener(element, 'click', clickHandler);
|
||||||
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
manager.addEventListener(element, 'dblclick', dblClickHandler);
|
||||||
expect(plugin1._eventHandler.has('click')).toBe(false);
|
expect(plugin2.eventHandler['click']).toBe(clickHandler);
|
||||||
expect(plugin2._eventHandler.get('click')).toBe(clickHandler);
|
expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler);
|
||||||
expect(plugin2._eventHandler.has('dblclick')).toBe(false);
|
|
||||||
expect(plugin1._eventHandler.get('dblclick')).toBe(dblClickHandler);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when no plugin can handle the event', () => {
|
it('should throw when no plugin can handle the event', () => {
|
||||||
@ -91,22 +87,23 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
class FakeEventManagerPlugin extends EventManagerPlugin {
|
class FakeEventManagerPlugin extends EventManagerPlugin {
|
||||||
/** @internal */
|
eventHandler: {[event: string]: Function} = {};
|
||||||
_eventHandler = new Map<string, Function>();
|
|
||||||
constructor(public _supports: string[]) { super(); }
|
|
||||||
|
|
||||||
supports(eventName: string): boolean { return ListWrapper.contains(this._supports, eventName); }
|
constructor(public supportedEvents: string[]) { super(); }
|
||||||
|
|
||||||
addEventListener(element: any /** TODO #9100 */, eventName: string, handler: Function) {
|
supports(eventName: string): boolean { return this.supportedEvents.indexOf(eventName) > -1; }
|
||||||
this._eventHandler.set(eventName, handler);
|
|
||||||
return () => { this._eventHandler.delete(eventName); };
|
addEventListener(element: any, eventName: string, handler: Function) {
|
||||||
|
this.eventHandler[eventName] = handler;
|
||||||
|
return () => { delete (this.eventHandler[eventName]); };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeNgZone extends NgZone {
|
class FakeNgZone extends NgZone {
|
||||||
constructor() { super({enableLongStackTrace: false}); }
|
constructor() { super({enableLongStackTrace: false}); }
|
||||||
run(fn: any /** TODO #9100 */) { fn(); }
|
run(fn: Function) { fn(); }
|
||||||
|
|
||||||
runOutsideAngular(fn: any /** TODO #9100 */) { return fn(); }
|
runOutsideAngular(fn: Function) { return fn(); }
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,6 @@ import {ListWrapper, StringMapWrapper} from '../src/facade/collection';
|
|||||||
import {DomAdapter, setRootDomAdapter} from './private_import_platform-browser';
|
import {DomAdapter, setRootDomAdapter} from './private_import_platform-browser';
|
||||||
import {isPresent, isBlank, global, setValueOnPath, DateWrapper} from '../src/facade/lang';
|
import {isPresent, isBlank, global, setValueOnPath, DateWrapper} from '../src/facade/lang';
|
||||||
import {SelectorMatcher, CssSelector} from './private_import_compiler';
|
import {SelectorMatcher, CssSelector} from './private_import_compiler';
|
||||||
import {Type} from '@angular/core';
|
|
||||||
import {ResourceLoader} from '@angular/compiler';
|
|
||||||
|
|
||||||
var parser: any /** TODO #9100 */ = null;
|
var parser: any /** TODO #9100 */ = null;
|
||||||
var serializer: any /** TODO #9100 */ = null;
|
var serializer: any /** TODO #9100 */ = null;
|
||||||
@ -136,17 +134,13 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
on(el: any /** TODO #9100 */, evt: any /** TODO #9100 */, listener: any /** TODO #9100 */) {
|
on(el: any /** TODO #9100 */, evt: any /** TODO #9100 */, listener: any /** TODO #9100 */) {
|
||||||
var listenersMap: {[k: /*any*/ string]: any} = el._eventListenersMap;
|
var listenersMap: {[k: string]: any} = el._eventListenersMap;
|
||||||
if (isBlank(listenersMap)) {
|
if (isBlank(listenersMap)) {
|
||||||
var listenersMap: {[k: /*any*/ string]: any} = StringMapWrapper.create();
|
var listenersMap: {[k: string]: any} = {};
|
||||||
el._eventListenersMap = listenersMap;
|
el._eventListenersMap = listenersMap;
|
||||||
}
|
}
|
||||||
var listeners = StringMapWrapper.get(listenersMap, evt);
|
const listeners = listenersMap[evt] || [];
|
||||||
if (isBlank(listeners)) {
|
listenersMap[evt] = [...listeners, listener];
|
||||||
listeners = [];
|
|
||||||
}
|
|
||||||
listeners.push(listener);
|
|
||||||
StringMapWrapper.set(listenersMap, evt, listeners);
|
|
||||||
}
|
}
|
||||||
onAndCancel(
|
onAndCancel(
|
||||||
el: any /** TODO #9100 */, evt: any /** TODO #9100 */,
|
el: any /** TODO #9100 */, evt: any /** TODO #9100 */,
|
||||||
@ -209,7 +203,7 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||||||
childNodes(el: any /** TODO #9100 */): Node[] { return el.childNodes; }
|
childNodes(el: any /** TODO #9100 */): Node[] { return el.childNodes; }
|
||||||
childNodesAsList(el: any /** TODO #9100 */): any[] {
|
childNodesAsList(el: any /** TODO #9100 */): any[] {
|
||||||
var childNodes = el.childNodes;
|
var childNodes = el.childNodes;
|
||||||
var res = ListWrapper.createFixedSize(childNodes.length);
|
var res = new Array(childNodes.length);
|
||||||
for (var i = 0; i < childNodes.length; i++) {
|
for (var i = 0; i < childNodes.length; i++) {
|
||||||
res[i] = childNodes[i];
|
res[i] = childNodes[i];
|
||||||
}
|
}
|
||||||
@ -489,7 +483,7 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||||||
}
|
}
|
||||||
removeAttribute(element: any /** TODO #9100 */, attribute: string) {
|
removeAttribute(element: any /** TODO #9100 */, attribute: string) {
|
||||||
if (attribute) {
|
if (attribute) {
|
||||||
StringMapWrapper.delete(element.attribs, attribute);
|
delete element.attribs[attribute];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeAttributeNS(element: any /** TODO #9100 */, ns: string, name: string) {
|
removeAttributeNS(element: any /** TODO #9100 */, ns: string, name: string) {
|
||||||
@ -507,7 +501,7 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||||||
this.appendChild(newDoc, body);
|
this.appendChild(newDoc, body);
|
||||||
StringMapWrapper.set(newDoc, 'head', head);
|
StringMapWrapper.set(newDoc, 'head', head);
|
||||||
StringMapWrapper.set(newDoc, 'body', body);
|
StringMapWrapper.set(newDoc, 'body', body);
|
||||||
StringMapWrapper.set(newDoc, '_window', StringMapWrapper.create());
|
StringMapWrapper.set(newDoc, '_window', {});
|
||||||
return newDoc;
|
return newDoc;
|
||||||
}
|
}
|
||||||
defaultDoc(): Document {
|
defaultDoc(): Document {
|
||||||
@ -546,7 +540,7 @@ export class Parse5DomAdapter extends DomAdapter {
|
|||||||
var rules: any[] /** TODO #9100 */ = [];
|
var rules: any[] /** TODO #9100 */ = [];
|
||||||
for (var i = 0; i < parsedRules.length; i++) {
|
for (var i = 0; i < parsedRules.length; i++) {
|
||||||
var parsedRule = parsedRules[i];
|
var parsedRule = parsedRules[i];
|
||||||
var rule: {[key: string]: any} = StringMapWrapper.create();
|
var rule: {[key: string]: any} = {};
|
||||||
StringMapWrapper.set(rule, 'cssText', css);
|
StringMapWrapper.set(rule, 'cssText', css);
|
||||||
StringMapWrapper.set(rule, 'style', {content: '', cssText: ''});
|
StringMapWrapper.set(rule, 'style', {content: '', cssText: ''});
|
||||||
if (parsedRule.type == 'rule') {
|
if (parsedRule.type == 'rule') {
|
||||||
|
@ -156,15 +156,11 @@ class MessageData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value from the StringMap if present. Otherwise returns null
|
* Returns the value if present, otherwise returns null
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
_getValueIfPresent(data: {[key: string]: any}, key: string) {
|
_getValueIfPresent(data: {[key: string]: any}, key: string) {
|
||||||
if (StringMapWrapper.contains(data, key)) {
|
return data.hasOwnProperty(key) ? data[key] : null;
|
||||||
return StringMapWrapper.get(data, key);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {Injectable, NgZone} from '@angular/core';
|
import {Injectable, NgZone} from '@angular/core';
|
||||||
|
|
||||||
import {EventEmitter} from '../../facade/async';
|
import {EventEmitter} from '../../facade/async';
|
||||||
import {StringMapWrapper} from '../../facade/collection';
|
|
||||||
|
|
||||||
import {MessageBus, MessageBusSink, MessageBusSource} from './message_bus';
|
import {MessageBus, MessageBusSink, MessageBusSource} from './message_bus';
|
||||||
|
|
||||||
@ -22,7 +21,7 @@ export interface PostMessageTarget {
|
|||||||
|
|
||||||
export class PostMessageBusSink implements MessageBusSink {
|
export class PostMessageBusSink implements MessageBusSink {
|
||||||
private _zone: NgZone;
|
private _zone: NgZone;
|
||||||
private _channels: {[key: string]: _Channel} = StringMapWrapper.create();
|
private _channels: {[key: string]: _Channel} = {};
|
||||||
private _messageBuffer: Array<Object> = [];
|
private _messageBuffer: Array<Object> = [];
|
||||||
|
|
||||||
constructor(private _postMessageTarget: PostMessageTarget) {}
|
constructor(private _postMessageTarget: PostMessageTarget) {}
|
||||||
@ -34,7 +33,7 @@ export class PostMessageBusSink implements MessageBusSink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initChannel(channel: string, runInZone: boolean = true): void {
|
initChannel(channel: string, runInZone: boolean = true): void {
|
||||||
if (StringMapWrapper.contains(this._channels, channel)) {
|
if (this._channels.hasOwnProperty(channel)) {
|
||||||
throw new Error(`${channel} has already been initialized`);
|
throw new Error(`${channel} has already been initialized`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ export class PostMessageBusSink implements MessageBusSink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
to(channel: string): EventEmitter<any> {
|
to(channel: string): EventEmitter<any> {
|
||||||
if (StringMapWrapper.contains(this._channels, channel)) {
|
if (this._channels.hasOwnProperty(channel)) {
|
||||||
return this._channels[channel].emitter;
|
return this._channels[channel].emitter;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`${channel} is not set up. Did you forget to call initChannel?`);
|
throw new Error(`${channel} is not set up. Did you forget to call initChannel?`);
|
||||||
@ -71,7 +70,7 @@ export class PostMessageBusSink implements MessageBusSink {
|
|||||||
|
|
||||||
export class PostMessageBusSource implements MessageBusSource {
|
export class PostMessageBusSource implements MessageBusSource {
|
||||||
private _zone: NgZone;
|
private _zone: NgZone;
|
||||||
private _channels: {[key: string]: _Channel} = StringMapWrapper.create();
|
private _channels: {[key: string]: _Channel} = {};
|
||||||
|
|
||||||
constructor(eventTarget?: EventTarget) {
|
constructor(eventTarget?: EventTarget) {
|
||||||
if (eventTarget) {
|
if (eventTarget) {
|
||||||
@ -86,7 +85,7 @@ export class PostMessageBusSource implements MessageBusSource {
|
|||||||
attachToZone(zone: NgZone) { this._zone = zone; }
|
attachToZone(zone: NgZone) { this._zone = zone; }
|
||||||
|
|
||||||
initChannel(channel: string, runInZone: boolean = true) {
|
initChannel(channel: string, runInZone: boolean = true) {
|
||||||
if (StringMapWrapper.contains(this._channels, channel)) {
|
if (this._channels.hasOwnProperty(channel)) {
|
||||||
throw new Error(`${channel} has already been initialized`);
|
throw new Error(`${channel} has already been initialized`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +95,7 @@ export class PostMessageBusSource implements MessageBusSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
from(channel: string): EventEmitter<any> {
|
from(channel: string): EventEmitter<any> {
|
||||||
if (StringMapWrapper.contains(this._channels, channel)) {
|
if (this._channels.hasOwnProperty(channel)) {
|
||||||
return this._channels[channel].emitter;
|
return this._channels[channel].emitter;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`${channel} is not set up. Did you forget to call initChannel?`);
|
throw new Error(`${channel} is not set up. Did you forget to call initChannel?`);
|
||||||
@ -112,7 +111,7 @@ export class PostMessageBusSource implements MessageBusSource {
|
|||||||
|
|
||||||
private _handleMessage(data: any): void {
|
private _handleMessage(data: any): void {
|
||||||
var channel = data.channel;
|
var channel = data.channel;
|
||||||
if (StringMapWrapper.contains(this._channels, channel)) {
|
if (this._channels.hasOwnProperty(channel)) {
|
||||||
var channelInfo = this._channels[channel];
|
var channelInfo = this._channels[channel];
|
||||||
if (channelInfo.runInZone) {
|
if (channelInfo.runInZone) {
|
||||||
this._zone.run(() => { channelInfo.emitter.emit(data.message); });
|
this._zone.run(() => { channelInfo.emitter.emit(data.message); });
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
import {Injectable, Type} from '@angular/core';
|
import {Injectable, Type} from '@angular/core';
|
||||||
|
|
||||||
import {EventEmitter} from '../../facade/async';
|
import {EventEmitter} from '../../facade/async';
|
||||||
import {ListWrapper, Map} from '../../facade/collection';
|
|
||||||
import {FunctionWrapper, isPresent} from '../../facade/lang';
|
import {FunctionWrapper, isPresent} from '../../facade/lang';
|
||||||
import {MessageBus} from '../shared/message_bus';
|
import {MessageBus} from '../shared/message_bus';
|
||||||
import {Serializer} from '../shared/serializer';
|
import {Serializer} from '../shared/serializer';
|
||||||
@ -72,7 +71,7 @@ export class ServiceMessageBroker_ extends ServiceMessageBroker {
|
|||||||
this._methods.set(methodName, (message: ReceivedMessage) => {
|
this._methods.set(methodName, (message: ReceivedMessage) => {
|
||||||
var serializedArgs = message.args;
|
var serializedArgs = message.args;
|
||||||
let numArgs = signature === null ? 0 : signature.length;
|
let numArgs = signature === null ? 0 : signature.length;
|
||||||
var deserializedArgs: any[] = ListWrapper.createFixedSize(numArgs);
|
var deserializedArgs: any[] = new Array(numArgs);
|
||||||
for (var i = 0; i < numArgs; i++) {
|
for (var i = 0; i < numArgs; i++) {
|
||||||
var serializedArg = serializedArgs[i];
|
var serializedArg = serializedArgs[i];
|
||||||
deserializedArgs[i] = this._serializer.deserialize(serializedArg, signature[i]);
|
deserializedArgs[i] = this._serializer.deserialize(serializedArg, signature[i]);
|
||||||
|
@ -6,9 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Set} from '../../facade/collection';
|
|
||||||
import {isPresent} from '../../facade/lang';
|
|
||||||
|
|
||||||
const MOUSE_EVENT_PROPERTIES = [
|
const MOUSE_EVENT_PROPERTIES = [
|
||||||
'altKey', 'button', 'clientX', 'clientY', 'metaKey', 'movementX', 'movementY', 'offsetX',
|
'altKey', 'button', 'clientX', 'clientY', 'metaKey', 'movementX', 'movementY', 'offsetX',
|
||||||
'offsetY', 'region', 'screenX', 'screenY', 'shiftKey'
|
'offsetY', 'region', 'screenX', 'screenY', 'shiftKey'
|
||||||
@ -56,7 +53,7 @@ function addTarget(e: Event, serializedEvent: {[key: string]: any}): {[key: stri
|
|||||||
if (NODES_WITH_VALUE.has((<HTMLElement>e.target).tagName.toLowerCase())) {
|
if (NODES_WITH_VALUE.has((<HTMLElement>e.target).tagName.toLowerCase())) {
|
||||||
var target = <HTMLInputElement>e.target;
|
var target = <HTMLInputElement>e.target;
|
||||||
serializedEvent['target'] = {'value': target.value};
|
serializedEvent['target'] = {'value': target.value};
|
||||||
if (isPresent(target.files)) {
|
if (target.files) {
|
||||||
serializedEvent['target']['files'] = target.files;
|
serializedEvent['target']['files'] = target.files;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import {LocationChangeListener, PlatformLocation} from '@angular/common';
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
|
|
||||||
import {EventEmitter} from '../../facade/async';
|
import {EventEmitter} from '../../facade/async';
|
||||||
import {StringMapWrapper} from '../../facade/collection';
|
|
||||||
import {StringWrapper} from '../../facade/lang';
|
import {StringWrapper} from '../../facade/lang';
|
||||||
import {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from '../shared/client_message_broker';
|
import {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from '../shared/client_message_broker';
|
||||||
import {MessageBus} from '../shared/message_bus';
|
import {MessageBus} from '../shared/message_bus';
|
||||||
@ -37,7 +36,7 @@ export class WebWorkerPlatformLocation extends PlatformLocation {
|
|||||||
this._channelSource.subscribe({
|
this._channelSource.subscribe({
|
||||||
next: (msg: {[key: string]: any}) => {
|
next: (msg: {[key: string]: any}) => {
|
||||||
var listeners: Array<Function> = null;
|
var listeners: Array<Function> = null;
|
||||||
if (StringMapWrapper.contains(msg, 'event')) {
|
if (msg.hasOwnProperty('event')) {
|
||||||
let type: string = msg['event']['type'];
|
let type: string = msg['event']['type'];
|
||||||
if (StringWrapper.equals(type, 'popstate')) {
|
if (StringWrapper.equals(type, 'popstate')) {
|
||||||
listeners = this._popStateListeners;
|
listeners = this._popStateListeners;
|
||||||
|
@ -16,8 +16,6 @@ import {SpyMessageBroker} from '../worker/spies';
|
|||||||
|
|
||||||
import {MockEventEmitter} from './mock_event_emitter';
|
import {MockEventEmitter} from './mock_event_emitter';
|
||||||
|
|
||||||
var __unused: Promise<any>; // avoid unused import when Promise union types are erased
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns two MessageBus instances that are attached to each other.
|
* Returns two MessageBus instances that are attached to each other.
|
||||||
* Such that whatever goes into one's sink comes out the others source.
|
* Such that whatever goes into one's sink comes out the others source.
|
||||||
@ -49,9 +47,9 @@ export function expectBrokerCall(
|
|||||||
expect(args.method).toEqual(methodName);
|
expect(args.method).toEqual(methodName);
|
||||||
if (isPresent(vals)) {
|
if (isPresent(vals)) {
|
||||||
expect(args.args.length).toEqual(vals.length);
|
expect(args.args.length).toEqual(vals.length);
|
||||||
ListWrapper.forEachWithIndex(vals, (v, i) => { expect(v).toEqual(args.args[i].value); });
|
vals.forEach((v, i) => { expect(v).toEqual(args.args[i].value); });
|
||||||
}
|
}
|
||||||
var promise: any /** TODO #9100 */ = null;
|
var promise: Promise<any>|void = null;
|
||||||
if (isPresent(handler)) {
|
if (isPresent(handler)) {
|
||||||
let givenValues = args.args.map((arg) => arg.value);
|
let givenValues = args.args.map((arg) => arg.value);
|
||||||
if (givenValues.length > 0) {
|
if (givenValues.length > 0) {
|
||||||
@ -81,13 +79,13 @@ export class MockMessageBusSource implements MessageBusSource {
|
|||||||
constructor(private _channels: {[key: string]: MockEventEmitter<any>}) {}
|
constructor(private _channels: {[key: string]: MockEventEmitter<any>}) {}
|
||||||
|
|
||||||
initChannel(channel: string, runInZone = true) {
|
initChannel(channel: string, runInZone = true) {
|
||||||
if (!StringMapWrapper.contains(this._channels, channel)) {
|
if (!this._channels.hasOwnProperty(channel)) {
|
||||||
this._channels[channel] = new MockEventEmitter();
|
this._channels[channel] = new MockEventEmitter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
from(channel: string): MockEventEmitter<any> {
|
from(channel: string): MockEventEmitter<any> {
|
||||||
if (!StringMapWrapper.contains(this._channels, channel)) {
|
if (!this._channels.hasOwnProperty(channel)) {
|
||||||
throw new Error(`${channel} is not set up. Did you forget to call initChannel?`);
|
throw new Error(`${channel} is not set up. Did you forget to call initChannel?`);
|
||||||
}
|
}
|
||||||
return this._channels[channel];
|
return this._channels[channel];
|
||||||
@ -100,13 +98,13 @@ export class MockMessageBusSink implements MessageBusSink {
|
|||||||
constructor(private _channels: {[key: string]: MockEventEmitter<any>}) {}
|
constructor(private _channels: {[key: string]: MockEventEmitter<any>}) {}
|
||||||
|
|
||||||
initChannel(channel: string, runInZone = true) {
|
initChannel(channel: string, runInZone = true) {
|
||||||
if (!StringMapWrapper.contains(this._channels, channel)) {
|
if (!this._channels.hasOwnProperty(channel)) {
|
||||||
this._channels[channel] = new MockEventEmitter();
|
this._channels[channel] = new MockEventEmitter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
to(channel: string): MockEventEmitter<any> {
|
to(channel: string): MockEventEmitter<any> {
|
||||||
if (!StringMapWrapper.contains(this._channels, channel)) {
|
if (!this._channels.hasOwnProperty(channel)) {
|
||||||
this._channels[channel] = new MockEventEmitter();
|
this._channels[channel] = new MockEventEmitter();
|
||||||
}
|
}
|
||||||
return this._channels[channel];
|
return this._channels[channel];
|
||||||
|
@ -401,9 +401,12 @@ export class UpgradeAdapter {
|
|||||||
._bootstrapModuleWithZone(
|
._bootstrapModuleWithZone(
|
||||||
DynamicNgUpgradeModule, undefined, ngZone,
|
DynamicNgUpgradeModule, undefined, ngZone,
|
||||||
(componentFactories: ComponentFactory<any>[]) => {
|
(componentFactories: ComponentFactory<any>[]) => {
|
||||||
componentFactories.forEach((componentFactory) => {
|
componentFactories.forEach((componentFactory: ComponentFactory<any>) => {
|
||||||
componentFactoryRefMap[getComponentInfo(componentFactory.componentType)
|
var type: Type<any> = componentFactory.componentType;
|
||||||
.selector] = componentFactory;
|
if (this.upgradedComponents.indexOf(type) !== -1) {
|
||||||
|
componentFactoryRefMap[getComponentInfo(type).selector] =
|
||||||
|
componentFactory;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then((ref: NgModuleRef<any>) => {
|
.then((ref: NgModuleRef<any>) => {
|
||||||
|
@ -964,6 +964,31 @@ export function main() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow attribute selectors for components in ng2', async(() => {
|
||||||
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => MyNg2Module));
|
||||||
|
var 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));
|
||||||
@ -994,7 +1019,7 @@ export function main() {
|
|||||||
|
|
||||||
document.body.innerHTML = '<ng2 name="World">project</ng2>';
|
document.body.innerHTML = '<ng2 name="World">project</ng2>';
|
||||||
|
|
||||||
adapter.bootstrap(document.body, ['myExample']).ready((ref) => {
|
adapter.bootstrap(document.body.firstElementChild, ['myExample']).ready((ref) => {
|
||||||
expect(multiTrim(document.body.textContent))
|
expect(multiTrim(document.body.textContent))
|
||||||
.toEqual('ng2[ng1[Hello World!](transclude)](project)');
|
.toEqual('ng2[ng1[Hello World!](transclude)](project)');
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
|
@ -4642,7 +4642,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zone.js": {
|
"zone.js": {
|
||||||
"version": "0.6.21"
|
"version": "0.6.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
|
6
npm-shrinkwrap.json
generated
6
npm-shrinkwrap.json
generated
@ -7414,9 +7414,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zone.js": {
|
"zone.js": {
|
||||||
"version": "0.6.21",
|
"version": "0.6.25",
|
||||||
"from": "zone.js@0.6.21",
|
"from": "zone.js@>=0.6.24 <0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.6.21.tgz"
|
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.6.25.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"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",
|
||||||
@ -21,7 +21,7 @@
|
|||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
"reflect-metadata": "^0.1.3",
|
"reflect-metadata": "^0.1.3",
|
||||||
"rxjs": "5.0.0-beta.12",
|
"rxjs": "5.0.0-beta.12",
|
||||||
"zone.js": "^0.6.21"
|
"zone.js": "^0.6.25"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/angularjs": "^1.5.13-alpha",
|
"@types/angularjs": "^1.5.13-alpha",
|
||||||
|
4
tools/public_api_guard/core/index.d.ts
vendored
4
tools/public_api_guard/core/index.d.ts
vendored
@ -880,7 +880,7 @@ export declare abstract class TemplateRef<C> {
|
|||||||
export declare class Testability implements PublicTestability {
|
export declare class Testability implements PublicTestability {
|
||||||
constructor(_ngZone: NgZone);
|
constructor(_ngZone: NgZone);
|
||||||
decreasePendingRequestCount(): number;
|
decreasePendingRequestCount(): number;
|
||||||
findBindings(using: any, provider: string, exactMatch: boolean): any[];
|
/** @deprecated */ findBindings(using: any, provider: string, exactMatch: boolean): any[];
|
||||||
findProviders(using: any, provider: string, exactMatch: boolean): any[];
|
findProviders(using: any, provider: string, exactMatch: boolean): any[];
|
||||||
getPendingRequestCount(): number;
|
getPendingRequestCount(): number;
|
||||||
increasePendingRequestCount(): number;
|
increasePendingRequestCount(): number;
|
||||||
@ -916,7 +916,7 @@ export declare const TRANSLATIONS_FORMAT: OpaqueToken;
|
|||||||
export declare function trigger(name: string, animation: AnimationMetadata[]): AnimationEntryMetadata;
|
export declare function trigger(name: string, animation: AnimationMetadata[]): AnimationEntryMetadata;
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export declare var Type: FunctionConstructor;
|
export declare const Type: FunctionConstructor;
|
||||||
|
|
||||||
/** @stable */
|
/** @stable */
|
||||||
export interface TypeDecorator {
|
export interface TypeDecorator {
|
||||||
|
@ -56,7 +56,7 @@ export declare type MetadataOverride<T> = {
|
|||||||
/** @experimental */
|
/** @experimental */
|
||||||
export declare function resetFakeAsyncZone(): void;
|
export declare function resetFakeAsyncZone(): void;
|
||||||
|
|
||||||
/** @experimental */
|
/** @stable */
|
||||||
export declare class TestBed implements Injector {
|
export declare class TestBed implements Injector {
|
||||||
ngModule: Type<any>;
|
ngModule: Type<any>;
|
||||||
platform: PlatformRef;
|
platform: PlatformRef;
|
||||||
|
Reference in New Issue
Block a user