Compare commits

...

16 Commits

Author SHA1 Message Date
712d1a7c37 chore(release): v2.0.1 2016-09-23 11:28:36 -07:00
16601f9359 docs(changelog): add changelog for 2.0.1 2016-09-23 10:50:42 -07:00
b81e2e7a31 fix(upgrade): allow attribute selectors for components in ng2 which are not part of upgrade (#11808)
fixes #11280
2016-09-23 10:48:47 -07:00
98fac36706 docs(Component): API docs for .encapsulation and .interpolation 2016-09-23 10:22:24 -07:00
3e780c032e refactor: misc cleanup 2016-09-23 10:22:05 -07:00
e09882180e refactor(common): cleanup (#11668) 2016-09-23 10:21:58 -07:00
0e18c57a17 docs(core): mark TestBed as stable api and add preliminary docs (#11767)
TestBed was accidentaly ommited from the 'stable' api list during the API sweep before final. We do consider it to be stable.
2016-09-23 10:21:50 -07:00
51e2b9c073 docs(contributing): remove preview references (#11795) 2016-09-23 10:21:44 -07:00
f218e240d3 ci(BrowserStack): add Safari 10 (#11796) 2016-09-23 10:21:31 -07:00
af6b219f8e refactor(TemplateParser): clearer error message for on* binding (#11802)
fixes #11756
2016-09-23 10:21:15 -07:00
20addf5f9f chore(ISSUE_TEMPLATE): update Angular version field (#11821) 2016-09-23 10:21:02 -07:00
2860418a3c fix(forms): disable all radios with disable() 2016-09-23 10:19:58 -07:00
39e251eea7 fix(forms): support unbound disabled in ngModel (#11736) 2016-09-23 10:19:46 -07:00
d7d716d5db chore(zone.js): update to 0.6.25 (#11725) 2016-09-23 10:19:30 -07:00
a95d65241c fix(compiler): Safe property access expressions work in event bindings (#11724) 2016-09-23 10:19:24 -07:00
fdb22bd185 refactor: misc cleanup (#11654) 2016-09-23 10:18:38 -07:00
72 changed files with 552 additions and 402 deletions

View File

@ -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 ]

View File

@ -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)

View File

@ -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

View File

@ -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)
}; };

View File

@ -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,
}; };
} }
} }

View File

@ -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);

View File

@ -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,

View File

@ -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[] = [

View File

@ -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();

View File

@ -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) {}

View File

@ -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(

View File

@ -67,7 +67,7 @@ export enum Plural {
Two, Two,
Few, Few,
Many, Many,
Other Other,
} }
/** /**

View File

@ -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,
});
});
} }
/** /**

View File

@ -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();

View File

@ -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
}); });
} }

View File

@ -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);
} }

View File

@ -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);
} }
} }

View File

@ -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] = [];
} }

View File

@ -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

View File

@ -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);

View File

@ -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); }
} }

View File

@ -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>();

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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; }

View File

@ -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 {

View File

@ -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]);
} }

View File

@ -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;
} }

View File

@ -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';

View File

@ -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[]>;
} }

View File

@ -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(

View File

@ -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,
]; ];
/** /**

View File

@ -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; }

View File

@ -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 [];

View File

@ -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; }

View File

@ -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', () => {

View File

@ -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', () => {

View File

@ -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 {
/** /**

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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');
} }
} }

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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', () => {

View File

@ -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', () => {

View File

@ -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>

View File

@ -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';

View File

@ -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(

View File

@ -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;

View File

@ -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;

View File

@ -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');

View File

@ -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];
} }

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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(); }
} }

View File

@ -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') {

View File

@ -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;
}
} }
} }

View File

@ -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); });

View File

@ -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]);

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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];

View File

@ -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>) => {

View File

@ -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();

View File

@ -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
View File

@ -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"
} }
} }
} }

View File

@ -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",

View File

@ -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 {

View File

@ -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;