+```
+
+Notes:
+ - while tag name are case sensitive, the best practice is to use dash case for component elements so that the browser
+ interpret them as custom elements,
+ - `(some-event)` would now bind to the `some-event` event (i.e. there is no implicit dash to camel case conversion),
+ - `[some-property]` would now bind to the `some-property` property (i.e. there is no implicit dash to camel case conversion),
+ - `#some-var` is not allowed any more ("-" can not be used in variable names).
+
+## Migration
+
+#### Templates
+
+1. Directives selectors, property bindings, event bindings, template variables and template element attributes should be changed to camel case:
+
+ Examples:
+ - `` should be changed to `
`,
+ - `` should be changed to ``,
+ - `` should be changed to ``,
+ - `` should be changed to ``,
+ - ` ` should be changed to ` `,
+ - `` should be changed to ``,
+
+ Note: while the tag names are now case-sensitive the best practice is to keep them lower-dash-cased so that the browser
+ treat them as custom elements. Using dashes in custom element names is required by the [Custom Element HTML Spec](http://www.w3.org/TR/custom-elements/#concepts).
+ This explains why the `` component is left unchanged.
+
+ `on-`, `bindon-`, `bind-` and `var-` prefixes are still part of the canonical syntax and should remain unchanged (lower cased):
+ - `on-some-event` should be changed to `on-someEvent`,
+ - `bind-my-prop` should be changed to `bind-myProp`,
+ - `bindon-my-prop` should be changed to `bindon-myProp`,
+ - `var-my-var` should be changed to `var-myVar`.
+
+2. Update variable binding
+
+ - `` should be changed to `
`
+
+3. The `template` attribute values should also be updated in the same way
+
+ `
` should be changed to `
`.
+
+ Note that both angular directives and your own directives must be updated in the same way.
+
+#### Directives and Components
+
+Take the following steps to upgrade your directives and components:
+
+1. Update the selector:
+ ```
+ @Directive({selector: 'tag[attr][name=value]'})
+ @Component({selector: 'tag[attr][name=value]'})
+ ```
+
+ Tag and attributes names are case sensitive:
+ - For tag names, the best practice is to keep them lower dash cased, do not update them,
+ - For attribute names, the best practice is to convert them from lower dash case to camel case.
+
+ Examples:
+ - `custom-tag` should stay `custom-tag` (do not update tag names),
+ - `[attr-name]` should be updated to `[attrName]`,
+ - `[attr-name=someValue]` should be updated to `[attrName=someValue]`,
+ - `custom-tag[attr-name=someValue]` should be updated to `custom-tag[attrName=someValue]`
+
+ Note: attribute values and classes are still matched case insensitive.
+
+2. Update the inputs
+ ```
+ @Directive({inputs: ['myProp', 'myOtherProp: my-attr-name']})
+ ```
+
+ As attribute names are now case sensitive, they should be converted from dash to camel case where they are specified.
+ The previous decorator becomes:
+
+ ```
+ @Directive({inputs: ['myProp', 'myOtherProp: myAttrName']})
+ ```
+
+ Notes:
+ - only the long syntax (with ":") needs to be updated,
+ - `properties` is the legacy name for `inputs` and should be updated in the same way - it is a good idea to replace
+ `properties` with `inputs` at the same time as support for the former will be removed soon.
+
+ The same applies for the `@Input` decorator:
+
+ ```
+ @Input() myProp;
+ @Input('my-attr-name') myProp;
+ ```
+
+ That is they only need to be updated when the attribute name is specified:
+
+ ```
+ @Input() myProp; // Nothing to update
+ @Input('myAttrName') myProp; // Convert the attribute name to camel case
+ ```
+
+3. Update the outputs
+
+ Update the outputs in the same way the inputs are updated:
+
+ ```
+ @Directive({outputs: ['myEvent', 'myOtherEvent: my-event-name']})
+ ```
+
+ should be updated to:
+
+ ```
+ @Directive({outputs: ['myEvent', 'myOtherEvent: myEventName']})
+ ```
+
+ If you use `events` instead of `outputs` you should update in the same way and switch to `outputs` as `events` is deprecated.
+
+ ```
+ @Output() myEvent;
+ @Output('my-event-name') myEvent;
+ ```
+
+ should be changed to:
+
+ ```
+ @Output() myEvent;
+ @Output('myEventName') myEvent;
+ ```
+
+4. Update the host bindings
+
+ ```
+ @Directive({
+ host: {
+ '[some-prop]': 'exp',
+ '[style.background-color]': 'exp',
+ '[class.some-class]': 'exp',
+ '[attr.some-attr]': 'exp',
+ '(some-event)': 'action()',
+ 'some-attr': 'value'
+ }
+ })
+ ```
+
+ should be changed to:
+
+ ```
+ @Directive({
+ host: {
+ '[someProp]': 'exp',
+ '[style.background-color]': 'exp',
+ '[class.some-class]': 'exp',
+ '[attr.some-attr]': 'exp',
+ '(someEvent)': 'action()',
+ 'some-attr': 'value'
+ }
+ })
+ ```
+
+ The property bindings (`[...]`) and event bindings (`(...)`) must be updated in the same way as they are updated in a
+ template - ie converted to camel case (reminder: `[attr.]`, `[class.]` and `[style.]` should not be converted to camel case).
+
+5. Update export name
+
+ ```
+ @Directive({
+ exportAs: 'some-name'
+ })
+ ```
+
+ should be changed to:
+
+ ```
+ @Directive({
+ exportAs: 'someName'
+ })
+ ```
+
+
+# CSS
+
+As the attribute names from your templates have been updated from dash to camel case, you should also reflect the changes
+in your stylesheets.
+
+The attributes that need to be updated are the ones used in the selector and the inputs of your directives.
+
+Before:
+
+```
+// Directive
+@Directive({
+ selector: '[my-dir]',
+ inputs: ['someProp: some-input'],
+})
+
+
+
+
+/* css */
+[my-dir] { ... }
+[some-input] { ... }
+[not-an-input] { ... }
+```
+
+After:
+
+```
+// Directive
+@Directive({
+ selector: '[myDir]',
+ inputs: ['someProp: someInput'],
+})
+
+
+
+
+/* css */
+[myDir] { ... }
+[someInput] { ... }
+[not-an-input] { ... }
+```
+
+Notes:
+ - `not-an-input` is not used in a selector nor it is an input of a directive, it need not be camel cased,
+ - CSS selectors are case insensitive you can use `[myDir]`, `[mydir]` or any other casing.
diff --git a/modules/angular2/docs/web_workers/web_workers.md b/modules/angular2/docs/web_workers/web_workers.md
new file mode 100644
index 000000000000..2a5dfbf2d398
--- /dev/null
+++ b/modules/angular2/docs/web_workers/web_workers.md
@@ -0,0 +1,560 @@
+# WebWorkers in Angular 2: Documentation
+
+Angular 2 includes native support for writing applications which live in a
+WebWorker. This document describes how to write applications that take advantage
+of this feature.
+It also provides a detailed description of the underlying messaging
+infrastructure that angular uses to communicate between the main process and the
+worker. This infrastructure can be modified by an application developer to
+enable driving an angular 2 application from an iFrame, different window / tab,
+server, etc..
+
+## Introduction
+WebWorker support in Angular2 is designed to make it easy to leverage parallelization in your web application.
+When you choose to run your application in a WebWorker angular runs both your application's logic and the
+majority of the core angular framework in a WebWorker.
+By offloading as much code as possible to the WebWorker we keep the UI thread
+free to handle events, manipulate the DOM, and run animations. This provides a
+better framerate and UX for applications.
+
+## Bootstrapping a WebWorker Application
+Bootstrapping a WebWorker application is not much different than bootstrapping a normal application.
+The main difference is that you need to do the bootstrap process on both the worker and render thread.
+Unlike in a standard Angular2 application you don't bootstrap your main component on the render thread.
+Instead you initialize a new application injector with the WORKER_APP_PLATFORM providers and provide the name
+of your WebWorker script. See the example below for details:
+
+### Example
+To bootstrap Hello World in a WebWorker we do the following in TypeScript
+```HTML
+
+
+
+
+
+
+
+
+
+
+
+```
+```TypeScript
+// index.js
+import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT} from "angular2/platform/worker_render";
+import {platform} from "angular2/core";
+
+platform([WORKER_RENDER_PLATFORM])
+.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"});
+```
+```JavaScript
+// loader.js
+importScripts("https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js", "https://jspm.io/system@0.16.js", "angular2/web_worker/worker.js");
+System.import("app");
+```
+```TypeScript
+// app.ts
+import {Component, View, platform} from "angular2/core";
+import {WORKER_APP_PLATFORM, WORKER_APP_APPLICATION} from "angular2/platform/worker_app";
+
+@Component({
+ selector: "hello-world"
+})
+@View({
+ template: "Hello {{name}}
+})
+export class HelloWorld {
+ name: string = "Jane";
+}
+
+platform([WORKER_APP_PLATFORM])
+.application([WORKER_APP_APPLICATION])
+.then((ref) => ref.bootstrap(RootComponent));
+```
+There's a few important things to note here:
+* The UI loads angular from the file `angular2/web_worker/ui.js` and the Worker loads angular from
+`angular2/web_worker/worker.js`. These bundles are created specifically for using WebWorkers and should be used
+instead of the normal angular2.js file. Both files contain subsets of the angular2 codebase that is designed to
+run specifically on the UI or Worker. Additionally, they contain the core messaging infrastructure used to
+communicate between the Worker and the UI. This messaging code is not in the standard angular2.js file.
+* We pass `loader.js` to our application injector using the WORKER_SCRIPT symbol. This tells angular that our WebWorkers's init script is located at `loader.js`.
+You can think of `loader.js` as the index.html file for the WebWorker.
+Since WebWorkers share no memory with the UI we need to reload the angular2 dependencies before
+bootstrapping our application. We do this with `importScripts`. Additionally, we need to do this in a different
+file than `app.ts` because our module loader (System.js in this example) has not been loaded yet, and `app.ts`
+will be compiled with a `System.define` call at the top.
+* The HelloWorld Component looks exactly like a normal Angular2 HelloWorld Component! The goal of WebWorker
+support was to allow as much of Angular to live in the worker as possible.
+As such, *most* angular2 components can be bootstrapped in a WebWorker with minimal to no changes required.
+
+For reference, here's the same HelloWorld example in Dart.
+```HTML
+
+
+
+
+
+
+```
+```Dart
+// index.dart
+import "angular2/core.dart";
+import "angular2/platform/worker_render.dart";
+
+main() {
+ platform([WORKER_RENDER_PLATFORM])
+ .asyncApplication(initIsolate("my_worker.dart"));
+}
+```
+```Dart
+// background_index.dart
+import "angular2/core.dart";
+import "angular2/platform/worker_app.dart";
+import "package:angular2/src/core/reflection/reflection.dart";
+import "package:angular2/src/core/reflection/reflection_capabilities.dart";
+
+@Component(
+ selector: "hello-world"
+)
+@View(
+ template: "Hello {{name}} "
+)
+class HelloWorld {
+ String name = "Jane";
+}
+
+main(List args, SendPort replyTo) {
+ reflector.reflectionCapabilities = new ReflectionCapabilities();
+ platform([WORKER_APP_PLATFORM, new Provider(RENDER_SEND_PORT, useValue: replyTo)])
+ .application([WORKER_APP_APPLICATION])
+ .bootstrap(RootComponent);
+}
+
+```
+This code is nearly the same as the TypeScript version with just a couple key differences:
+* We don't have a `loader.js` file. Dart applications don't need this file because you don't need a module loader.
+* We provide a `SendPort` through DI using the token `RENDER_SEND_PORT`. Dart applications use the Isolate API, which communicates via
+Dart's Port abstraction. When you call `setupIsolate` from the UI thread, angular starts a new Isolate to run
+your application logic. When Dart starts a new Isolate it passes a `SendPort` to that Isolate so that it
+can communicate with the Isolate that spawned it. You need to provide this `SendPort` through DI
+so that Angular can communicate with the UI.
+* You need to set up `ReflectionCapabilities` on both the UI and Worker. Just like writing non-concurrent
+Angular2 Dart applications you need to set up the reflector. You should not use Reflection in production,
+but should use the angular 2 transformer to remove it in your final JS code. Note there's currently a bug
+with running the transformer on your UI code (#3971). You can (and should) pass the file where you call
+`bootstrap` as an entry point to the transformer, but you should not pass your UI index file
+to the transformer until that bug is fixed.
+* In dart we call `asyncApplication` instead of `application` from the render thread because starting an isolate in Dart is asyncronous
+ whereas starting a new WebWorker in JavaScript is a synchronous operation.
+
+## Writing WebWorker Compatible Components
+You can do almost everything in a WebWorker component that you can do in a typical Angular 2 Component.
+The main exception is that there is **no** DOM access from a WebWorker component. In Dart this means you can't
+import anything from `dart:html` and in JavaScript it means you can't use `document` or `window`. Instead you
+should use data bindings and if needed you can inject the `Renderer` along with your component's `ElementRef`
+directly into your component and use methods such as `setElementProperty`, `setElementAttribute`,
+`setElementClass`, `setElementStyle`, `invokeElementMethod`, and `setText`. Note that you **cannot** call
+`getNativeElementSync`. Doing so will always return `null` when running in a WebWorker.
+If you need DOM access see [Running Code on the UI](#running-code-on-the-ui).
+
+## WebWorker Design Overview
+When running your application in a WebWorker, the majority of the angular core along with your application logic
+runs on the worker. The two main components that run on the UI are the `Renderer` and the `RenderCompiler`. When
+running angular in a WebWorker the bindings for these two components are replaced by the `WebWorkerRenderer` and
+the `WebWorkerRenderCompiler`. When these components are used at runtime, they pass messages through the
+[MessageBroker](#messagebroker) instructing the UI to run the actual method and return the result. The
+[MessageBroker](#messagebroker) abstraction allows either side of the WebWorker boundary to schedule code to run
+on the opposite side and receive the result. You can use the [MessageBroker](#messagebroker)
+Additionally, the [MessageBroker](#messagebroker) sits on top of the [MessageBus](#messagebus).
+MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary such as `WebWorker <--> UI` communication, `UI <--> Server` communication,
+or `Window <--> Window` communication.
+
+See the diagram below for a high level overview of how this code is structured:
+
+
+
+## Running Code on the UI
+If your application needs to run code on the UI, there are a few options. The easiest way is to use a
+CustomElement in your view. You can then register this custom element from your html file and run code in response
+to the element's lifecycle hooks. Note, Custom Elements are still experimental. See
+[MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) for the latest details on how
+to use them.
+
+If you require more robust communication between the WebWorker and the UI you can use the [MessageBroker](#using-the-messagebroker-in-your-application) or
+[MessageBus](#using-the-messagebus-in-your-application) directly.
+
+## MessageBus
+The MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary. It supports multiplex communication through the use of a channel
+abstraction.
+
+Angular currently includes two stable MessageBus implementations, which are used by default when you run your
+application inside a WebWorker.
+
+1. The `PostMessageBus` is used by JavaScript applications to communicate between a WebWorker and the UI.
+2. The `IsolateMessageBus` is used by Dart applications to communicate between a background Isolate and the UI.
+
+Angular also includes three experimental MessageBus implementations:
+
+1. The `WebSocketMessageBus` is a Dart MessageBus that lives on the UI and communicates with an angular
+application running on a server. It's intended to be used with either the `SingleClientServerMessageBus` or the
+`MultiClientServerMessageBus`.
+2. The `SingleClientServerMessageBus` is a Dart MessageBus that lives on a Dart Server. It allows an angular
+application to run on a server and communicate with a single browser that's running the `WebSocketMessageBus`.
+3. The `MultiClientServerMessageBus` is like the `SingleClientServerMessageBus` except it allows an arbitrary
+number of clients to connect to the server. It keeps all connected browsers in sync and if an event fires in
+any connected browser it propagates the result to all connected clients. This can be especially useful as a
+debugging tool, by allowing you to connect multiple browsers / devices to the same angular application,
+change the state of that application, and ensure that all the clients render the view correctly. Using these tools
+can make it easy to catch tricky browser compatibility issues.
+
+### Using the MessageBus in Your Application
+**Note**: If you want to pass custom messages between the UI and WebWorker, it's recommended you use the
+[MessageBroker](#using-the-messagebroker-in-your-application). However, if you want to control the messaging
+protocol yourself you can use the MessageBus directly.
+
+You can obtain the MessageBus on both the render and worker thread through DI.
+To use the MessageBus you need to initialize a new channel on both the UI and WebWorker.
+In TypeScript that would look like this:
+```TypeScript
+// index.ts, which is running on the UI.
+import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT, MessageBus} from "angular2/platform/worker_render";
+import {platform} from "angular2/core";
+
+let appRef = platform([WORKER_RENDER_PLATFORM])
+.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"});
+let bus = appRef.injector.get(MessageBus);
+bus.initChannel("My Custom Channel");
+```
+```TypeScript
+// background_index.ts, which is running on the WebWorker
+import {MessageBus} from 'angular2/platform/worker_app';
+@Component({...})
+@View({...})
+export class MyComponent {
+ constructor (bus: MessageBus) {
+ bus.initChannel("My Custom Channel");
+ }
+}
+```
+
+Once the channel has been initialized either side can use the `from` and `to` methods on the MessageBus to send
+and receive messages. Both methods return EventEmitter. Expanding on the example from earlier:
+```TypeScript
+// index.ts, which is running on the UI.
+import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT, MessageBus} from "angular2/platform/worker_render";
+import {platform} from "angular2/core";
+
+let appRef = platform([WORKER_RENDER_PLATFORM])
+.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"});
+let bus = appRef.injector.get(MessageBus);
+bus.initChannel("My Custom Channel");
+bus.to("My Custom Channel").emit("Hello from the UI");
+```
+```TypeScript
+// background_index.ts, which is running on the WebWorker
+import {Component, View} from 'angular2/core';
+import {MessageBus} from 'angular2/platform/worker_app';
+@Component({...})
+@View({...})
+export class MyComponent {
+ constructor (bus: MessageBus) {
+ bus.initChannel("My Custom Channel");
+ bus.from("My Custom Channel").observer((message) => {
+ console.log(message); // will print "hello from the UI"
+ });
+ }
+}
+```
+
+This example is nearly identical in Dart, and is included below for reference:
+```Dart
+// index.dart, which is running on the UI.
+import 'package:angular2/web_workers/ui.dart';
+
+main() {
+ import "angular2/core.dart";
+ import "angular2/platform/worker_render.dart";
+
+ platform([WORKER_RENDER_PLATFORM])
+ .asyncApplication(initIsolate("my_worker.dart")).then((ref) {
+ var bus = ref.injector.get(MessageBus);
+ bus.initChannel("My Custom Channel");
+ bus.to("My Custom Channel").add("hello from the UI");
+ });
+}
+
+```
+```Dart
+// background_index.dart, which is running on the WebWorker
+import 'package:angular2/platform/worker_app.dart';
+@Component(...)
+@View(...)
+class MyComponent {
+ MyComponent (MessageBus bus) {
+ bus.initChannel("My Custom Channel");
+ bus.from("My Custom Channel").listen((message) {
+ print(message); // will print "hello from the UI"
+ });
+ }
+}
+```
+The only substantial difference between these APIs in Dart and TypeScript is the different APIs for the
+`EventEmitter`.
+
+**Note:** Because the messages passed through the MessageBus cross a WebWorker boundary, they must be serializable.
+If you use the MessageBus directly, you are responsible for serializing your messages.
+In JavaScript / TypeScript this means they must be serializable via JavaScript's
+[structured cloning algorithim](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
+
+In Dart this means they must be valid messages that can be passed through a
+[SendPort](https://api.dartlang.org/1.12.1/dart-isolate/SendPort/send.html).
+
+
+### MessageBus and Zones
+The MessageBus API includes support for [zones](http://www.github.com/angular/zone.js).
+A MessageBus can be attached to a specific zone (by calling `attachToZone`). Then specific channels can be
+specified to run in the zone when they are initialized.
+If a channel is running in the zone, that means that any events emitted from that channel will be executed within
+the given zone. For example, by default angular runs the EventDispatch channel inside the angular zone. That means
+when an event is fired from the DOM and received on the WebWorker the event handler automatically runs inside the
+angular zone. This is desired because after the event handler exits we want to exit the zone so that we trigger
+change detection. Generally, you want your channels to run inside the zone unless you have a good reason for why
+they need to run outside the zone.
+
+### Implementing and Using a Custom MessageBus
+**Note:** Implementing and using a Custom MessageBus is experimental and the APIs may change.
+
+If you want to drive your application from something other than a WebWorker you can implement a custom message
+bus. Implementing a custom message bus just means creating a class that fulfills the API specified by the
+abstract MessageBus class.
+
+If you're implementing your MessageBus in Dart you can extend the `GenericMessageBus` class included in angular.
+if you do this, you don't need to implement zone or channel support yourself. You only need to implement a
+`MessageBusSink` that extends `GenericMessageBusSink` and a `MessageBusSource` that extends
+`GenericMessageBusSource`. The `MessageBusSink` must override the `sendMessages` method. This method is
+given a list of serialized messages that it is required to send through the sink.
+The `MessageBusSource` needs to provide a [Stream](https://api.dartlang.org/1.12.1/dart-async/Stream-class.html)
+of incoming messages (either by passing the stream to `GenericMessageBusSource's` constructor or by calling
+attachTo() with the stream). It also needs to override the abstract `decodeMessages` method. This method is
+given a List of serialized messages received by the source and should perform any decoding work that needs to be
+done before the application can read the messages.
+
+For example, if your MessageBus sends and receives JSON data you would do the following:
+```Dart
+import 'package:angular2/src/web_workers/shared/generic_message_bus.dart';
+import 'dart:convert';
+
+class JsonMessageBusSink extends GenericMessageBusSink {
+ @override
+ void sendMessages(List messages) {
+ String encodedMessages = JSON.encode(messages);
+ // Send encodedMessages here
+ }
+}
+
+class JsonMessageBusSource extends GenericMessageBuSource {
+ JsonMessageBusSource(Stream incomingMessages) : super (incomingMessages);
+
+ @override
+ List decodeMessages(dynamic messages) {
+ return JSON.decode(messages);
+ }
+}
+```
+
+Once you've implemented your custom MessageBus in either TypeScript or Dart, you must provide it through DI
+during bootstrap like so:
+
+In TypeScript:
+```TypeScript
+// index.ts, running on the UI side
+import {platform, Provider, APP_INITIALIZER, Injector} from 'angular2/core';
+import {
+ WORKER_RENDER_PLATFORM,
+ WORKER_RENDER_APPLICATION_COMMON,
+ initializeGenericWorkerRenderer,
+ MessageBus
+} from 'angular2/platform/worker_render';
+
+var bus = new MyAwesomeMessageBus();
+platform([WORKER_RENDER_PLATFORM])
+.application([WORKER_RENDER_APPLICATION_COMMON, new Provider(MessageBus, {useValue: bus}),
+ new Provider(APP_INITIALIZER, {
+ useFactory: (injector) => () => initializeGenericWorkerRenderer(injector),
+ deps: [Injector],
+ multi: true
+ })
+]);
+```
+```TypeScript
+// background_index.ts, running on the application side
+import {WORKER_APP_PLATFORM, genericWorkerAppProviders} from "angular2/platform/worker_app";
+import {NgZone, platform, Provider} from "angular/core";
+import {MyApp} from './app';
+
+/**
+ * Do initialization work here to set up the app thread and MessageBus;
+ * Once you have a working MessageBus you should bootstrap your app.
+ */
+
+platform([WORKER_APP_PLATFORM_PROVIDERS])
+.application([WORKER_APP_APPLICATION_COMMON, new Provider(MessageBus, {useValue: bus}),
+new Provider(APP_INITIALIZER, {useFactory: (zone, bus) => () => initAppThread(zone, bus), multi: true, deps: [NgZone, MessageBus]})])
+.bootstrap(MyApp);
+
+function initAppThread(zone: NgZone, bus: MyAwesomeMessageBus): void{
+ /**
+ * Here you can do any initilization work that requires the app providers to be initialized.
+ * At a minimum, you must attach your bus to the zone and setup a DOM adapter.
+ * Depending on your environment you may choose to do more work here.
+ */
+}
+```
+In Dart:
+```Dart
+// index.dart, running on the UI side
+import 'package:angular2/core.dart';
+import 'package:angular2/platform/worker_render.dart';
+
+main() {
+ var bus = new MyAwesomeMessageBus();
+ platform([WORKER_RENDER_PLATFORM])
+ .application([WORKER_RENDER_APPLICATION_COMMON, new Provider(MessageBus, useValue: bus),
+ new Provider(APP_INITIALIZER,
+ useFactory: (injector) => () => initializeGenericWorkerRenderer(injector),
+ deps: [Injector],
+ multi: true
+ )
+ ]);
+}
+
+```
+```Dart
+// background_index.dart, running on the application side
+import "package:angular2/platform/worker_app.dart";
+import "package:angular2/core.dart";
+import "./app.dart" show MyApp;
+
+main() {
+ /**
+ * Do initialization work here to set up the app thread and MessageBus;
+ * Once you have a working MessageBus you should bootstrap your app.
+ */
+ reflector.reflectionCapabilities = new ReflectionCapabilities();
+ platform([WORKER_APP_PLATFORM_PROVIDERS])
+ .application([WORKER_APP_APPLICATION_COMMON, new Provider(MessageBus, useValue: bus),
+new Provider(APP_INITIALIZER, useFactory: (zone, bus) => () => initAppThread(zone, bus), multi: true, deps: [NgZone, MessageBus])])
+ .bootstrap(MyApp);
+}
+
+
+void initAppThread(NgZone zone) {
+ /**
+ * Here you can do any initilization work that requires the app providers to be initialized.
+ * At a minimum, you must attach your bus to the zone and setup a DOM adapter.
+ * Depending on your environment you may choose to do more work here.
+ */
+}
+```
+Notice how we use the `WORKER_RENDER_APPLICTION_COMMON` providers instead of the `WORKER_RENDER_APPLICATION` providers on the render thread.
+This is because the `WORKER_RENDER_APPLICATION` providers include an application initializer that starts a new WebWorker/Isolate.
+The `WORKER_RENDER_APPLICATION_COMMON` providers make no assumption about where your application code lives.
+However, we now need to provide our own app initializer. At the very least this initializer needs to call `initializeGenericWorkerRenderer`.
+
+## MessageBroker
+The MessageBroker is a higher level messaging abstraction that sits on top of the MessageBus. It is used when you
+want to execute code on the other side of a runtime boundary and may want to receive the result.
+There are two types of MessageBrokers:
+
+1. The `ServiceMessageBroker` is used by the side that actually performs
+an operation and may return a result;
+2. The `ClientMessageBroker` is used by the side that requests that
+an operation be performed and may want to receive the result.
+
+### Using the MessageBroker In Your Application
+To use MessageBrokers in your application you must initialize both a `ClientMessageBroker` and a
+`ServiceMessageBroker` on the same channel. You can then register methods with the `ServiceMessageBroker` and
+instruct the `ClientMessageBroker` to run those methods. Below is a lightweight example of using
+MessageBrokers in an application. For a more complete example, check out the `WebWorkerRenderer` and
+`MessageBasedRenderer` inside the Angular WebWorker code.
+
+#### Using the MessageBroker in TypeScript
+```TypeScript
+// index.ts, which is running on the UI with a method that we want to expose to a WebWorker
+import {WORKER_RENDER_PLATFORM, WORKER_RENDER_APPLICATION, WORKER_SCRIPT, ServiceMessageBrokerFactory} from "angular2/platform/worker_render";
+import {platform} from "angular2/core";
+
+let appRef = platform([WORKER_RENDER_PLATFORM])
+.application([WORKER_RENDER_APPLICATION, new Provider(WORKER_SCRIPT, {useValue: "loader.js"});
+let injector = instance.injector;
+var broker = injector.get(ServiceMessageBrokerFactory).createMessageBroker("My Broker Channel");
+
+// assume we have some function doCoolThings that takes a string argument and returns a Promise
+broker.registerMethod("awesomeMethod", [PRIMITIVE], (arg1: string) => doCoolThing(arg1), PRIMITIVE);
+```
+```TypeScript
+// background.ts, which is running on a WebWorker and wants to execute a method on the UI
+import {Component, View} from 'angular2/core';
+import {ClientMessageBrokerFactory, PRIMITIVE, UiArguments, FnArgs} from 'angular2/platform/worker_app';
+
+@Component(...)
+@View(...)
+export class MyComponent {
+ constructor(brokerFactory: ClientMessageBrokerFactory) {
+ var broker = brokerFactory.createMessageBroker("My Broker Channel");
+
+ var arguments = [new FnArg(value, PRIMITIVE)];
+ var methodInfo = new UiArguments("awesomeMethod", arguments);
+ broker.runOnService(methodInfo, PRIMTIVE).then((result: string) => {
+ // result will be equal to the return value of doCoolThing(value) that ran on the UI.
+ });
+ }
+}
+```
+#### Using the MessageBroker in Dart
+```Dart
+// index.dart, which is running on the UI with a method that we want to expose to a WebWorker
+import "angular2/core.dart";
+import "angular2/platform/worker_render.dart";
+
+main() {
+ platform([WORKER_RENDER_PLATFORM])
+ .asyncApplication(initIsolate("my_worker.dart")).then((ref) {
+ var broker = ref.injector.get(ServiceMessageBrokerFactory).createMessageBroker("My Broker Channel");
+
+ // assume we have some function doCoolThings that takes a String argument and returns a Future
+ broker.registerMethod("awesomeMethod", [PRIMITIVE], (String arg1) => doCoolThing(arg1), PRIMITIVE);
+ });
+}
+
+```
+```Dart
+// background.dart, which is running on a WebWorker and wants to execute a method on the UI
+import 'package:angular2/core.dart';
+import 'package:angular2/platform/worker_app.dart';
+
+@Component(...)
+@View(...)
+class MyComponent {
+ MyComponent(ClientMessageBrokerFactory brokerFactory) {
+ var broker = brokerFactory.createMessageBroker("My Broker Channel");
+
+ var arguments = [new FnArg(value, PRIMITIVE)];
+ var methodInfo = new UiArguments("awesomeMethod", arguments);
+ broker.runOnService(methodInfo, PRIMTIVE).then((String result) {
+ // result will be equal to the return value of doCoolThing(value) that ran on the UI.
+ });
+ }
+}
+```
+Both the client and the service create new MessageBrokers and attach them to the same channel.
+The service then calls `registerMethod` to register the method that it wants to listen to. Register method takes
+four arguments. The first is the name of the method, the second is the Types of that method's parameters, the
+third is the method itself, and the fourth (which is optional) is the return Type of that method.
+The MessageBroker handles serializing / deserializing your parameters and return types using angular's serializer.
+However, at the moment the serializer only knows how to serialize angular classes like those used by the Renderer.
+If you're passing anything other than those types around in your application you can handle serialization yourself
+and then use the `PRIMITIVE` type to tell the MessageBroker to avoid serializing your data.
+
+The last thing that happens is that the client calls `runOnService` with the name of the method it wants to run,
+a list of that method's arguments and their types, and (optionally) the expected return type.
diff --git a/modules/angular2/examples/README.md b/modules/angular2/examples/README.md
new file mode 100644
index 000000000000..855bc0b7a3ed
--- /dev/null
+++ b/modules/angular2/examples/README.md
@@ -0,0 +1,6 @@
+# API Examples
+
+This folder contains small example apps that get in-lined into our API docs.
+These examples are written with idiomatic TypeScript, and are not transpiled to Dart.
+Each example contains tests for application behavior (as opposed to testing Angular's
+behavior) just like an Angular application developer would write.
diff --git a/modules/angular2/src/di/type_info.ts b/modules/angular2/examples/animate/ts/.gitkeep
similarity index 100%
rename from modules/angular2/src/di/type_info.ts
rename to modules/angular2/examples/animate/ts/.gitkeep
diff --git a/modules/angular2/examples/common/forms/ts/validators/validators.ts b/modules/angular2/examples/common/forms/ts/validators/validators.ts
new file mode 100644
index 000000000000..6744c8b5ed92
--- /dev/null
+++ b/modules/angular2/examples/common/forms/ts/validators/validators.ts
@@ -0,0 +1,30 @@
+import {Component} from 'angular2/core';
+import {MinLengthValidator, MaxLengthValidator} from 'angular2/common';
+
+// #docregion min
+@Component({
+ selector: 'min-cmp',
+ directives: [MinLengthValidator],
+ template: `
+
+`
+})
+class MinLengthTestComponent {
+}
+// #enddocregion
+
+// #docregion max
+@Component({
+ selector: 'max-cmp',
+ directives: [MaxLengthValidator],
+ template: `
+
+`
+})
+class MaxLengthTestComponent {
+}
+// #enddocregion
diff --git a/modules/angular2/examples/compiler/ts/url_resolver/url_resolver.ts b/modules/angular2/examples/compiler/ts/url_resolver/url_resolver.ts
new file mode 100644
index 000000000000..3910a38a1a82
--- /dev/null
+++ b/modules/angular2/examples/compiler/ts/url_resolver/url_resolver.ts
@@ -0,0 +1,19 @@
+import {provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {UrlResolver} from 'angular2/compiler';
+
+var MyApp;
+
+// #docregion url_resolver
+class MyUrlResolver extends UrlResolver {
+ resolve(baseUrl: string, url: string): string {
+ // Serve CSS files from a special CDN.
+ if (url.substr(-4) === '.css') {
+ return super.resolve('http://cdn.myapp.com/css/', url);
+ }
+ return super.resolve(baseUrl, url);
+ }
+}
+
+bootstrap(MyApp, [provide(UrlResolver, {useClass: MyUrlResolver})]);
+// #enddocregion
diff --git a/modules/angular2/examples/core/debug/ts/debug_element/debug_element.ts b/modules/angular2/examples/core/debug/ts/debug_element/debug_element.ts
new file mode 100644
index 000000000000..ebda75d05c34
--- /dev/null
+++ b/modules/angular2/examples/core/debug/ts/debug_element/debug_element.ts
@@ -0,0 +1,16 @@
+import {DebugElement, Scope} from 'angular2/core';
+
+var debugElement: DebugElement;
+var predicate;
+
+// #docregion scope_all
+debugElement.query(predicate, Scope.all);
+// #enddocregion
+
+// #docregion scope_light
+debugElement.query(predicate, Scope.light);
+// #enddocregion
+
+// #docregion scope_view
+debugElement.query(predicate, Scope.view);
+// #enddocregion
diff --git a/modules/angular2/examples/core/di/ts/forward_ref/forward_ref.ts b/modules/angular2/examples/core/di/ts/forward_ref/forward_ref.ts
new file mode 100644
index 000000000000..a9b524b80fca
--- /dev/null
+++ b/modules/angular2/examples/core/di/ts/forward_ref/forward_ref.ts
@@ -0,0 +1,26 @@
+import {Inject, Injector, forwardRef, resolveForwardRef, ForwardRefFn} from 'angular2/core';
+
+// #docregion forward_ref_fn
+var ref = forwardRef(() => Lock);
+// #enddocregion
+
+// #docregion forward_ref
+class Door {
+ lock: Lock;
+ constructor(@Inject(forwardRef(() => Lock)) lock: Lock) { this.lock = lock; }
+}
+
+// Only at this point Lock is defined.
+class Lock {}
+
+var injector = Injector.resolveAndCreate([Door, Lock]);
+var door = injector.get(Door);
+expect(door instanceof Door).toBe(true);
+expect(door.lock instanceof Lock).toBe(true);
+// #enddocregion
+
+// #docregion resolve_forward_ref
+var ref = forwardRef(() => "refValue");
+expect(resolveForwardRef(ref)).toEqual("refValue");
+expect(resolveForwardRef("regularValue")).toEqual("regularValue");
+// #enddocregion
\ No newline at end of file
diff --git a/modules/angular2/examples/core/forms/ts/ng_validators/ng_validators.ts b/modules/angular2/examples/core/forms/ts/ng_validators/ng_validators.ts
new file mode 100644
index 000000000000..e0206403bad0
--- /dev/null
+++ b/modules/angular2/examples/core/forms/ts/ng_validators/ng_validators.ts
@@ -0,0 +1,10 @@
+import {bootstrap} from 'angular2/bootstrap';
+import {NG_VALIDATORS} from 'angular2/common';
+import {Provider} from 'angular2/core';
+
+let MyApp = null;
+let myValidator = null;
+
+// #docregion ng_validators
+bootstrap(MyApp, [new Provider(NG_VALIDATORS, {useValue: myValidator, multi: true})]);
+// #enddocregion
diff --git a/modules/angular2/examples/core/pipes/ts/async_pipe/async_pipe_example.dart b/modules/angular2/examples/core/pipes/ts/async_pipe/async_pipe_example.dart
new file mode 100644
index 000000000000..2bc22b2b2a1e
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/async_pipe/async_pipe_example.dart
@@ -0,0 +1,2 @@
+library angular2.examples.core.pipes.ts.async_pipe;
+// TODO(alxhub): Implement an example for Dart.
\ No newline at end of file
diff --git a/modules/angular2/examples/core/pipes/ts/async_pipe/async_pipe_example.ts b/modules/angular2/examples/core/pipes/ts/async_pipe/async_pipe_example.ts
new file mode 100644
index 000000000000..879ff08455a5
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/async_pipe/async_pipe_example.ts
@@ -0,0 +1,58 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {Observable} from 'rxjs/Observable';
+
+// #docregion AsyncPipe
+@Component({
+ selector: 'async-example',
+ template: `
+
Wait for it... {{ greeting | async }}
+
{{ arrived ? 'Reset' : 'Resolve' }}
+
`
+})
+export class AsyncPipeExample {
+ greeting: Promise = null;
+ arrived: boolean = false;
+
+ private resolve: Function = null;
+
+ constructor() { this.reset(); }
+
+ reset() {
+ this.arrived = false;
+ this.greeting = new Promise((resolve, reject) => { this.resolve = resolve; });
+ }
+
+ clicked() {
+ if (this.arrived) {
+ this.reset();
+ } else {
+ this.resolve("hi there!");
+ this.arrived = true;
+ }
+ }
+}
+// #enddocregion
+
+// #docregion AsyncPipeObservable
+@Component({selector: "task-cmp", template: "Time: {{ time | async }}"})
+class Task {
+ time = new Observable(
+ observer => { setInterval(_ => observer.next(new Date().getTime()), 500); });
+}
+// #enddocregion
+
+@Component({
+ selector: 'example-app',
+ directives: [AsyncPipeExample],
+ template: `
+ AsyncPipe Example
+
+ `
+})
+export class AppCmp {
+}
+
+export function main() {
+ bootstrap(AppCmp);
+}
diff --git a/modules/angular2/examples/core/pipes/ts/async_pipe/index.html b/modules/angular2/examples/core/pipes/ts/async_pipe/index.html
new file mode 100644
index 000000000000..3b4b0e30c7ac
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/async_pipe/index.html
@@ -0,0 +1,24 @@
+
+
+
+ AsyncPipe Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/core/pipes/ts/date_pipe/date_pipe_example.dart b/modules/angular2/examples/core/pipes/ts/date_pipe/date_pipe_example.dart
new file mode 100644
index 000000000000..40832aac0623
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/date_pipe/date_pipe_example.dart
@@ -0,0 +1,2 @@
+library angular2.examples.core.pipes.ts.date_pipe;
+// TODO(alxhub): Implement an example for Dart.
diff --git a/modules/angular2/examples/core/pipes/ts/date_pipe/date_pipe_example.ts b/modules/angular2/examples/core/pipes/ts/date_pipe/date_pipe_example.ts
new file mode 100644
index 000000000000..5523dfdcc865
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/date_pipe/date_pipe_example.ts
@@ -0,0 +1,31 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+
+// #docregion DatePipe
+@Component({
+ selector: 'date-example',
+ template: `
+
Today is {{today | date}}
+
Or if you prefer, {{today | date:'fullDate'}}
+
The time is {{today | date:'jmZ'}}
+
`
+})
+export class DatePipeExample {
+ today: number = Date.now();
+}
+// #enddocregion
+
+@Component({
+ selector: 'example-app',
+ directives: [DatePipeExample],
+ template: `
+ DatePipe Example
+
+ `
+})
+export class AppCmp {
+}
+
+export function main() {
+ bootstrap(AppCmp);
+}
diff --git a/modules/angular2/examples/core/pipes/ts/date_pipe/index.html b/modules/angular2/examples/core/pipes/ts/date_pipe/index.html
new file mode 100644
index 000000000000..43ccdf1337c7
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/date_pipe/index.html
@@ -0,0 +1,24 @@
+
+
+
+ DatePipe Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/core/pipes/ts/json_pipe/index.html b/modules/angular2/examples/core/pipes/ts/json_pipe/index.html
new file mode 100644
index 000000000000..4d4ece7ab143
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/json_pipe/index.html
@@ -0,0 +1,24 @@
+
+
+
+ JsonPipe Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/core/pipes/ts/json_pipe/json_pipe_example.ts b/modules/angular2/examples/core/pipes/ts/json_pipe/json_pipe_example.ts
new file mode 100644
index 000000000000..8d9a62614338
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/json_pipe/json_pipe_example.ts
@@ -0,0 +1,32 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+
+// #docregion JsonPipe
+@Component({
+ selector: 'json-example',
+ template: `
+
Without JSON pipe:
+
{{object}}
+
With JSON pipe:
+
{{object | json}}
+
`
+})
+export class JsonPipeExample {
+ object: Object = {foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}}
+}
+// #enddocregion
+
+@Component({
+ selector: 'example-app',
+ directives: [JsonPipeExample],
+ template: `
+ JsonPipe Example
+
+ `
+})
+export class AppCmp {
+}
+
+export function main() {
+ bootstrap(AppCmp);
+}
diff --git a/modules/angular2/examples/core/pipes/ts/lowerupper_pipe/index.html b/modules/angular2/examples/core/pipes/ts/lowerupper_pipe/index.html
new file mode 100644
index 000000000000..74d5242b7110
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/lowerupper_pipe/index.html
@@ -0,0 +1,24 @@
+
+
+
+ LowercasePipe & UppercasePipe Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/core/pipes/ts/lowerupper_pipe/lowerupper_pipe_example.ts b/modules/angular2/examples/core/pipes/ts/lowerupper_pipe/lowerupper_pipe_example.ts
new file mode 100644
index 000000000000..2d891111a1d1
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/lowerupper_pipe/lowerupper_pipe_example.ts
@@ -0,0 +1,32 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+
+// #docregion LowerUpperPipe
+@Component({
+ selector: 'lowerupper-example',
+ template: `
+
Name:
+
In lowercase:
'{{value | lowercase}}'
+
In uppercase:
'{{value | uppercase}}'
+
`
+})
+export class LowerUpperPipeExample {
+ value: string;
+ change(value) { this.value = value; }
+}
+// #enddocregion
+
+@Component({
+ selector: 'example-app',
+ directives: [LowerUpperPipeExample],
+ template: `
+ LowercasePipe & UppercasePipe Example
+
+ `
+})
+export class AppCmp {
+}
+
+export function main() {
+ bootstrap(AppCmp);
+}
diff --git a/modules/angular2/examples/core/pipes/ts/number_pipe/index.html b/modules/angular2/examples/core/pipes/ts/number_pipe/index.html
new file mode 100644
index 000000000000..c208aeb66191
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/number_pipe/index.html
@@ -0,0 +1,24 @@
+
+
+
+ Numeric Pipe Examples
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/core/pipes/ts/number_pipe/number_pipe_example.ts b/modules/angular2/examples/core/pipes/ts/number_pipe/number_pipe_example.ts
new file mode 100644
index 000000000000..08f1b4efb0b0
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/number_pipe/number_pipe_example.ts
@@ -0,0 +1,66 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+
+// #docregion NumberPipe
+@Component({
+ selector: 'number-example',
+ template: `
+
e (no formatting): {{e}}
+
e (3.1-5): {{e | number:'3.1-5'}}
+
pi (no formatting): {{pi}}
+
pi (3.5-5): {{pi | number:'3.5-5'}}
+
`
+})
+export class NumberPipeExample {
+ pi: number = 3.141;
+ e: number = 2.718281828459045;
+}
+// #enddocregion
+
+// #docregion PercentPipe
+@Component({
+ selector: 'percent-example',
+ template: `
+
A: {{a | percent}}
+
B: {{b | percent:'4.3-5'}}
+
`
+})
+export class PercentPipeExample {
+ a: number = 0.259;
+ b: number = 1.3495;
+}
+// #enddocregion
+
+// #docregion CurrencyPipe
+@Component({
+ selector: 'currency-example',
+ template: `
+
A: {{a | currency:'USD':false}}
+
B: {{b | currency:'USD':true:'4.2-2'}}
+
`
+})
+export class CurrencyPipeExample {
+ a: number = 0.259;
+ b: number = 1.3495;
+}
+// #enddocregion
+
+@Component({
+ selector: 'example-app',
+ directives: [NumberPipeExample, PercentPipeExample, CurrencyPipeExample],
+ template: `
+ Numeric Pipe Examples
+ NumberPipe Example
+
+ PercentPipe Example
+
+ CurrencyPipeExample
+
+ `
+})
+export class AppCmp {
+}
+
+export function main() {
+ bootstrap(AppCmp);
+}
diff --git a/modules/angular2/examples/core/pipes/ts/slice_pipe/index.html b/modules/angular2/examples/core/pipes/ts/slice_pipe/index.html
new file mode 100644
index 000000000000..e77619bebfc7
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/slice_pipe/index.html
@@ -0,0 +1,24 @@
+
+
+
+ SlicePipe Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/core/pipes/ts/slice_pipe/slice_pipe_example.ts b/modules/angular2/examples/core/pipes/ts/slice_pipe/slice_pipe_example.ts
new file mode 100644
index 000000000000..2504b9da2f9a
--- /dev/null
+++ b/modules/angular2/examples/core/pipes/ts/slice_pipe/slice_pipe_example.ts
@@ -0,0 +1,47 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+
+// #docregion SlicePipe_string
+@Component({
+ selector: 'slice-string-example',
+ template: `
+
{{str}}[0:4]: '{{str | slice:0:4}}' - output is expected to be 'abcd'
+
{{str}}[4:0]: '{{str | slice:4:0}}' - output is expected to be ''
+
{{str}}[-4]: '{{str | slice:-4}}' - output is expected to be 'ghij'
+
{{str}}[-4:-2]: '{{str | slice:-4:-2}}' - output is expected to be 'gh'
+
{{str}}[-100]: '{{str | slice:-100}}' - output is expected to be 'abcdefghij'
+
{{str}}[100]: '{{str | slice:100}}' - output is expected to be ''
+
`
+})
+export class SlicePipeStringExample {
+ str: string = 'abcdefghij';
+}
+// #enddocregion
+
+// #docregion SlicePipe_list
+@Component({
+ selector: 'slice-list-example',
+ template: `
+
{{i}}
+
`
+})
+export class SlicePipeListExample {
+ collection: string[] = ['a', 'b', 'c', 'd'];
+}
+// #enddocregion
+
+@Component({
+ selector: 'example-app',
+ directives: [SlicePipeListExample, SlicePipeStringExample],
+ template: `
+ SlicePipe Examples
+
+
+ `
+})
+export class AppCmp {
+}
+
+export function main() {
+ bootstrap(AppCmp);
+}
diff --git a/modules/angular2/examples/core/ts/.gitkeep b/modules/angular2/examples/core/ts/.gitkeep
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/modules/angular2/examples/core/ts/bootstrap/bootstrap.ts b/modules/angular2/examples/core/ts/bootstrap/bootstrap.ts
new file mode 100644
index 000000000000..1e999bf76409
--- /dev/null
+++ b/modules/angular2/examples/core/ts/bootstrap/bootstrap.ts
@@ -0,0 +1,13 @@
+import {Component} from 'angular2/core';
+import {bootstrap} from 'angular2/platform/browser';
+
+// #docregion bootstrap
+@Component({selector: 'my-app', template: 'Hello {{ name }}!'})
+class MyApp {
+ name: string = 'World';
+}
+
+function main() {
+ return bootstrap(MyApp);
+}
+// #enddocregion
diff --git a/modules/angular2/examples/core/ts/metadata/metadata.ts b/modules/angular2/examples/core/ts/metadata/metadata.ts
new file mode 100644
index 000000000000..0924ad4e8daf
--- /dev/null
+++ b/modules/angular2/examples/core/ts/metadata/metadata.ts
@@ -0,0 +1,43 @@
+import {Component, Attribute, Directive, Pipe} from 'angular2/core';
+
+var CustomDirective;
+
+// #docregion component
+@Component({selector: 'greet', template: 'Hello {{name}}!', directives: [CustomDirective]})
+class Greet {
+ name: string = 'World';
+}
+// #enddocregion
+
+// #docregion attributeFactory
+@Component({selector: 'page', template: 'Title: {{title}}'})
+class Page {
+ title: string;
+ constructor(@Attribute('title') title: string) { this.title = title; }
+}
+// #enddocregion
+
+// #docregion attributeMetadata
+@Directive({selector: 'input'})
+class InputAttrDirective {
+ constructor(@Attribute('type') type) {
+ // type would be 'text' in this example
+ }
+}
+// #enddocregion
+
+// #docregion directive
+@Directive({selector: 'input'})
+class InputDirective {
+ constructor() {
+ // Add some logic.
+ }
+}
+// #enddocregion
+
+// #docregion pipe
+@Pipe({name: 'lowercase'})
+class Lowercase {
+ transform(v, args) { return v.toLowerCase(); }
+}
+// #enddocregion
diff --git a/modules/angular2/examples/core/ts/platform/platform.ts b/modules/angular2/examples/core/ts/platform/platform.ts
new file mode 100644
index 000000000000..98a916c9d3ec
--- /dev/null
+++ b/modules/angular2/examples/core/ts/platform/platform.ts
@@ -0,0 +1,13 @@
+import {Component, platform} from 'angular2/core';
+import {BROWSER_PROVIDERS, BROWSER_APP_PROVIDERS} from 'angular2/platform/browser';
+
+var appProviders: any[] = [];
+
+// #docregion longform
+@Component({selector: 'my-app', template: 'Hello World'})
+class MyApp {
+}
+
+var app = platform(BROWSER_PROVIDERS).application([BROWSER_APP_PROVIDERS, appProviders]);
+app.bootstrap(MyApp);
+// #enddocregion
diff --git a/modules/angular2/examples/core/ts/prod_mode/my_component.ts b/modules/angular2/examples/core/ts/prod_mode/my_component.ts
new file mode 100644
index 000000000000..e265b80648d3
--- /dev/null
+++ b/modules/angular2/examples/core/ts/prod_mode/my_component.ts
@@ -0,0 +1,5 @@
+import {Component} from 'angular2/core';
+
+@Component({selector: 'my-component', template: 'My Component '})
+export class MyComponent {
+}
diff --git a/modules/angular2/examples/core/ts/prod_mode/prod_mode_example.ts b/modules/angular2/examples/core/ts/prod_mode/prod_mode_example.ts
new file mode 100644
index 000000000000..76c3e15f4afa
--- /dev/null
+++ b/modules/angular2/examples/core/ts/prod_mode/prod_mode_example.ts
@@ -0,0 +1,8 @@
+// #docregion enableProdMode
+import {enableProdMode} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {MyComponent} from 'my_component';
+
+enableProdMode();
+bootstrap(MyComponent);
+// #enddocregion
diff --git a/modules/angular2/examples/facade/ts/async/observable.ts b/modules/angular2/examples/facade/ts/async/observable.ts
new file mode 100644
index 000000000000..56ce718a74fc
--- /dev/null
+++ b/modules/angular2/examples/facade/ts/async/observable.ts
@@ -0,0 +1,8 @@
+// #docregion Observable
+import {Observable} from 'rxjs/Observable';
+var obs = new Observable(obs => {
+ var i = 0;
+ setInterval(_ => { obs.next(++i); }, 1000);
+});
+obs.subscribe(i => console.log(`${i} seconds elapsed`));
+// #enddocregion
diff --git a/modules/angular2/examples/facade/ts/async/observable_all.ts b/modules/angular2/examples/facade/ts/async/observable_all.ts
new file mode 100644
index 000000000000..6c1b2ae1c0dc
--- /dev/null
+++ b/modules/angular2/examples/facade/ts/async/observable_all.ts
@@ -0,0 +1,3 @@
+// #docregion Observable
+import 'rxjs';
+// #enddocregion
diff --git a/modules/angular2/examples/facade/ts/async/observable_patched.ts b/modules/angular2/examples/facade/ts/async/observable_patched.ts
new file mode 100644
index 000000000000..b63ae01e8887
--- /dev/null
+++ b/modules/angular2/examples/facade/ts/async/observable_patched.ts
@@ -0,0 +1,10 @@
+// #docregion Observable
+import {Observable} from 'rxjs/Observable';
+import 'rxjs/add/operator/map';
+
+var obs = new Observable(obs => {
+ var i = 0;
+ setInterval(_ => obs.next(++i), 1000);
+});
+obs.map(i => `${i} seconds elapsed`).subscribe(msg => console.log(msg));
+// #enddocregion
diff --git a/modules/angular2/examples/facade/ts/async/observable_pure.ts b/modules/angular2/examples/facade/ts/async/observable_pure.ts
new file mode 100644
index 000000000000..a73bfb4d0b5c
--- /dev/null
+++ b/modules/angular2/examples/facade/ts/async/observable_pure.ts
@@ -0,0 +1,10 @@
+// #docregion Observable
+import {Observable} from 'rxjs/Observable';
+import {map} from 'rxjs/operator/map';
+
+var obs = new Observable(obs => {
+ var i = 0;
+ setInterval(_ => obs.next(++i), 1000);
+});
+map.call(obs, i => `${i} seconds elapsed`).subscribe(msg => console.log(msg));
+// #enddocregion
diff --git a/modules/angular2/examples/http/ts/.gitkeep b/modules/angular2/examples/http/ts/.gitkeep
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/modules/angular2/examples/platform/dom/debug/ts/by/by.ts b/modules/angular2/examples/platform/dom/debug/ts/by/by.ts
new file mode 100644
index 000000000000..58c888328cc4
--- /dev/null
+++ b/modules/angular2/examples/platform/dom/debug/ts/by/by.ts
@@ -0,0 +1,17 @@
+import {By} from 'angular2/platform/browser';
+import {DebugElement, Scope} from 'angular2/core';
+
+var debugElement: DebugElement;
+class MyDirective {}
+
+// #docregion by_all
+debugElement.query(By.all(), Scope.all);
+// #enddocregion
+
+// #docregion by_css
+debugElement.query(By.css('[attribute]'), Scope.all);
+// #enddocregion
+
+// #docregion by_directive
+debugElement.query(By.directive(MyDirective), Scope.all);
+// #enddocregion
diff --git a/modules/angular2/examples/platform/dom/debug/ts/debug_element_view_listener/providers.ts b/modules/angular2/examples/platform/dom/debug/ts/debug_element_view_listener/providers.ts
new file mode 100644
index 000000000000..b9dec70aaeac
--- /dev/null
+++ b/modules/angular2/examples/platform/dom/debug/ts/debug_element_view_listener/providers.ts
@@ -0,0 +1,10 @@
+import {Component} from 'angular2/core';
+import {bootstrap, ELEMENT_PROBE_PROVIDERS} from 'angular2/platform/browser';
+
+@Component({selector: 'my-component'})
+class MyAppComponent {
+}
+
+// #docregion providers
+bootstrap(MyAppComponent, [ELEMENT_PROBE_PROVIDERS]);
+// #enddocregion
\ No newline at end of file
diff --git a/modules/angular2/examples/router/ts/.gitkeep b/modules/angular2/examples/router/ts/.gitkeep
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts b/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts
new file mode 100644
index 000000000000..cd0ccc66e2df
--- /dev/null
+++ b/modules/angular2/examples/router/ts/can_activate/can_activate_example.ts
@@ -0,0 +1,57 @@
+import {provide, Component} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {
+ CanActivate,
+ RouteConfig,
+ ComponentInstruction,
+ APP_BASE_HREF,
+ ROUTER_DIRECTIVES
+} from 'angular2/router';
+
+function checkIfWeHavePermission(instruction: ComponentInstruction) {
+ return instruction.params['id'] == '1';
+}
+
+// #docregion canActivate
+@Component({selector: 'control-panel-cmp', template: `Settings: ...
`})
+@CanActivate(checkIfWeHavePermission)
+class ControlPanelCmp {
+}
+// #enddocregion
+
+
+@Component({
+ selector: 'home-cmp',
+ template: `
+ Welcome Home!
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+class HomeCmp {
+}
+
+
+@Component({
+ selector: 'example-app',
+ template: `
+ My App
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+@RouteConfig([
+ {path: '/user-settings/:id', component: ControlPanelCmp, name: 'ControlPanelCmp'},
+ {path: '/', component: HomeCmp, name: 'HomeCmp'}
+])
+class AppCmp {
+}
+
+
+export function main() {
+ return bootstrap(
+ AppCmp, [provide(APP_BASE_HREF, {useValue: '/angular2/examples/router/ts/can_activate'})]);
+}
diff --git a/modules/angular2/examples/router/ts/can_activate/can_activate_spec.ts b/modules/angular2/examples/router/ts/can_activate/can_activate_spec.ts
new file mode 100644
index 000000000000..3f5728bb7afa
--- /dev/null
+++ b/modules/angular2/examples/router/ts/can_activate/can_activate_spec.ts
@@ -0,0 +1,36 @@
+import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
+import {Promise} from 'angular2/src/facade/async';
+
+function waitForElement(selector) {
+ var EC = (protractor).ExpectedConditions;
+ // Waits for the element with id 'abc' to be present on the dom.
+ browser.wait(EC.presenceOf($(selector)), 20000);
+}
+
+describe('reuse example app', function() {
+
+ afterEach(verifyNoBrowserErrors);
+
+ var URL = 'angular2/examples/router/ts/can_activate/';
+
+ it('should navigate to user 1', function() {
+ browser.get(URL);
+ waitForElement('home-cmp');
+
+ element(by.css('#user-1-link')).click();
+ waitForElement('control-panel-cmp');
+ expect(browser.getCurrentUrl()).toMatch(/\/user-settings\/1$/);
+
+ expect(element(by.css('control-panel-cmp')).getText()).toContain('Settings');
+ });
+
+ it('should not navigate to user 2', function() {
+ browser.get(URL);
+ waitForElement('home-cmp');
+
+ element(by.css('#user-2-link')).click();
+ waitForElement('home-cmp');
+
+ expect(element(by.css('home-cmp')).getText()).toContain('Welcome Home!');
+ });
+});
diff --git a/modules/angular2/examples/router/ts/can_activate/index.html b/modules/angular2/examples/router/ts/can_activate/index.html
new file mode 100644
index 000000000000..13c8bdab8493
--- /dev/null
+++ b/modules/angular2/examples/router/ts/can_activate/index.html
@@ -0,0 +1,24 @@
+
+
+
+ Routing canActivate Lifecycle Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts b/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts
new file mode 100644
index 000000000000..41de37b4b9b8
--- /dev/null
+++ b/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_example.ts
@@ -0,0 +1,67 @@
+import {provide, Component} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {
+ CanDeactivate,
+ RouteConfig,
+ RouteParams,
+ ComponentInstruction,
+ ROUTER_DIRECTIVES,
+ APP_BASE_HREF
+} from 'angular2/router';
+
+// #docregion routerCanDeactivate
+@Component({
+ selector: 'note-cmp',
+ template: `
+
+
id: {{id}}
+
+ `
+})
+class NoteCmp implements CanDeactivate {
+ id: string;
+
+ constructor(params: RouteParams) { this.id = params.get('id'); }
+
+ routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
+ return confirm('Are you sure you want to leave?');
+ }
+}
+// #enddocregion
+
+
+@Component({
+ selector: 'note-index-cmp',
+ template: `
+ Your Notes
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+class NoteIndexCmp {
+}
+
+
+@Component({
+ selector: 'example-app',
+ template: `
+ My App
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+@RouteConfig([
+ {path: '/note/:id', component: NoteCmp, name: 'NoteCmp'},
+ {path: '/', component: NoteIndexCmp, name: 'NoteIndexCmp'}
+])
+class AppCmp {
+}
+
+
+export function main() {
+ return bootstrap(
+ AppCmp, [provide(APP_BASE_HREF, {useValue: '/angular2/examples/router/ts/can_deactivate'})]);
+}
diff --git a/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_spec.ts b/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_spec.ts
new file mode 100644
index 000000000000..b92fd26332fc
--- /dev/null
+++ b/modules/angular2/examples/router/ts/can_deactivate/can_deactivate_spec.ts
@@ -0,0 +1,52 @@
+import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
+import {Promise} from 'angular2/src/facade/async';
+
+function waitForElement(selector) {
+ var EC = (protractor).ExpectedConditions;
+ // Waits for the element with id 'abc' to be present on the dom.
+ browser.wait(EC.presenceOf($(selector)), 20000);
+}
+
+function waitForAlert() {
+ var EC = (protractor).ExpectedConditions;
+ browser.wait(EC.alertIsPresent(), 1000);
+}
+
+describe('can deactivate example app', function() {
+
+ afterEach(verifyNoBrowserErrors);
+
+ var URL = 'angular2/examples/router/ts/can_deactivate/';
+
+ it('should not navigate away when prompt is cancelled', function() {
+ browser.get(URL);
+ waitForElement('note-index-cmp');
+
+ element(by.css('#note-1-link')).click();
+ waitForElement('note-cmp');
+
+ browser.navigate().back();
+ waitForAlert();
+
+ browser.switchTo().alert().dismiss(); // Use to simulate cancel button
+
+ expect(element(by.css('note-cmp')).getText()).toContain('id: 1');
+ });
+
+ it('should navigate away when prompt is confirmed', function() {
+ browser.get(URL);
+ waitForElement('note-index-cmp');
+
+ element(by.css('#note-1-link')).click();
+ waitForElement('note-cmp');
+
+ browser.navigate().back();
+ waitForAlert();
+
+ browser.switchTo().alert().accept();
+
+ waitForElement('note-index-cmp');
+
+ expect(element(by.css('note-index-cmp')).getText()).toContain('Your Notes');
+ });
+});
diff --git a/modules/angular2/examples/router/ts/can_deactivate/index.html b/modules/angular2/examples/router/ts/can_deactivate/index.html
new file mode 100644
index 000000000000..05a7324d38d4
--- /dev/null
+++ b/modules/angular2/examples/router/ts/can_deactivate/index.html
@@ -0,0 +1,24 @@
+
+
+
+ Routing routerCanDeactivate Lifecycle Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/router/ts/on_activate/index.html b/modules/angular2/examples/router/ts/on_activate/index.html
new file mode 100644
index 000000000000..12badf9ade7f
--- /dev/null
+++ b/modules/angular2/examples/router/ts/on_activate/index.html
@@ -0,0 +1,24 @@
+
+
+
+ Routing Reuse Lifecycle Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts b/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts
new file mode 100644
index 000000000000..2a0451391221
--- /dev/null
+++ b/modules/angular2/examples/router/ts/on_activate/on_activate_example.ts
@@ -0,0 +1,47 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {
+ OnActivate,
+ ComponentInstruction,
+ RouteConfig,
+ ROUTER_DIRECTIVES,
+ APP_BASE_HREF
+} from 'angular2/router';
+
+
+// #docregion routerOnActivate
+@Component({selector: 'my-cmp', template: `routerOnActivate: {{log}}
`})
+class MyCmp implements OnActivate {
+ log: string = '';
+
+ routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
+ this.log = `Finished navigating from "${prev ? prev.urlPath : 'null'}" to "${next.urlPath}"`;
+ }
+}
+// #enddocregion
+
+
+@Component({
+ selector: 'example-app',
+ template: `
+ My App
+
+ Navigate Home |
+ Navigate with a Param
+
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+@RouteConfig([
+ {path: '/', component: MyCmp, name: 'HomeCmp'},
+ {path: '/:param', component: MyCmp, name: 'ParamCmp'}
+])
+class AppCmp {
+}
+
+
+export function main() {
+ return bootstrap(
+ AppCmp, [provide(APP_BASE_HREF, {useValue: '/angular2/examples/router/ts/on_activate'})]);
+}
diff --git a/modules/angular2/examples/router/ts/on_activate/on_activate_spec.ts b/modules/angular2/examples/router/ts/on_activate/on_activate_spec.ts
new file mode 100644
index 000000000000..d6e57e6fba79
--- /dev/null
+++ b/modules/angular2/examples/router/ts/on_activate/on_activate_spec.ts
@@ -0,0 +1,34 @@
+import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
+import {Promise} from 'angular2/src/facade/async';
+
+function waitForElement(selector) {
+ var EC = (protractor).ExpectedConditions;
+ // Waits for the element with id 'abc' to be present on the dom.
+ browser.wait(EC.presenceOf($(selector)), 20000);
+}
+
+describe('on activate example app', function() {
+ afterEach(verifyNoBrowserErrors);
+
+ var URL = 'angular2/examples/router/ts/on_activate/';
+
+ it('should update the text when navigating between routes', function() {
+ browser.get(URL);
+ waitForElement('my-cmp');
+
+ expect(element(by.css('my-cmp')).getText())
+ .toContain('routerOnActivate: Finished navigating from "null" to ""');
+
+ element(by.css('#param-link')).click();
+ waitForElement('my-cmp');
+
+ expect(element(by.css('my-cmp')).getText())
+ .toContain('routerOnActivate: Finished navigating from "" to "1"');
+
+ browser.navigate().back();
+ waitForElement('my-cmp');
+
+ expect(element(by.css('my-cmp')).getText())
+ .toContain('routerOnActivate: Finished navigating from "1" to ""');
+ });
+});
diff --git a/modules/angular2/examples/router/ts/on_deactivate/index.html b/modules/angular2/examples/router/ts/on_deactivate/index.html
new file mode 100644
index 000000000000..13439d3d5417
--- /dev/null
+++ b/modules/angular2/examples/router/ts/on_deactivate/index.html
@@ -0,0 +1,24 @@
+
+
+
+ Routing Reuse Lifecycle Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts b/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts
new file mode 100644
index 000000000000..036a0a47a27a
--- /dev/null
+++ b/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_example.ts
@@ -0,0 +1,63 @@
+import {Component, Injectable, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {
+ OnDeactivate,
+ ComponentInstruction,
+ RouteConfig,
+ ROUTER_DIRECTIVES,
+ APP_BASE_HREF
+} from 'angular2/router';
+
+
+@Injectable()
+class LogService {
+ logs: string[] = [];
+
+ addLog(message: string): void { this.logs.push(message); }
+}
+
+
+// #docregion routerOnDeactivate
+@Component({selector: 'my-cmp', template: `hello
`})
+class MyCmp implements OnDeactivate {
+ constructor(private logService: LogService) {}
+
+ routerOnDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
+ this.logService.addLog(
+ `Navigating from "${prev ? prev.urlPath : 'null'}" to "${next.urlPath}"`);
+ }
+}
+// #enddocregion
+
+
+@Component({
+ selector: 'example-app',
+ template: `
+ My App
+
+ Navigate Home |
+ Navigate with a Param
+
+
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+@RouteConfig([
+ {path: '/', component: MyCmp, name: 'HomeCmp'},
+ {path: '/:param', component: MyCmp, name: 'ParamCmp'}
+])
+class AppCmp {
+ constructor(public logService: LogService) {}
+}
+
+
+export function main() {
+ return bootstrap(AppCmp, [
+ provide(APP_BASE_HREF, {useValue: '/angular2/examples/router/ts/on_deactivate'}),
+ LogService
+ ]);
+}
diff --git a/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_spec.ts b/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_spec.ts
new file mode 100644
index 000000000000..5f48717d0cba
--- /dev/null
+++ b/modules/angular2/examples/router/ts/on_deactivate/on_deactivate_spec.ts
@@ -0,0 +1,32 @@
+import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
+import {Promise} from 'angular2/src/facade/async';
+
+function waitForElement(selector) {
+ var EC = (protractor).ExpectedConditions;
+ // Waits for the element with id 'abc' to be present on the dom.
+ browser.wait(EC.presenceOf($(selector)), 20000);
+}
+
+describe('on activate example app', function() {
+ afterEach(verifyNoBrowserErrors);
+
+ var URL = 'angular2/examples/router/ts/on_deactivate/';
+
+ it('should update the text when navigating between routes', function() {
+ browser.get(URL);
+ waitForElement('my-cmp');
+
+ expect(element(by.css('#log')).getText()).toEqual('Log:');
+
+ element(by.css('#param-link')).click();
+ waitForElement('my-cmp');
+
+ expect(element(by.css('#log')).getText()).toEqual('Log:\nNavigating from "" to "1"');
+
+ browser.navigate().back();
+ waitForElement('my-cmp');
+
+ expect(element(by.css('#log')).getText())
+ .toEqual('Log:\nNavigating from "" to "1"\nNavigating from "1" to ""');
+ });
+});
diff --git a/modules/angular2/examples/router/ts/reuse/index.html b/modules/angular2/examples/router/ts/reuse/index.html
new file mode 100644
index 000000000000..6db5c421c69b
--- /dev/null
+++ b/modules/angular2/examples/router/ts/reuse/index.html
@@ -0,0 +1,24 @@
+
+
+
+ Routing Reuse Lifecycle Example
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
diff --git a/modules/angular2/examples/router/ts/reuse/reuse_example.ts b/modules/angular2/examples/router/ts/reuse/reuse_example.ts
new file mode 100644
index 000000000000..4e34e31d791e
--- /dev/null
+++ b/modules/angular2/examples/router/ts/reuse/reuse_example.ts
@@ -0,0 +1,58 @@
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/bootstrap';
+import {
+ CanActivate,
+ RouteConfig,
+ ComponentInstruction,
+ ROUTER_DIRECTIVES,
+ APP_BASE_HREF,
+ CanReuse,
+ RouteParams,
+ OnReuse
+} from 'angular2/router';
+
+
+// #docregion reuseCmp
+@Component({
+ selector: 'my-cmp',
+ template: `
+ hello {{name}}!
+ message:
+ `
+})
+class MyCmp implements CanReuse,
+ OnReuse {
+ name: string;
+ constructor(params: RouteParams) { this.name = params.get('name') || 'NOBODY'; }
+
+ routerCanReuse(next: ComponentInstruction, prev: ComponentInstruction) { return true; }
+
+ routerOnReuse(next: ComponentInstruction, prev: ComponentInstruction) {
+ this.name = next.params['name'];
+ }
+}
+// #enddocregion
+
+
+@Component({
+ selector: 'example-app',
+ template: `
+ Say hi to...
+ Naomi |
+ Brad
+
+ `,
+ directives: [ROUTER_DIRECTIVES]
+})
+@RouteConfig([
+ {path: '/', component: MyCmp, name: 'HomeCmp'},
+ {path: '/:name', component: MyCmp, name: 'HomeCmp'}
+])
+class AppCmp {
+}
+
+
+export function main() {
+ return bootstrap(AppCmp,
+ [provide(APP_BASE_HREF, {useValue: '/angular2/examples/router/ts/reuse'})]);
+}
diff --git a/modules/angular2/examples/router/ts/reuse/reuse_spec.ts b/modules/angular2/examples/router/ts/reuse/reuse_spec.ts
new file mode 100644
index 000000000000..e1f24547227a
--- /dev/null
+++ b/modules/angular2/examples/router/ts/reuse/reuse_spec.ts
@@ -0,0 +1,36 @@
+import {verifyNoBrowserErrors} from 'angular2/src/testing/e2e_util';
+import {Promise} from 'angular2/src/facade/async';
+
+function waitForElement(selector) {
+ var EC = (protractor).ExpectedConditions;
+ // Waits for the element with id 'abc' to be present on the dom.
+ browser.wait(EC.presenceOf($(selector)), 20000);
+}
+
+describe('reuse example app', function() {
+
+ afterEach(verifyNoBrowserErrors);
+
+ var URL = 'angular2/examples/router/ts/reuse/';
+
+ it('should build a link which points to the detail page', function() {
+ browser.get(URL);
+ waitForElement('my-cmp');
+
+ element(by.css('#naomi-link')).click();
+ waitForElement('my-cmp');
+ expect(browser.getCurrentUrl()).toMatch(/\/naomi$/);
+
+ // type something into input
+ element(by.css('#message')).sendKeys('long time no see!');
+
+ // navigate to Brad
+ element(by.css('#brad-link')).click();
+ waitForElement('my-cmp');
+ expect(browser.getCurrentUrl()).toMatch(/\/brad$/);
+
+ // check that typed input is the same
+ expect(element(by.css('#message')).getAttribute('value')).toEqual('long time no see!');
+ });
+
+});
diff --git a/modules/angular2/examples/testing/ts/fake_async.ts b/modules/angular2/examples/testing/ts/fake_async.ts
new file mode 100644
index 000000000000..55bb766b91af
--- /dev/null
+++ b/modules/angular2/examples/testing/ts/fake_async.ts
@@ -0,0 +1,29 @@
+import {describe, it, fakeAsync, expect, tick, clearPendingTimers} from 'angular2/testing';
+
+// #docregion basic
+describe('this test', () => {
+ it('looks async but is synchronous', fakeAsync((): void => {
+ var flag = false;
+ setTimeout(() => { flag = true; }, 100);
+ expect(flag).toBe(false);
+ tick(50);
+ expect(flag).toBe(false);
+ tick(50);
+ expect(flag).toBe(true);
+ }));
+});
+// #enddocregion
+
+// #docregion pending
+describe('this test', () => {
+ it('aborts a timer', fakeAsync((): void => {
+ // This timer is scheduled but doesn't need to complete for the
+ // test to pass (maybe it's a timeout for some operation).
+ // Leaving it will cause the test to fail...
+ setTimeout(() => {}, 100);
+
+ // Unless we clean it up first.
+ clearPendingTimers();
+ }));
+});
+// #enddocregion
\ No newline at end of file
diff --git a/modules/angular2/examples/testing/ts/matchers.ts b/modules/angular2/examples/testing/ts/matchers.ts
new file mode 100644
index 000000000000..f0bf7d2818dc
--- /dev/null
+++ b/modules/angular2/examples/testing/ts/matchers.ts
@@ -0,0 +1,40 @@
+import {expect} from 'angular2/testing';
+
+var value: any;
+var element: any;
+var exception: any;
+
+abstract class OtherClass {}
+class SomeClass {}
+
+// #docregion toBePromise
+expect(value).toBePromise();
+// #enddocregion
+
+// #docregion toBeAnInstanceOf
+expect(value).toBeAnInstanceOf(SomeClass);
+// #enddocregion
+
+// #docregion toHaveText
+expect(element).toHaveText('Hello world!');
+// #enddocregion
+
+// #docregion toHaveCssClass
+expect(element).toHaveCssClass('current');
+// #enddocregion
+
+// #docregion toHaveCssStyle
+expect(element).toHaveCssStyle({width: '100px', height: 'auto'});
+// #enddocregion
+
+// #docregion toContainError
+expect(exception).toContainError('Failed to load');
+// #enddocregion
+
+// #docregion toThrowErrorWith
+expect(() => { throw 'Failed to load'; }).toThrowErrorWith('Failed to load');
+// #enddocregion
+
+// #docregion toImplement
+expect(SomeClass).toImplement(OtherClass);
+// #enddocregion
diff --git a/modules/angular2/examples/testing/ts/testing.ts b/modules/angular2/examples/testing/ts/testing.ts
new file mode 100644
index 000000000000..f46a2e00799d
--- /dev/null
+++ b/modules/angular2/examples/testing/ts/testing.ts
@@ -0,0 +1,90 @@
+import {
+ describe,
+ fdescribe,
+ xdescribe,
+ it,
+ fit,
+ xit,
+ beforeEach,
+ afterEach,
+ beforeEachProviders,
+ inject
+} from 'angular2/testing';
+import {provide} from 'angular2/core';
+
+var db: any;
+class MyService {}
+class MyMockService implements MyService {}
+
+// #docregion describeIt
+describe('some component', () => {
+ it('does something', () => {
+ // This is a test.
+ });
+});
+// #enddocregion
+
+// #docregion fdescribe
+fdescribe('some component', () => {
+ it('has a test', () => {
+ // This test will run.
+ });
+});
+describe('another component',
+ () => { it('also has a test', () => { throw 'This test will not run.'; }); });
+// #enddocregion
+
+// #docregion xdescribe
+xdescribe('some component', () => { it('has a test', () => {throw 'This test will not run.'}); });
+describe('another component', () => {
+ it('also has a test', () => {
+ // This test will run.
+ });
+});
+// #enddocregion
+
+// #docregion fit
+describe('some component', () => {
+ fit('has a test', () => {
+ // This test will run.
+ });
+ it('has another test', () => { throw 'This test will not run.'; });
+});
+// #enddocregion
+
+// #docregion xit
+describe('some component', () => {
+ xit('has a test', () => { throw 'This test will not run.'; });
+ it('has another test', () => {
+ // This test will run.
+ });
+});
+// #enddocregion
+
+// #docregion beforeEach
+describe('some component', () => {
+ beforeEach(() => { db.connect(); });
+ it('uses the db', () => {
+ // Database is connected.
+ });
+});
+// #enddocregion
+
+// #docregion beforeEachProviders
+describe('some component', () => {
+ beforeEachProviders(() => [provide(MyService, {useClass: MyMockService})]);
+ it('uses MyService', inject([MyService], (service) => {
+ // service is an instance of MyMockService.
+ }));
+});
+// #enddocregion
+
+// #docregion afterEach
+describe('some component', () => {
+ afterEach((done) => { db.reset().then((_) => done()); });
+ it('uses the db', () => {
+ // This test can leave the database in a dirty state.
+ // The afterEach will ensure it gets reset.
+ });
+});
+// #enddocregion
diff --git a/modules/angular2/examples/web_workers/ts/.gitkeep b/modules/angular2/examples/web_workers/ts/.gitkeep
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/modules/angular2/forms.ts b/modules/angular2/forms.ts
deleted file mode 100644
index 723f9ff1a36c..000000000000
--- a/modules/angular2/forms.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @module
- * @description
- * This module is used for handling user input, by defining and building a {@link ControlGroup} that
- * consists of
- * {@link Control} objects, and mapping them onto the DOM. {@link Control} objects can then be used
- * to read information
- * from the form DOM elements.
- *
- * This module is not included in the `angular2` module; you must import the forms module
- * explicitly.
- *
- */
-
-export {AbstractControl, Control, ControlGroup, ControlArray} from './src/forms/model';
-
-export {AbstractControlDirective} from './src/forms/directives/abstract_control_directive';
-export {Form} from './src/forms/directives/form_interface';
-export {ControlContainer} from './src/forms/directives/control_container';
-export {NgControlName} from './src/forms/directives/ng_control_name';
-export {NgFormControl} from './src/forms/directives/ng_form_control';
-export {NgModel} from './src/forms/directives/ng_model';
-export {NgControl} from './src/forms/directives/ng_control';
-export {NgControlGroup} from './src/forms/directives/ng_control_group';
-export {NgFormModel} from './src/forms/directives/ng_form_model';
-export {NgForm} from './src/forms/directives/ng_form';
-export {ControlValueAccessor} from './src/forms/directives/control_value_accessor';
-export {DefaultValueAccessor} from './src/forms/directives/default_value_accessor';
-export {CheckboxControlValueAccessor} from './src/forms/directives/checkbox_value_accessor';
-export {
- NgSelectOption,
- SelectControlValueAccessor
-} from './src/forms/directives/select_control_value_accessor';
-export {FORM_DIRECTIVES} from './src/forms/directives';
-export {Validators} from './src/forms/validators';
-export {NgValidator, NgRequiredValidator} from './src/forms/directives/validators';
-export {FormBuilder} from './src/forms/form_builder';
-
-import {FormBuilder} from './src/forms/form_builder';
-import {CONST_EXPR, Type} from './src/facade/lang';
-
-export const FORM_BINDINGS: List = CONST_EXPR([FormBuilder]);
diff --git a/modules/angular2/globals.d.ts b/modules/angular2/globals.d.ts
deleted file mode 100644
index 4e45e219f906..000000000000
--- a/modules/angular2/globals.d.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * This file contains declarations of global symbols we reference in our code
- */
-
-///
-declare var assert: any;
-declare type int = number;
-
-interface List extends Array {}
-
-// FIXME: K must be string!
-// FIXME: should have an index signature, `[k: string]: V;`
-interface StringMap {}
-
-interface BrowserNodeGlobal {
- Object: typeof Object;
- Array: typeof Array;
- Map: typeof Map;
- Set: typeof Set;
- Date: typeof Date;
- RegExp: typeof RegExp;
- JSON: typeof JSON;
- Math: typeof Math;
- assert(condition): void;
- Reflect: any;
- zone: Zone;
- getAngularTestability: Function;
- getAllAngularTestabilities: Function;
- setTimeout: Function;
- clearTimeout: Function;
- setInterval: Function;
- clearInterval: Function;
-}
diff --git a/modules/angular2/http.ts b/modules/angular2/http.ts
new file mode 100644
index 000000000000..5341e23191a0
--- /dev/null
+++ b/modules/angular2/http.ts
@@ -0,0 +1,300 @@
+/**
+ * @module
+ * @description
+ * The http module provides services to perform http requests. To get started, see the {@link Http}
+ * class.
+ */
+import {provide, Provider} from 'angular2/core';
+import {Http, Jsonp} from './src/http/http';
+import {XHRBackend, XHRConnection} from './src/http/backends/xhr_backend';
+import {JSONPBackend, JSONPBackend_, JSONPConnection} from './src/http/backends/jsonp_backend';
+import {BrowserXhr} from './src/http/backends/browser_xhr';
+import {BrowserJsonp} from './src/http/backends/browser_jsonp';
+import {BaseRequestOptions, RequestOptions} from './src/http/base_request_options';
+import {ConnectionBackend} from './src/http/interfaces';
+import {BaseResponseOptions, ResponseOptions} from './src/http/base_response_options';
+export {Request} from './src/http/static_request';
+export {Response} from './src/http/static_response';
+
+export {
+ RequestOptionsArgs,
+ ResponseOptionsArgs,
+ Connection,
+ ConnectionBackend
+} from './src/http/interfaces';
+
+export {BrowserXhr} from './src/http/backends/browser_xhr';
+export {BaseRequestOptions, RequestOptions} from './src/http/base_request_options';
+export {BaseResponseOptions, ResponseOptions} from './src/http/base_response_options';
+export {XHRBackend, XHRConnection} from './src/http/backends/xhr_backend';
+export {JSONPBackend, JSONPConnection} from './src/http/backends/jsonp_backend';
+export {Http, Jsonp} from './src/http/http';
+
+export {Headers} from './src/http/headers';
+
+export {ResponseType, ReadyState, RequestMethod} from './src/http/enums';
+export {URLSearchParams} from './src/http/url_search_params';
+
+/**
+ * Provides a basic set of injectables to use the {@link Http} service in any application.
+ *
+ * The `HTTP_PROVIDERS` should be included either in a component's injector,
+ * or in the root injector when bootstrapping an application.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/snj7Nv?p=preview))
+ *
+ * ```
+ * import {Component} from 'angular2/core';
+ * import {bootstrap} from 'angular2/platform/browser';
+ * import {NgFor} from 'angular2/common';
+ * import {HTTP_PROVIDERS, Http} from 'angular2/http';
+ *
+ * @Component({
+ * selector: 'app',
+ * providers: [HTTP_PROVIDERS],
+ * template: `
+ *
+ *
People
+ *
+ *
+ * {{person.name}}
+ *
+ *
+ *
+ * `,
+ * directives: [NgFor]
+ * })
+ * export class App {
+ * people: Object[];
+ * constructor(http:Http) {
+ * http.get('people.json').subscribe(res => {
+ * this.people = res.json();
+ * });
+ * }
+ * active:boolean = false;
+ * toggleActiveState() {
+ * this.active = !this.active;
+ * }
+ * }
+ *
+ * bootstrap(App)
+ * .catch(err => console.error(err));
+ * ```
+ *
+ * The primary public API included in `HTTP_PROVIDERS` is the {@link Http} class.
+ * However, other providers required by `Http` are included,
+ * which may be beneficial to override in certain cases.
+ *
+ * The providers included in `HTTP_PROVIDERS` include:
+ * * {@link Http}
+ * * {@link XHRBackend}
+ * * `BrowserXHR` - Private factory to create `XMLHttpRequest` instances
+ * * {@link RequestOptions} - Bound to {@link BaseRequestOptions} class
+ * * {@link ResponseOptions} - Bound to {@link BaseResponseOptions} class
+ *
+ * There may be cases where it makes sense to extend the base request options,
+ * such as to add a search string to be appended to all URLs.
+ * To accomplish this, a new provider for {@link RequestOptions} should
+ * be added in the same injector as `HTTP_PROVIDERS`.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/aCMEXi?p=preview))
+ *
+ * ```
+ * import {provide} from 'angular2/core';
+ * import {bootstrap} from 'angular2/platform/browser';
+ * import {HTTP_PROVIDERS, BaseRequestOptions, RequestOptions} from 'angular2/http';
+ *
+ * class MyOptions extends BaseRequestOptions {
+ * search: string = 'coreTeam=true';
+ * }
+ *
+ * bootstrap(App, [HTTP_PROVIDERS, provide(RequestOptions, {useClass: MyOptions})])
+ * .catch(err => console.error(err));
+ * ```
+ *
+ * Likewise, to use a mock backend for unit tests, the {@link XHRBackend}
+ * provider should be bound to {@link MockBackend}.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/7LWALD?p=preview))
+ *
+ * ```
+ * import {provide} from 'angular2/core';
+ * import {bootstrap} from 'angular2/platform/browser';
+ * import {HTTP_PROVIDERS, Http, Response, XHRBackend} from 'angular2/http';
+ * import {MockBackend} from 'angular2/http/testing';
+ *
+ * var people = [{name: 'Jeff'}, {name: 'Tobias'}];
+ *
+ * var injector = Injector.resolveAndCreate([
+ * HTTP_PROVIDERS,
+ * MockBackend,
+ * provide(XHRBackend, {useExisting: MockBackend})
+ * ]);
+ * var http = injector.get(Http);
+ * var backend = injector.get(MockBackend);
+ *
+ * // Listen for any new requests
+ * backend.connections.observer({
+ * next: connection => {
+ * var response = new Response({body: people});
+ * setTimeout(() => {
+ * // Send a response to the request
+ * connection.mockRespond(response);
+ * });
+ * });
+ *
+ * http.get('people.json').observer({
+ * next: res => {
+ * // Response came from mock backend
+ * console.log('first person', res.json()[0].name);
+ * }
+ * });
+ * ```
+ */
+export const HTTP_PROVIDERS: any[] = [
+ // TODO(pascal): use factory type annotations once supported in DI
+ // issue: https://github.com/angular/angular/issues/3183
+ provide(Http,
+ {
+ useFactory: (xhrBackend, requestOptions) => new Http(xhrBackend, requestOptions),
+ deps: [XHRBackend, RequestOptions]
+ }),
+ BrowserXhr,
+ provide(RequestOptions, {useClass: BaseRequestOptions}),
+ provide(ResponseOptions, {useClass: BaseResponseOptions}),
+ XHRBackend
+];
+
+/**
+ * See {@link HTTP_PROVIDERS} instead.
+ *
+ * @deprecated
+ */
+export const HTTP_BINDINGS = HTTP_PROVIDERS;
+
+/**
+ * Provides a basic set of providers to use the {@link Jsonp} service in any application.
+ *
+ * The `JSONP_PROVIDERS` should be included either in a component's injector,
+ * or in the root injector when bootstrapping an application.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/vmeN4F?p=preview))
+ *
+ * ```
+ * import {Component} from 'angular2/core';
+ * import {NgFor} from 'angular2/common';
+ * import {JSONP_PROVIDERS, Jsonp} from 'angular2/http';
+ *
+ * @Component({
+ * selector: 'app',
+ * providers: [JSONP_PROVIDERS],
+ * template: `
+ *
+ *
People
+ *
+ *
+ * {{person.name}}
+ *
+ *
+ *
+ * `,
+ * directives: [NgFor]
+ * })
+ * export class App {
+ * people: Array;
+ * constructor(jsonp:Jsonp) {
+ * jsonp.request('people.json').subscribe(res => {
+ * this.people = res.json();
+ * })
+ * }
+ * }
+ * ```
+ *
+ * The primary public API included in `JSONP_PROVIDERS` is the {@link Jsonp} class.
+ * However, other providers required by `Jsonp` are included,
+ * which may be beneficial to override in certain cases.
+ *
+ * The providers included in `JSONP_PROVIDERS` include:
+ * * {@link Jsonp}
+ * * {@link JSONPBackend}
+ * * `BrowserJsonp` - Private factory
+ * * {@link RequestOptions} - Bound to {@link BaseRequestOptions} class
+ * * {@link ResponseOptions} - Bound to {@link BaseResponseOptions} class
+ *
+ * There may be cases where it makes sense to extend the base request options,
+ * such as to add a search string to be appended to all URLs.
+ * To accomplish this, a new provider for {@link RequestOptions} should
+ * be added in the same injector as `JSONP_PROVIDERS`.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/TFug7x?p=preview))
+ *
+ * ```
+ * import {provide} from 'angular2/core';
+ * import {bootstrap} from 'angular2/platform/browser';
+ * import {JSONP_PROVIDERS, BaseRequestOptions, RequestOptions} from 'angular2/http';
+ *
+ * class MyOptions extends BaseRequestOptions {
+ * search: string = 'coreTeam=true';
+ * }
+ *
+ * bootstrap(App, [JSONP_PROVIDERS, provide(RequestOptions, {useClass: MyOptions})])
+ * .catch(err => console.error(err));
+ * ```
+ *
+ * Likewise, to use a mock backend for unit tests, the {@link JSONPBackend}
+ * provider should be bound to {@link MockBackend}.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/HDqZWL?p=preview))
+ *
+ * ```
+ * import {provide, Injector} from 'angular2/core';
+ * import {JSONP_PROVIDERS, Jsonp, Response, JSONPBackend} from 'angular2/http';
+ * import {MockBackend} from 'angular2/http/testing';
+ *
+ * var people = [{name: 'Jeff'}, {name: 'Tobias'}];
+ * var injector = Injector.resolveAndCreate([
+ * JSONP_PROVIDERS,
+ * MockBackend,
+ * provide(JSONPBackend, {useExisting: MockBackend})
+ * ]);
+ * var jsonp = injector.get(Jsonp);
+ * var backend = injector.get(MockBackend);
+ *
+ * // Listen for any new requests
+ * backend.connections.observer({
+ * next: connection => {
+ * var response = new Response({body: people});
+ * setTimeout(() => {
+ * // Send a response to the request
+ * connection.mockRespond(response);
+ * });
+ * });
+
+ * jsonp.get('people.json').observer({
+ * next: res => {
+ * // Response came from mock backend
+ * console.log('first person', res.json()[0].name);
+ * }
+ * });
+ * ```
+ */
+export const JSONP_PROVIDERS: any[] = [
+ // TODO(pascal): use factory type annotations once supported in DI
+ // issue: https://github.com/angular/angular/issues/3183
+ provide(Jsonp,
+ {
+ useFactory: (jsonpBackend, requestOptions) => new Jsonp(jsonpBackend, requestOptions),
+ deps: [JSONPBackend, RequestOptions]
+ }),
+ BrowserJsonp,
+ provide(RequestOptions, {useClass: BaseRequestOptions}),
+ provide(ResponseOptions, {useClass: BaseResponseOptions}),
+ provide(JSONPBackend, {useClass: JSONPBackend_})
+];
+
+/**
+ * See {@link JSONP_PROVIDERS} instead.
+ *
+ * @deprecated
+ */
+export const JSON_BINDINGS = JSONP_PROVIDERS;
diff --git a/modules/angular2/http/testing.ts b/modules/angular2/http/testing.ts
new file mode 100644
index 000000000000..4b0e8a88c3fd
--- /dev/null
+++ b/modules/angular2/http/testing.ts
@@ -0,0 +1 @@
+export * from 'angular2/src/http/backends/mock_backend';
\ No newline at end of file
diff --git a/modules/angular2/instrumentation.ts b/modules/angular2/instrumentation.ts
new file mode 100644
index 000000000000..67049babaf8e
--- /dev/null
+++ b/modules/angular2/instrumentation.ts
@@ -0,0 +1,7 @@
+export {
+ wtfCreateScope,
+ wtfLeave,
+ wtfStartTimeRange,
+ wtfEndTimeRange,
+ WtfScopeFn
+} from './src/core/profile/profile';
diff --git a/modules/angular2/manual_typings/globals-es6.d.ts b/modules/angular2/manual_typings/globals-es6.d.ts
new file mode 100644
index 000000000000..703f7de00966
--- /dev/null
+++ b/modules/angular2/manual_typings/globals-es6.d.ts
@@ -0,0 +1,36 @@
+/**
+ * Declarations angular depends on for compilation to ES6.
+ * This file is also used to propagate our transitive typings
+ * to users.
+ */
+
+///
+///
+
+// TODO: ideally the node.d.ts reference should be scoped only for files that need and not to all
+// the code including client code
+///
+
+declare var assert: any;
+
+
+interface BrowserNodeGlobal {
+ Object: typeof Object;
+ Array: typeof Array;
+ Map: typeof Map;
+ Set: typeof Set;
+ Date: typeof Date;
+ RegExp: typeof RegExp;
+ JSON: typeof JSON;
+ Math: typeof Math;
+ assert(condition: any): void;
+ Reflect: any;
+ zone: Zone;
+ getAngularTestability: Function;
+ getAllAngularTestabilities: Function;
+ frameworkStabilizers: Array;
+ setTimeout: Function;
+ clearTimeout: Function;
+ setInterval: Function;
+ clearInterval: Function;
+}
diff --git a/modules/angular2/manual_typings/globals.d.ts b/modules/angular2/manual_typings/globals.d.ts
new file mode 100644
index 000000000000..164d17e7a6ba
--- /dev/null
+++ b/modules/angular2/manual_typings/globals.d.ts
@@ -0,0 +1,7 @@
+/**
+ * Declarations angular depends on for compilation to ES6.
+ * This file is also used to propagate our transitive typings
+ * to users.
+ */
+///
+///
diff --git a/modules/angular2/metadata.dart b/modules/angular2/metadata.dart
deleted file mode 100644
index 81484884f2f0..000000000000
--- a/modules/angular2/metadata.dart
+++ /dev/null
@@ -1,4 +0,0 @@
-library angular2.metadata;
-
-export 'package:angular2/src/core/metadata.dart';
-export 'package:angular2/src/core/compiler/interfaces.dart';
diff --git a/modules/angular2/metadata.ts b/modules/angular2/metadata.ts
deleted file mode 100644
index 7223a51b10e1..000000000000
--- a/modules/angular2/metadata.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @module
- * @description
- *
- * Annotations provide the additional information that Angular requires in order to run your
- * application. This module
- * contains {@link ComponentMetadata}, {@link DirectiveMetadata}, and {@link ViewMetadata}
- * annotations, as well as
- * the {@link Host} annotation that is used by Angular to resolve dependencies.
- *
- */
-
-export {
- ComponentMetadata,
- DirectiveMetadata,
- PipeMetadata,
- LifecycleEvent,
- ViewMetadata,
- ViewEncapsulation,
- QueryMetadata,
- AttributeMetadata,
- Attribute,
- AttributeFactory,
- Component,
- ComponentDecorator,
- ComponentFactory,
- Directive,
- DirectiveDecorator,
- DirectiveFactory,
- View,
- ViewDecorator,
- ViewFactory,
- Query,
- QueryFactory,
- ViewQuery,
- Pipe,
- PipeFactory
-} from './src/core/metadata';
-
-export {
- OnAllChangesDone,
- OnChange,
- OnDestroy,
- OnInit,
- OnCheck
-} from './src/core/compiler/interfaces';
-
-export {Class, ClassDefinition, TypeDecorator} from './src/util/decorators';
diff --git a/modules/angular2/mock.ts b/modules/angular2/mock.ts
deleted file mode 100644
index 4d186a45766d..000000000000
--- a/modules/angular2/mock.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './src/mock/mock_location_strategy';
-export {LocationStrategy} from './src/router/location_strategy';
-
-export {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
-export {MockXHR} from 'angular2/src/render/xhr_mock';
diff --git a/modules/angular2/package.json b/modules/angular2/package.json
index fa1a6b8ba929..e4f2d5afd591 100644
--- a/modules/angular2/package.json
+++ b/modules/angular2/package.json
@@ -7,19 +7,12 @@
"contributors": <%= JSON.stringify(packageJson.contributors) %>,
"license": "<%= packageJson.license %>",
"repository": <%= JSON.stringify(packageJson.repository) %>,
- "dependencies": {
- "traceur": "<%= packageJson.dependencies.traceur %>",
+ "devDependencies": <%= JSON.stringify(packageJson.defaultDevDependencies) %>,
+ "peerDependencies": {
+ "es6-promise": "<%= packageJson.dependencies['es6-promise'] %>",
+ "es6-shim": "<%= packageJson.dependencies['es6-shim'] %>",
"reflect-metadata": "<%= packageJson.dependencies['reflect-metadata'] %>",
- "rtts_assert": "<%= packageJson.version %>",
- "rx": "<%= packageJson.dependencies['rx'] %>",
+ "rxjs": "<%= packageJson.dependencies['rxjs'] %>",
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
- },
- "devDependencies": <%= JSON.stringify(packageJson.defaultDevDependencies) %>,
- "typescript": {
- "definitions": [
- "bundles/typings/angular2/angular2.d.ts",
- "bundles/typings/angular2/http.d.ts",
- "bundles/typings/angular2/router.d.ts"
- ]
}
}
diff --git a/modules/angular2/pipes.ts b/modules/angular2/pipes.ts
deleted file mode 100644
index 5bf87b165beb..000000000000
--- a/modules/angular2/pipes.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * @module
- * @description
- * This module provides advanced support for extending change detection.
- */
-
-export {UpperCasePipe} from './src/pipes/uppercase_pipe';
-export {LowerCasePipe} from './src/pipes/lowercase_pipe';
-export {AsyncPipe} from './src/pipes/async_pipe';
-export {JsonPipe} from './src/pipes/json_pipe';
-export {DatePipe} from './src/pipes/date_pipe';
-export {DecimalPipe, PercentPipe, CurrencyPipe} from './src/pipes/number_pipe';
-export {LimitToPipe} from './src/pipes/limit_to_pipe';
-export {DEFAULT_PIPES_TOKEN, DEFAULT_PIPES} from './src/pipes/default_pipes';
diff --git a/modules/angular2/platform/browser.ts b/modules/angular2/platform/browser.ts
new file mode 100644
index 000000000000..741f1f65e98b
--- /dev/null
+++ b/modules/angular2/platform/browser.ts
@@ -0,0 +1,112 @@
+export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
+export {
+ BROWSER_PROVIDERS,
+ ELEMENT_PROBE_BINDINGS,
+ ELEMENT_PROBE_PROVIDERS,
+ inspectNativeElement,
+ BrowserDomAdapter,
+ By,
+ Title,
+ DOCUMENT,
+ enableDebugTools,
+ disableDebugTools
+} from 'angular2/src/platform/browser_common';
+
+import {Type, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
+import {Promise} from 'angular2/src/facade/promise';
+import {
+ BROWSER_PROVIDERS,
+ BROWSER_APP_COMMON_PROVIDERS
+} from 'angular2/src/platform/browser_common';
+import {COMPILER_PROVIDERS} from 'angular2/compiler';
+import {ComponentRef, platform, reflector} from 'angular2/core';
+import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities';
+import {XHRImpl} from "angular2/src/platform/browser/xhr_impl";
+import {XHR} from 'angular2/compiler';
+import {Provider} from 'angular2/src/core/di';
+
+/**
+ * An array of providers that should be passed into `application()` when bootstrapping a component.
+ */
+export const BROWSER_APP_PROVIDERS: Array = CONST_EXPR([
+ BROWSER_APP_COMMON_PROVIDERS,
+ COMPILER_PROVIDERS,
+ new Provider(XHR, {useClass: XHRImpl}),
+]);
+
+/**
+ * Bootstrapping for Angular applications.
+ *
+ * You instantiate an Angular application by explicitly specifying a component to use
+ * as the root component for your application via the `bootstrap()` method.
+ *
+ * ## Simple Example
+ *
+ * Assuming this `index.html`:
+ *
+ * ```html
+ *
+ *
+ *
+ * loading...
+ *
+ *
+ * ```
+ *
+ * An application is bootstrapped inside an existing browser DOM, typically `index.html`.
+ * Unlike Angular 1, Angular 2 does not compile/process providers in `index.html`. This is
+ * mainly for security reasons, as well as architectural changes in Angular 2. This means
+ * that `index.html` can safely be processed using server-side technologies such as
+ * providers. Bindings can thus use double-curly `{{ syntax }}` without collision from
+ * Angular 2 component double-curly `{{ syntax }}`.
+ *
+ * We can use this script code:
+ *
+ * {@example core/ts/bootstrap/bootstrap.ts region='bootstrap'}
+ *
+ * When the app developer invokes `bootstrap()` with the root component `MyApp` as its
+ * argument, Angular performs the following tasks:
+ *
+ * 1. It uses the component's `selector` property to locate the DOM element which needs
+ * to be upgraded into the angular component.
+ * 2. It creates a new child injector (from the platform injector). Optionally, you can
+ * also override the injector configuration for an app by invoking `bootstrap` with the
+ * `componentInjectableBindings` argument.
+ * 3. It creates a new `Zone` and connects it to the angular application's change detection
+ * domain instance.
+ * 4. It creates an emulated or shadow DOM on the selected component's host element and loads the
+ * template into it.
+ * 5. It instantiates the specified component.
+ * 6. Finally, Angular performs change detection to apply the initial data providers for the
+ * application.
+ *
+ *
+ * ## Bootstrapping Multiple Applications
+ *
+ * When working within a browser window, there are many singleton resources: cookies, title,
+ * location, and others. Angular services that represent these resources must likewise be
+ * shared across all Angular applications that occupy the same browser window. For this
+ * reason, Angular creates exactly one global platform object which stores all shared
+ * services, and each angular application injector has the platform injector as its parent.
+ *
+ * Each application has its own private injector as well. When there are multiple
+ * applications on a page, Angular treats each application injector's services as private
+ * to that application.
+ *
+ * ## API
+ *
+ * - `appComponentType`: The root component which should act as the application. This is
+ * a reference to a `Type` which is annotated with `@Component(...)`.
+ * - `customProviders`: An additional set of providers that can be added to the
+ * app injector to override default injection behavior.
+ *
+ * Returns a `Promise` of {@link ComponentRef}.
+ */
+export function bootstrap(
+ appComponentType: Type,
+ customProviders?: Array ): Promise {
+ reflector.reflectionCapabilities = new ReflectionCapabilities();
+ let appProviders =
+ isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
+ return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
+}
diff --git a/modules/angular2/platform/browser_static.ts b/modules/angular2/platform/browser_static.ts
new file mode 100644
index 000000000000..732b08bf1156
--- /dev/null
+++ b/modules/angular2/platform/browser_static.ts
@@ -0,0 +1,43 @@
+export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
+export {
+ BROWSER_PROVIDERS,
+ ELEMENT_PROBE_BINDINGS,
+ ELEMENT_PROBE_PROVIDERS,
+ inspectNativeElement,
+ BrowserDomAdapter,
+ By,
+ Title,
+ enableDebugTools,
+ disableDebugTools
+} from 'angular2/src/platform/browser_common';
+
+import {Type, isPresent} from 'angular2/src/facade/lang';
+import {Promise} from 'angular2/src/facade/promise';
+import {
+ BROWSER_PROVIDERS,
+ BROWSER_APP_COMMON_PROVIDERS
+} from 'angular2/src/platform/browser_common';
+import {ComponentRef, platform} from 'angular2/core';
+
+/**
+ * An array of providers that should be passed into `application()` when bootstrapping a component
+ * when all templates
+ * have been precompiled offline.
+ */
+export const BROWSER_APP_PROVIDERS: Array =
+ BROWSER_APP_COMMON_PROVIDERS;
+
+/**
+ * See {@link bootstrap} for more information.
+ */
+export function bootstrapStatic(appComponentType: Type,
+ customProviders?: Array ,
+ initReflector?: Function): Promise {
+ if (isPresent(initReflector)) {
+ initReflector();
+ }
+
+ let appProviders =
+ isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
+ return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
+}
diff --git a/modules/angular2/platform/common_dom.ts b/modules/angular2/platform/common_dom.ts
new file mode 100644
index 000000000000..c74e5ee84bf6
--- /dev/null
+++ b/modules/angular2/platform/common_dom.ts
@@ -0,0 +1,15 @@
+/**
+ * This is a set of classes and objects that can be used both in the browser and on the server.
+ */
+export {DOM, setRootDomAdapter, DomAdapter} from 'angular2/src/platform/dom/dom_adapter';
+export {DomRenderer} from 'angular2/src/platform/dom/dom_renderer';
+export {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
+export {SharedStylesHost, DomSharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host';
+export {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
+export {
+ EVENT_MANAGER_PLUGINS,
+ EventManager,
+ EventManagerPlugin
+} from 'angular2/src/platform/dom/events/event_manager';
+export * from 'angular2/src/platform/dom/debug/by';
+export * from 'angular2/src/platform/dom/debug/debug_element_view_listener';
\ No newline at end of file
diff --git a/modules/angular2/platform/server.dart b/modules/angular2/platform/server.dart
new file mode 100644
index 000000000000..61ae1b680956
--- /dev/null
+++ b/modules/angular2/platform/server.dart
@@ -0,0 +1,2 @@
+// TODO: vsavkin add SERVER_PROVIDERS and SERVER_APP_PROVIDERS
+export 'package:angular2/src/platform/server/html_adapter.dart';
diff --git a/modules/angular2/platform/server.ts b/modules/angular2/platform/server.ts
new file mode 100644
index 000000000000..9270dfbef16e
--- /dev/null
+++ b/modules/angular2/platform/server.ts
@@ -0,0 +1,2 @@
+// TODO: vsavkin add SERVER_PROVIDERS and SERVER_APP_PROVIDERS
+export {Parse5DomAdapter} from 'angular2/src/platform/server/parse5_adapter';
\ No newline at end of file
diff --git a/modules/angular2/platform/testing/browser.ts b/modules/angular2/platform/testing/browser.ts
new file mode 100644
index 000000000000..8aeb60f7cdba
--- /dev/null
+++ b/modules/angular2/platform/testing/browser.ts
@@ -0,0 +1,21 @@
+import {
+ TEST_BROWSER_STATIC_PLATFORM_PROVIDERS,
+ ADDITIONAL_TEST_BROWSER_PROVIDERS
+} from 'angular2/platform/testing/browser_static';
+
+import {BROWSER_APP_PROVIDERS} from 'angular2/platform/browser';
+
+
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+/**
+ * Default patform providers for testing.
+ */
+export const TEST_BROWSER_PLATFORM_PROVIDERS: Array =
+ CONST_EXPR([TEST_BROWSER_STATIC_PLATFORM_PROVIDERS]);
+
+/**
+ * Default application providers for testing.
+ */
+export const TEST_BROWSER_APPLICATION_PROVIDERS: Array =
+ CONST_EXPR([BROWSER_APP_PROVIDERS, ADDITIONAL_TEST_BROWSER_PROVIDERS]);
diff --git a/modules/angular2/platform/testing/browser_static.ts b/modules/angular2/platform/testing/browser_static.ts
new file mode 100644
index 000000000000..1f4192134e0e
--- /dev/null
+++ b/modules/angular2/platform/testing/browser_static.ts
@@ -0,0 +1,69 @@
+import {
+ APP_ID,
+ DirectiveResolver,
+ NgZone,
+ Provider,
+ ViewResolver,
+ PLATFORM_COMMON_PROVIDERS,
+ PLATFORM_INITIALIZER
+} from 'angular2/core';
+import {BROWSER_APP_COMMON_PROVIDERS} from 'angular2/src/platform/browser_common';
+import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter';
+
+import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
+import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
+import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
+import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
+import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
+import {LocationStrategy} from 'angular2/src/router/location_strategy';
+import {MockNgZone} from 'angular2/src/mock/ng_zone_mock';
+
+import {XHRImpl} from "angular2/src/platform/browser/xhr_impl";
+import {XHR} from 'angular2/compiler';
+
+import {TestComponentBuilder} from 'angular2/src/testing/test_component_builder';
+
+import {BrowserDetection} from 'angular2/src/testing/utils';
+
+import {ELEMENT_PROBE_PROVIDERS} from 'angular2/platform/common_dom';
+
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+import {Log} from 'angular2/src/testing/utils';
+
+function initBrowserTests() {
+ BrowserDomAdapter.makeCurrent();
+ BrowserDetection.setup();
+}
+
+/**
+ * Default patform providers for testing without a compiler.
+ */
+export const TEST_BROWSER_STATIC_PLATFORM_PROVIDERS: Array =
+ CONST_EXPR([
+ PLATFORM_COMMON_PROVIDERS,
+ new Provider(PLATFORM_INITIALIZER, {useValue: initBrowserTests, multi: true})
+ ]);
+
+export const ADDITIONAL_TEST_BROWSER_PROVIDERS: Array =
+ CONST_EXPR([
+ new Provider(APP_ID, {useValue: 'a'}),
+ ELEMENT_PROBE_PROVIDERS,
+ new Provider(DirectiveResolver, {useClass: MockDirectiveResolver}),
+ new Provider(ViewResolver, {useClass: MockViewResolver}),
+ Log,
+ TestComponentBuilder,
+ new Provider(NgZone, {useClass: MockNgZone}),
+ new Provider(LocationStrategy, {useClass: MockLocationStrategy}),
+ new Provider(AnimationBuilder, {useClass: MockAnimationBuilder}),
+ ]);
+
+/**
+ * Default application providers for testing without a compiler.
+ */
+export const TEST_BROWSER_STATIC_APPLICATION_PROVIDERS: Array =
+ CONST_EXPR([
+ BROWSER_APP_COMMON_PROVIDERS,
+ new Provider(XHR, {useClass: XHRImpl}),
+ ADDITIONAL_TEST_BROWSER_PROVIDERS
+ ]);
diff --git a/modules/angular2/platform/testing/server.dart b/modules/angular2/platform/testing/server.dart
new file mode 100644
index 000000000000..a46a40721fc6
--- /dev/null
+++ b/modules/angular2/platform/testing/server.dart
@@ -0,0 +1 @@
+// Intentionally blank, the Parse5Adapater bindings for JavaScript don't apply.
diff --git a/modules/angular2/platform/testing/server.ts b/modules/angular2/platform/testing/server.ts
new file mode 100644
index 000000000000..47156c14d46c
--- /dev/null
+++ b/modules/angular2/platform/testing/server.ts
@@ -0,0 +1,90 @@
+import {
+ APP_ID,
+ DirectiveResolver,
+ NgZone,
+ Provider,
+ ViewResolver,
+ PLATFORM_COMMON_PROVIDERS,
+ PLATFORM_INITIALIZER,
+ APPLICATION_COMMON_PROVIDERS,
+ Renderer
+} from 'angular2/core';
+import {Parse5DomAdapter} from 'angular2/src/platform/server/parse5_adapter';
+
+import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
+import {MockAnimationBuilder} from 'angular2/src/mock/animation_builder_mock';
+import {MockDirectiveResolver} from 'angular2/src/mock/directive_resolver_mock';
+import {MockViewResolver} from 'angular2/src/mock/view_resolver_mock';
+import {MockLocationStrategy} from 'angular2/src/mock/mock_location_strategy';
+import {LocationStrategy} from 'angular2/src/router/location_strategy';
+import {MockNgZone} from 'angular2/src/mock/ng_zone_mock';
+
+import {TestComponentBuilder} from 'angular2/src/testing/test_component_builder';
+import {XHR} from 'angular2/src/compiler/xhr';
+import {BrowserDetection} from 'angular2/src/testing/utils';
+
+import {COMPILER_PROVIDERS} from 'angular2/src/compiler/compiler';
+import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
+import {DOM} from 'angular2/src/platform/dom/dom_adapter';
+import {RootRenderer} from 'angular2/src/core/render/api';
+import {DomRootRenderer, DomRootRenderer_} from 'angular2/src/platform/dom/dom_renderer';
+import {DomSharedStylesHost} from 'angular2/src/platform/dom/shared_styles_host';
+
+import {
+ EventManager,
+ EVENT_MANAGER_PLUGINS,
+ ELEMENT_PROBE_PROVIDERS
+} from 'angular2/platform/common_dom';
+import {DomEventsPlugin} from 'angular2/src/platform/dom/events/dom_events';
+
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+import {Log} from 'angular2/src/testing/utils';
+
+function initServerTests() {
+ Parse5DomAdapter.makeCurrent();
+ BrowserDetection.setup();
+}
+
+/**
+ * Default patform providers for testing.
+ */
+export const TEST_SERVER_PLATFORM_PROVIDERS: Array = CONST_EXPR([
+ PLATFORM_COMMON_PROVIDERS,
+ new Provider(PLATFORM_INITIALIZER, {useValue: initServerTests, multi: true})
+]);
+
+function appDoc() {
+ try {
+ return DOM.defaultDoc();
+ } catch (e) {
+ return null;
+ }
+}
+
+/**
+ * Default application providers for testing.
+ */
+export const TEST_SERVER_APPLICATION_PROVIDERS: Array =
+ CONST_EXPR([
+ // TODO(julie): when angular2/platform/server is available, use that instead of making our own
+ // list here.
+ APPLICATION_COMMON_PROVIDERS,
+ COMPILER_PROVIDERS,
+ new Provider(DOCUMENT, {useFactory: appDoc}),
+ new Provider(DomRootRenderer, {useClass: DomRootRenderer_}),
+ new Provider(RootRenderer, {useExisting: DomRootRenderer}),
+ EventManager,
+ new Provider(EVENT_MANAGER_PLUGINS, {useClass: DomEventsPlugin, multi: true}),
+ new Provider(XHR, {useClass: XHR}),
+ new Provider(APP_ID, {useValue: 'a'}),
+ DomSharedStylesHost,
+ ELEMENT_PROBE_PROVIDERS,
+ new Provider(DirectiveResolver, {useClass: MockDirectiveResolver}),
+ new Provider(ViewResolver, {useClass: MockViewResolver}),
+ Log,
+ TestComponentBuilder,
+ new Provider(NgZone, {useClass: MockNgZone}),
+ new Provider(LocationStrategy, {useClass: MockLocationStrategy}),
+ new Provider(AnimationBuilder, {useClass: MockAnimationBuilder}),
+ ]);
diff --git a/modules/angular2/platform/worker_app.dart b/modules/angular2/platform/worker_app.dart
new file mode 100644
index 000000000000..e2ff19ea65c8
--- /dev/null
+++ b/modules/angular2/platform/worker_app.dart
@@ -0,0 +1,14 @@
+library angular2.platform.worker_app;
+
+export "package:angular2/src/platform/worker_app_common.dart"
+ show WORKER_APP_PLATFORM, WORKER_APP_APPLICATION_COMMON;
+export "package:angular2/src/core/angular_entrypoint.dart"
+ show AngularEntrypoint;
+export "package:angular2/src/platform/worker_app.dart"
+ show WORKER_APP_APPLICATION, RENDER_SEND_PORT;
+export 'package:angular2/src/web_workers/shared/client_message_broker.dart'
+ show ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments;
+export 'package:angular2/src/web_workers/shared/service_message_broker.dart'
+ show ReceivedMessage, ServiceMessageBroker, ServiceMessageBrokerFactory;
+export 'package:angular2/src/web_workers/shared/serializer.dart' show PRIMITIVE;
+export 'package:angular2/src/web_workers/shared/message_bus.dart';
diff --git a/modules/angular2/platform/worker_app.ts b/modules/angular2/platform/worker_app.ts
new file mode 100644
index 000000000000..7e6957be967e
--- /dev/null
+++ b/modules/angular2/platform/worker_app.ts
@@ -0,0 +1,19 @@
+export {
+ WORKER_APP_PLATFORM,
+ WORKER_APP_APPLICATION_COMMON
+} from 'angular2/src/platform/worker_app_common';
+export {WORKER_APP_APPLICATION} from 'angular2/src/platform/worker_app';
+export {
+ ClientMessageBroker,
+ ClientMessageBrokerFactory,
+ FnArg,
+ UiArguments
+} from '../src/web_workers/shared/client_message_broker';
+export {
+ ReceivedMessage,
+ ServiceMessageBroker,
+ ServiceMessageBrokerFactory
+} from '../src/web_workers/shared/service_message_broker';
+export {PRIMITIVE} from '../src/web_workers/shared/serializer';
+export * from '../src/web_workers/shared/message_bus';
+export {AngularEntrypoint} from 'angular2/src/core/angular_entrypoint';
diff --git a/modules/angular2/platform/worker_render.dart b/modules/angular2/platform/worker_render.dart
new file mode 100644
index 000000000000..aafab6599dfe
--- /dev/null
+++ b/modules/angular2/platform/worker_render.dart
@@ -0,0 +1,24 @@
+library angular2.platform.worker_render;
+
+export 'package:angular2/src/platform/worker_render_common.dart'
+ show
+ WORKER_SCRIPT,
+ WORKER_RENDER_PLATFORM,
+ WORKER_RENDER_APPLICATION_COMMON,
+ initializeGenericWorkerRenderer;
+
+export 'package:angular2/src/platform/worker_render.dart'
+ show WORKER_RENDER_APPLICATION, initIsolate, WebWorkerInstance;
+
+export '../src/web_workers/shared/client_message_broker.dart'
+ show ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments;
+
+export '../src/web_workers/shared/service_message_broker.dart'
+ show ReceivedMessage, ServiceMessageBroker, ServiceMessageBrokerFactory;
+
+export '../src/web_workers/shared/serializer.dart' show PRIMITIVE;
+export '../src/web_workers/shared/message_bus.dart';
+
+import 'package:angular2/src/platform/worker_render_common.dart';
+
+const WORKER_RENDER_APP = WORKER_RENDER_APPLICATION_COMMON;
diff --git a/modules/angular2/platform/worker_render.ts b/modules/angular2/platform/worker_render.ts
new file mode 100644
index 000000000000..a601dbf253eb
--- /dev/null
+++ b/modules/angular2/platform/worker_render.ts
@@ -0,0 +1,26 @@
+export {
+ WORKER_SCRIPT,
+ WORKER_RENDER_PLATFORM,
+ initializeGenericWorkerRenderer,
+ WORKER_RENDER_APPLICATION_COMMON
+} from 'angular2/src/platform/worker_render_common';
+export {WORKER_RENDER_APPLICATION, WebWorkerInstance} from 'angular2/src/platform/worker_render';
+export {
+ ClientMessageBroker,
+ ClientMessageBrokerFactory,
+ FnArg,
+ UiArguments
+} from '../src/web_workers/shared/client_message_broker';
+export {
+ ReceivedMessage,
+ ServiceMessageBroker,
+ ServiceMessageBrokerFactory
+} from '../src/web_workers/shared/service_message_broker';
+export {PRIMITIVE} from '../src/web_workers/shared/serializer';
+export * from '../src/web_workers/shared/message_bus';
+import {WORKER_RENDER_APPLICATION} from 'angular2/src/platform/worker_render';
+
+/**
+ * @deprecated Use WORKER_RENDER_APPLICATION
+ */
+export const WORKER_RENDER_APP = WORKER_RENDER_APPLICATION;
diff --git a/modules/angular2/profile.ts b/modules/angular2/profile.ts
deleted file mode 100644
index f1ad6ec76809..000000000000
--- a/modules/angular2/profile.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export {
- wtfCreateScope,
- wtfLeave,
- wtfStartTimeRange,
- wtfEndTimeRange,
- WtfScopeFn
-} from './src/profile/profile';
diff --git a/modules/angular2/pubspec.yaml b/modules/angular2/pubspec.yaml
index 568a544c1b7d..a5243e3025dd 100644
--- a/modules/angular2/pubspec.yaml
+++ b/modules/angular2/pubspec.yaml
@@ -9,19 +9,22 @@ homepage: <%= packageJson.homepage %>
environment:
sdk: '>=1.10.0 <2.0.0'
dependencies:
- analyzer: '>=0.24.4 <0.26.0'
+ analyzer: '>=0.24.4 <0.28.0'
barback: '^0.15.2+2'
- code_transformers: '^0.2.8'
dart_style: '>=0.1.8 <0.3.0'
+ glob: '^1.0.0'
html: '^0.12.0'
intl: '^0.12.4'
logging: '>=0.9.0 <0.12.0'
observe: '^0.13.1'
+ protobuf: '^0.5.0'
quiver: '^0.21.4'
source_span: '^1.0.0'
stack_trace: '^1.1.1'
dev_dependencies:
- guinness: '^0.1.17'
+ code_transformers: '>=0.2.9+4 <0.4.0'
+ guinness: '^0.1.18'
+ test: '^0.12.6'
transformers:
- angular2
- $dart2js:
diff --git a/modules/angular2/render.ts b/modules/angular2/render.ts
deleted file mode 100644
index f0b3f69e8e35..000000000000
--- a/modules/angular2/render.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * @module
- * @description
- * This module provides advanced support for extending dom strategy.
- */
-
-export {
- RenderDirectiveMetadata,
- DomRenderer,
- RenderEventDispatcher,
- Renderer,
- RenderElementRef,
- RenderViewRef,
- RenderProtoViewRef,
- RenderFragmentRef,
- RenderViewWithFragments,
- ViewDefinition,
- DOCUMENT,
- APP_ID,
- DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES,
- MAX_IN_MEMORY_ELEMENTS_PER_TEMPLATE
-} from './src/render/render';
diff --git a/modules/angular2/router.ts b/modules/angular2/router.ts
index e47435e654de..4cea18950a6a 100644
--- a/modules/angular2/router.ts
+++ b/modules/angular2/router.ts
@@ -4,53 +4,115 @@
* Maps application URLs into application states, to support deep-linking and navigation.
*/
-
-export {Router, RootRouter} from './src/router/router';
+export {Router} from './src/router/router';
export {RouterOutlet} from './src/router/router_outlet';
export {RouterLink} from './src/router/router_link';
-export {RouteParams} from './src/router/instruction';
-export {RouteRegistry} from './src/router/route_registry';
-export {LocationStrategy} from './src/router/location_strategy';
+export {RouteParams, RouteData} from './src/router/instruction';
+export {PlatformLocation} from './src/router/platform_location';
+export {RouteRegistry, ROUTER_PRIMARY_COMPONENT} from './src/router/route_registry';
+export {LocationStrategy, APP_BASE_HREF} from './src/router/location_strategy';
export {HashLocationStrategy} from './src/router/hash_location_strategy';
-export {HTML5LocationStrategy} from './src/router/html5_location_strategy';
-export {Location, APP_BASE_HREF} from './src/router/location';
-export {Pipeline} from './src/router/pipeline';
+export {PathLocationStrategy} from './src/router/path_location_strategy';
+export {Location} from './src/router/location';
export * from './src/router/route_config_decorator';
export * from './src/router/route_definition';
export {OnActivate, OnDeactivate, OnReuse, CanDeactivate, CanReuse} from './src/router/interfaces';
export {CanActivate} from './src/router/lifecycle_annotations';
export {Instruction, ComponentInstruction} from './src/router/instruction';
-export {Url} from './src/router/url_parser';
-export {OpaqueToken, Type} from 'angular2/angular2';
+export {OpaqueToken} from 'angular2/core';
+import {PlatformLocation} from './src/router/platform_location';
import {LocationStrategy} from './src/router/location_strategy';
-import {HTML5LocationStrategy} from './src/router/html5_location_strategy';
+import {PathLocationStrategy} from './src/router/path_location_strategy';
import {Router, RootRouter} from './src/router/router';
import {RouterOutlet} from './src/router/router_outlet';
import {RouterLink} from './src/router/router_link';
-import {RouteRegistry} from './src/router/route_registry';
-import {Pipeline} from './src/router/pipeline';
+import {RouteRegistry, ROUTER_PRIMARY_COMPONENT} from './src/router/route_registry';
import {Location} from './src/router/location';
-import {APP_COMPONENT} from './src/core/application_tokens';
-import {Binding} from './di';
+import {ApplicationRef, provide, OpaqueToken, Provider} from 'angular2/core';
import {CONST_EXPR} from './src/facade/lang';
-import {List} from './src/facade/collection';
+import {BaseException} from 'angular2/src/facade/exceptions';
-export const ROUTER_DIRECTIVES: List = CONST_EXPR([RouterOutlet, RouterLink]);
+/**
+ * A list of directives. To use the router directives like {@link RouterOutlet} and
+ * {@link RouterLink}, add this to your `directives` array in the {@link View} decorator of your
+ * component.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
+ *
+ * ```
+ * import {Component} from 'angular2/core';
+ * import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from 'angular2/router';
+ *
+ * @Component({directives: [ROUTER_DIRECTIVES]})
+ * @RouteConfig([
+ * {...},
+ * ])
+ * class AppCmp {
+ * // ...
+ * }
+ *
+ * bootstrap(AppCmp, [ROUTER_PROVIDERS]);
+ * ```
+ */
+export const ROUTER_DIRECTIVES: any[] = CONST_EXPR([RouterOutlet, RouterLink]);
-export const ROUTER_BINDINGS: List = CONST_EXPR([
+/**
+ * A list of {@link Provider}s. To use the router, you must add this to your application.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
+ *
+ * ```
+ * import {Component} from 'angular2/core';
+ * import {
+ * ROUTER_DIRECTIVES,
+ * ROUTER_PROVIDERS,
+ * RouteConfig
+ * } from 'angular2/router';
+ *
+ * @Component({directives: [ROUTER_DIRECTIVES]})
+ * @RouteConfig([
+ * {...},
+ * ])
+ * class AppCmp {
+ * // ...
+ * }
+ *
+ * bootstrap(AppCmp, [ROUTER_PROVIDERS]);
+ * ```
+ */
+export const ROUTER_PROVIDERS: any[] = CONST_EXPR([
RouteRegistry,
- Pipeline,
- CONST_EXPR(new Binding(LocationStrategy, {toClass: HTML5LocationStrategy})),
+ CONST_EXPR(new Provider(LocationStrategy, {useClass: PathLocationStrategy})),
+ PlatformLocation,
Location,
- CONST_EXPR(
- new Binding(Router,
- {
- toFactory: routerFactory,
- deps: CONST_EXPR([RouteRegistry, Pipeline, Location, APP_COMPONENT])
- }))
+ CONST_EXPR(new Provider(
+ Router,
+ {
+ useFactory: routerFactory,
+ deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT, ApplicationRef])
+ })),
+ CONST_EXPR(new Provider(
+ ROUTER_PRIMARY_COMPONENT,
+ {useFactory: routerPrimaryComponentFactory, deps: CONST_EXPR([ApplicationRef])}))
]);
-function routerFactory(registry, pipeline, location, appRoot) {
- return new RootRouter(registry, pipeline, location, appRoot);
+/**
+ * Use {@link ROUTER_PROVIDERS} instead.
+ *
+ * @deprecated
+ */
+export const ROUTER_BINDINGS = ROUTER_PROVIDERS;
+
+function routerFactory(registry, location, primaryComponent, appRef) {
+ var rootRouter = new RootRouter(registry, location, primaryComponent);
+ appRef.registerDisposeListener(() => rootRouter.dispose());
+ return rootRouter;
+}
+
+function routerPrimaryComponentFactory(app) {
+ if (app.componentTypes.length == 0) {
+ throw new BaseException("Bootstrap at least one component before injecting Router.");
+ }
+ return app.componentTypes[0];
}
diff --git a/modules/angular2/router/router_link_dsl.ts b/modules/angular2/router/router_link_dsl.ts
new file mode 100644
index 000000000000..5f108b826f68
--- /dev/null
+++ b/modules/angular2/router/router_link_dsl.ts
@@ -0,0 +1,35 @@
+import {TEMPLATE_TRANSFORMS} from 'angular2/compiler';
+import {Provider} from 'angular2/core';
+import {RouterLinkTransform} from 'angular2/src/router/router_link_transform';
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+export {RouterLinkTransform} from 'angular2/src/router/router_link_transform';
+
+/**
+ * Enables the router link DSL.
+ *
+ * Warning. This feature is experimental and can change.
+ *
+ * To enable the transformer pass the router link DSL provider to `bootstrap`.
+ *
+ * ## Example:
+ * ```
+ * import {bootstrap} from 'angular2/platform/browser';
+ * import {ROUTER_LINK_DSL_PROVIDER} from 'angular2/router/router_link_dsl';
+ *
+ * bootstrap(CustomApp, [ROUTER_LINK_DSL_PROVIDER]);
+ * ```
+ *
+ * The DSL allows you to express router links as follows:
+ * ```
+ *
+ *
+ *
+ *
+ *
+ *
+ * ```
+ */
+export const ROUTER_LINK_DSL_PROVIDER =
+ CONST_EXPR(new Provider(TEMPLATE_TRANSFORMS, {useClass: RouterLinkTransform, multi: true}));
diff --git a/modules/angular2/router/testing.ts b/modules/angular2/router/testing.ts
new file mode 100644
index 000000000000..d565555caa44
--- /dev/null
+++ b/modules/angular2/router/testing.ts
@@ -0,0 +1,2 @@
+export * from 'angular2/src/mock/mock_location_strategy';
+export * from 'angular2/src/mock/location_mock';
diff --git a/modules/angular2/src/animate/animation.ts b/modules/angular2/src/animate/animation.ts
new file mode 100644
index 000000000000..4e7375898980
--- /dev/null
+++ b/modules/angular2/src/animate/animation.ts
@@ -0,0 +1,200 @@
+import {
+ DateWrapper,
+ StringWrapper,
+ RegExpWrapper,
+ NumberWrapper,
+ isPresent
+} from 'angular2/src/facade/lang';
+import {Math} from 'angular2/src/facade/math';
+import {camelCaseToDashCase} from 'angular2/src/platform/dom/util';
+import {StringMapWrapper} from 'angular2/src/facade/collection';
+import {DOM} from 'angular2/src/platform/dom/dom_adapter';
+
+import {BrowserDetails} from './browser_details';
+import {CssAnimationOptions} from './css_animation_options';
+
+export class Animation {
+ /** functions to be called upon completion */
+ callbacks: Function[] = [];
+
+ /** the duration (ms) of the animation (whether from CSS or manually set) */
+ computedDuration: number;
+
+ /** the animation delay (ms) (whether from CSS or manually set) */
+ computedDelay: number;
+
+ /** timestamp of when the animation started */
+ startTime: number;
+
+ /** functions for removing event listeners */
+ eventClearFunctions: Function[] = [];
+
+ /** flag used to track whether or not the animation has finished */
+ completed: boolean = false;
+
+ private _stringPrefix: string = '';
+
+ /** total amount of time that the animation should take including delay */
+ get totalTime(): number {
+ let delay = this.computedDelay != null ? this.computedDelay : 0;
+ let duration = this.computedDuration != null ? this.computedDuration : 0;
+ return delay + duration;
+ }
+
+ /**
+ * Stores the start time and starts the animation
+ * @param element
+ * @param data
+ * @param browserDetails
+ */
+ constructor(public element: HTMLElement, public data: CssAnimationOptions,
+ public browserDetails: BrowserDetails) {
+ this.startTime = DateWrapper.toMillis(DateWrapper.now());
+ this._stringPrefix = DOM.getAnimationPrefix();
+ this.setup();
+ this.wait(timestamp => this.start());
+ }
+
+ wait(callback: Function) {
+ // Firefox requires 2 frames for some reason
+ this.browserDetails.raf(callback, 2);
+ }
+
+ /**
+ * Sets up the initial styles before the animation is started
+ */
+ setup(): void {
+ if (this.data.fromStyles != null) this.applyStyles(this.data.fromStyles);
+ if (this.data.duration != null)
+ this.applyStyles({'transitionDuration': this.data.duration.toString() + 'ms'});
+ if (this.data.delay != null)
+ this.applyStyles({'transitionDelay': this.data.delay.toString() + 'ms'});
+ }
+
+ /**
+ * After the initial setup has occurred, this method adds the animation styles
+ */
+ start(): void {
+ this.addClasses(this.data.classesToAdd);
+ this.addClasses(this.data.animationClasses);
+ this.removeClasses(this.data.classesToRemove);
+ if (this.data.toStyles != null) this.applyStyles(this.data.toStyles);
+ var computedStyles = DOM.getComputedStyle(this.element);
+ this.computedDelay =
+ Math.max(this.parseDurationString(
+ computedStyles.getPropertyValue(this._stringPrefix + 'transition-delay')),
+ this.parseDurationString(
+ this.element.style.getPropertyValue(this._stringPrefix + 'transition-delay')));
+ this.computedDuration = Math.max(this.parseDurationString(computedStyles.getPropertyValue(
+ this._stringPrefix + 'transition-duration')),
+ this.parseDurationString(this.element.style.getPropertyValue(
+ this._stringPrefix + 'transition-duration')));
+ this.addEvents();
+ }
+
+ /**
+ * Applies the provided styles to the element
+ * @param styles
+ */
+ applyStyles(styles: {[key: string]: any}): void {
+ StringMapWrapper.forEach(styles, (value, key) => {
+ var dashCaseKey = camelCaseToDashCase(key);
+ if (isPresent(DOM.getStyle(this.element, dashCaseKey))) {
+ DOM.setStyle(this.element, dashCaseKey, value.toString());
+ } else {
+ DOM.setStyle(this.element, this._stringPrefix + dashCaseKey, value.toString());
+ }
+ });
+ }
+
+ /**
+ * Adds the provided classes to the element
+ * @param classes
+ */
+ addClasses(classes: string[]): void {
+ for (let i = 0, len = classes.length; i < len; i++) DOM.addClass(this.element, classes[i]);
+ }
+
+ /**
+ * Removes the provided classes from the element
+ * @param classes
+ */
+ removeClasses(classes: string[]): void {
+ for (let i = 0, len = classes.length; i < len; i++) DOM.removeClass(this.element, classes[i]);
+ }
+
+ /**
+ * Adds events to track when animations have finished
+ */
+ addEvents(): void {
+ if (this.totalTime > 0) {
+ this.eventClearFunctions.push(DOM.onAndCancel(
+ this.element, DOM.getTransitionEnd(), (event: any) => this.handleAnimationEvent(event)));
+ } else {
+ this.handleAnimationCompleted();
+ }
+ }
+
+ handleAnimationEvent(event: any): void {
+ let elapsedTime = Math.round(event.elapsedTime * 1000);
+ if (!this.browserDetails.elapsedTimeIncludesDelay) elapsedTime += this.computedDelay;
+ event.stopPropagation();
+ if (elapsedTime >= this.totalTime) this.handleAnimationCompleted();
+ }
+
+ /**
+ * Runs all animation callbacks and removes temporary classes
+ */
+ handleAnimationCompleted(): void {
+ this.removeClasses(this.data.animationClasses);
+ this.callbacks.forEach(callback => callback());
+ this.callbacks = [];
+ this.eventClearFunctions.forEach(fn => fn());
+ this.eventClearFunctions = [];
+ this.completed = true;
+ }
+
+ /**
+ * Adds animation callbacks to be called upon completion
+ * @param callback
+ * @returns {Animation}
+ */
+ onComplete(callback: Function): Animation {
+ if (this.completed) {
+ callback();
+ } else {
+ this.callbacks.push(callback);
+ }
+ return this;
+ }
+
+ /**
+ * Converts the duration string to the number of milliseconds
+ * @param duration
+ * @returns {number}
+ */
+ parseDurationString(duration: string): number {
+ var maxValue = 0;
+ // duration must have at least 2 characters to be valid. (number + type)
+ if (duration == null || duration.length < 2) {
+ return maxValue;
+ } else if (duration.substring(duration.length - 2) == 'ms') {
+ let value = NumberWrapper.parseInt(this.stripLetters(duration), 10);
+ if (value > maxValue) maxValue = value;
+ } else if (duration.substring(duration.length - 1) == 's') {
+ let ms = NumberWrapper.parseFloat(this.stripLetters(duration)) * 1000;
+ let value = Math.floor(ms);
+ if (value > maxValue) maxValue = value;
+ }
+ return maxValue;
+ }
+
+ /**
+ * Strips the letters from the duration string
+ * @param str
+ * @returns {string}
+ */
+ stripLetters(str: string): string {
+ return StringWrapper.replaceAll(str, RegExpWrapper.create('[^0-9]+$', ''), '');
+ }
+}
diff --git a/modules/angular2/src/animate/animation_builder.ts b/modules/angular2/src/animate/animation_builder.ts
new file mode 100644
index 000000000000..3b82e629ffca
--- /dev/null
+++ b/modules/angular2/src/animate/animation_builder.ts
@@ -0,0 +1,19 @@
+import {Injectable} from 'angular2/src/core/di';
+
+import {CssAnimationBuilder} from './css_animation_builder';
+import {BrowserDetails} from './browser_details';
+
+@Injectable()
+export class AnimationBuilder {
+ /**
+ * Used for DI
+ * @param browserDetails
+ */
+ constructor(public browserDetails: BrowserDetails) {}
+
+ /**
+ * Creates a new CSS Animation
+ * @returns {CssAnimationBuilder}
+ */
+ css(): CssAnimationBuilder { return new CssAnimationBuilder(this.browserDetails); }
+}
diff --git a/modules/angular2/src/animate/browser_details.ts b/modules/angular2/src/animate/browser_details.ts
new file mode 100644
index 000000000000..8c0316321ff3
--- /dev/null
+++ b/modules/angular2/src/animate/browser_details.ts
@@ -0,0 +1,54 @@
+import {Injectable} from 'angular2/src/core/di';
+import {Math} from 'angular2/src/facade/math';
+import {DOM} from 'angular2/src/platform/dom/dom_adapter';
+
+@Injectable()
+export class BrowserDetails {
+ elapsedTimeIncludesDelay = false;
+
+ constructor() { this.doesElapsedTimeIncludesDelay(); }
+
+ /**
+ * Determines if `event.elapsedTime` includes transition delay in the current browser. At this
+ * time, Chrome and Opera seem to be the only browsers that include this.
+ */
+ doesElapsedTimeIncludesDelay(): void {
+ var div = DOM.createElement('div');
+ DOM.setAttribute(div, 'style', `position: absolute; top: -9999px; left: -9999px; width: 1px;
+ height: 1px; transition: all 1ms linear 1ms;`);
+ // Firefox requires that we wait for 2 frames for some reason
+ this.raf(timestamp => {
+ DOM.on(div, 'transitionend', (event: any) => {
+ var elapsed = Math.round(event.elapsedTime * 1000);
+ this.elapsedTimeIncludesDelay = elapsed == 2;
+ DOM.remove(div);
+ });
+ DOM.setStyle(div, 'width', '2px');
+ }, 2);
+ }
+
+ raf(callback: Function, frames: number = 1): Function {
+ var queue: RafQueue = new RafQueue(callback, frames);
+ return () => queue.cancel();
+ }
+}
+
+class RafQueue {
+ currentFrameId: number;
+ constructor(public callback: Function, public frames: number) { this._raf(); }
+ private _raf() {
+ this.currentFrameId = DOM.requestAnimationFrame(timestamp => this._nextFrame(timestamp));
+ }
+ private _nextFrame(timestamp: number) {
+ this.frames--;
+ if (this.frames > 0) {
+ this._raf();
+ } else {
+ this.callback(timestamp);
+ }
+ }
+ cancel() {
+ DOM.cancelAnimationFrame(this.currentFrameId);
+ this.currentFrameId = null;
+ }
+}
diff --git a/modules/angular2/src/animate/css_animation_builder.ts b/modules/angular2/src/animate/css_animation_builder.ts
new file mode 100644
index 000000000000..502d7f64a571
--- /dev/null
+++ b/modules/angular2/src/animate/css_animation_builder.ts
@@ -0,0 +1,93 @@
+import {CssAnimationOptions} from './css_animation_options';
+import {Animation} from './animation';
+import {BrowserDetails} from './browser_details';
+
+export class CssAnimationBuilder {
+ /** @type {CssAnimationOptions} */
+ data: CssAnimationOptions = new CssAnimationOptions();
+
+ /**
+ * Accepts public properties for CssAnimationBuilder
+ */
+ constructor(public browserDetails: BrowserDetails) {}
+
+ /**
+ * Adds a temporary class that will be removed at the end of the animation
+ * @param className
+ */
+ addAnimationClass(className: string): CssAnimationBuilder {
+ this.data.animationClasses.push(className);
+ return this;
+ }
+
+ /**
+ * Adds a class that will remain on the element after the animation has finished
+ * @param className
+ */
+ addClass(className: string): CssAnimationBuilder {
+ this.data.classesToAdd.push(className);
+ return this;
+ }
+
+ /**
+ * Removes a class from the element
+ * @param className
+ */
+ removeClass(className: string): CssAnimationBuilder {
+ this.data.classesToRemove.push(className);
+ return this;
+ }
+
+ /**
+ * Sets the animation duration (and overrides any defined through CSS)
+ * @param duration
+ */
+ setDuration(duration: number): CssAnimationBuilder {
+ this.data.duration = duration;
+ return this;
+ }
+
+ /**
+ * Sets the animation delay (and overrides any defined through CSS)
+ * @param delay
+ */
+ setDelay(delay: number): CssAnimationBuilder {
+ this.data.delay = delay;
+ return this;
+ }
+
+ /**
+ * Sets styles for both the initial state and the destination state
+ * @param from
+ * @param to
+ */
+ setStyles(from: {[key: string]: any}, to: {[key: string]: any}): CssAnimationBuilder {
+ return this.setFromStyles(from).setToStyles(to);
+ }
+
+ /**
+ * Sets the initial styles for the animation
+ * @param from
+ */
+ setFromStyles(from: {[key: string]: any}): CssAnimationBuilder {
+ this.data.fromStyles = from;
+ return this;
+ }
+
+ /**
+ * Sets the destination styles for the animation
+ * @param to
+ */
+ setToStyles(to: {[key: string]: any}): CssAnimationBuilder {
+ this.data.toStyles = to;
+ return this;
+ }
+
+ /**
+ * Starts the animation and returns a promise
+ * @param element
+ */
+ start(element: HTMLElement): Animation {
+ return new Animation(element, this.data, this.browserDetails);
+ }
+}
diff --git a/modules/angular2/src/animate/css_animation_options.ts b/modules/angular2/src/animate/css_animation_options.ts
new file mode 100644
index 000000000000..eab07b893a83
--- /dev/null
+++ b/modules/angular2/src/animate/css_animation_options.ts
@@ -0,0 +1,22 @@
+export class CssAnimationOptions {
+ /** initial styles for the element */
+ fromStyles: {[key: string]: any};
+
+ /** destination styles for the element */
+ toStyles: {[key: string]: any};
+
+ /** classes to be added to the element */
+ classesToAdd: string[] = [];
+
+ /** classes to be removed from the element */
+ classesToRemove: string[] = [];
+
+ /** classes to be added for the duration of the animation */
+ animationClasses: string[] = [];
+
+ /** override the duration of the animation (in milliseconds) */
+ duration: number;
+
+ /** override the transition delay (in milliseconds) */
+ delay: number;
+}
diff --git a/modules/angular2/src/change_detection/abstract_change_detector.ts b/modules/angular2/src/change_detection/abstract_change_detector.ts
deleted file mode 100644
index aac85baf5379..000000000000
--- a/modules/angular2/src/change_detection/abstract_change_detector.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-import {isPresent, isBlank, BaseException, StringWrapper} from 'angular2/src/facade/lang';
-import {List, ListWrapper} from 'angular2/src/facade/collection';
-import {ChangeDetectionUtil} from './change_detection_util';
-import {ChangeDetectorRef} from './change_detector_ref';
-import {DirectiveRecord} from './directive_record';
-import {ChangeDetector, ChangeDispatcher} from './interfaces';
-import {Pipes} from './pipes';
-import {
- ChangeDetectionError,
- ExpressionChangedAfterItHasBeenCheckedException,
- DehydratedException
-} from './exceptions';
-import {ProtoRecord} from './proto_record';
-import {BindingRecord} from './binding_record';
-import {Locals} from './parser/locals';
-import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from './constants';
-import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
-import {isObservable} from './observable_facade';
-
-var _scope_check: WtfScopeFn = wtfCreateScope(`ChangeDetector#check(ascii id, bool throwOnChange)`);
-
-class _Context {
- constructor(public element: any, public componentElement: any, public instance: any,
- public context: any, public locals: any, public injector: any,
- public expression: any) {}
-}
-
-export class AbstractChangeDetector implements ChangeDetector {
- lightDomChildren: List = [];
- shadowDomChildren: List = [];
- parent: ChangeDetector;
- ref: ChangeDetectorRef;
-
- // The names of the below fields must be kept in sync with codegen_name_util.ts or
- // change detection will fail.
- alreadyChecked: any = false;
- context: T;
- directiveRecords: List;
- dispatcher: ChangeDispatcher;
- locals: Locals = null;
- mode: string = null;
- pipes: Pipes = null;
- firstProtoInCurrentBinding: number;
- protos: List;
-
- // This is an experimental feature. Works only in Dart.
- subscriptions: any[];
- streams: any[];
-
- constructor(public id: string, dispatcher: ChangeDispatcher, protos: List,
- directiveRecords: List, public modeOnHydrate: string) {
- this.ref = new ChangeDetectorRef(this);
- this.directiveRecords = directiveRecords;
- this.dispatcher = dispatcher;
- this.protos = protos;
- }
-
- addChild(cd: ChangeDetector): void {
- this.lightDomChildren.push(cd);
- cd.parent = this;
- }
-
- removeChild(cd: ChangeDetector): void { ListWrapper.remove(this.lightDomChildren, cd); }
-
- addShadowDomChild(cd: ChangeDetector): void {
- this.shadowDomChildren.push(cd);
- cd.parent = this;
- }
-
- removeShadowDomChild(cd: ChangeDetector): void { ListWrapper.remove(this.shadowDomChildren, cd); }
-
- remove(): void { this.parent.removeChild(this); }
-
- handleEvent(eventName: string, elIndex: number, locals: Locals): boolean {
- var res = this.handleEventInternal(eventName, elIndex, locals);
- this.markPathToRootAsCheckOnce();
- return res;
- }
-
- handleEventInternal(eventName: string, elIndex: number, locals: Locals): boolean { return false; }
-
- detectChanges(): void { this.runDetectChanges(false); }
-
- checkNoChanges(): void { throw new BaseException("Not implemented"); }
-
- runDetectChanges(throwOnChange: boolean): void {
- if (StringWrapper.equals(this.mode, DETACHED) || StringWrapper.equals(this.mode, CHECKED))
- return;
- var s = _scope_check(this.id, throwOnChange);
- this.detectChangesInRecords(throwOnChange);
- this._detectChangesInLightDomChildren(throwOnChange);
- if (throwOnChange === false) this.callOnAllChangesDone();
- this._detectChangesInShadowDomChildren(throwOnChange);
- if (StringWrapper.equals(this.mode, CHECK_ONCE)) this.mode = CHECKED;
- wtfLeave(s);
- }
-
- // This method is not intended to be overridden. Subclasses should instead provide an
- // implementation of `detectChangesInRecordsInternal` which does the work of detecting changes
- // and which this method will call.
- // This method expects that `detectChangesInRecordsInternal` will set the property
- // `this.firstProtoInCurrentBinding` to the selfIndex of the first proto record. This is to
- // facilitate error reporting.
- detectChangesInRecords(throwOnChange: boolean): void {
- if (!this.hydrated()) {
- this.throwDehydratedError();
- }
- try {
- this.detectChangesInRecordsInternal(throwOnChange);
- } catch (e) {
- this._throwError(e, e.stack);
- }
- }
-
- // Subclasses should override this method to perform any work necessary to detect and report
- // changes. For example, changes should be reported via `ChangeDetectionUtil.addChange`, lifecycle
- // methods should be called, etc.
- // This implementation should also set `this.firstProtoInCurrentBinding` to the selfIndex of the
- // first proto record
- // to facilitate error reporting. See {@link #detectChangesInRecords}.
- detectChangesInRecordsInternal(throwOnChange: boolean): void {}
-
- // This method is not intended to be overridden. Subclasses should instead provide an
- // implementation of `hydrateDirectives`.
- hydrate(context: T, locals: Locals, directives: any, pipes: any): void {
- this.mode = this.modeOnHydrate;
- this.context = context;
- this.locals = locals;
- this.pipes = pipes;
- this.hydrateDirectives(directives);
- this.alreadyChecked = false;
- }
-
- // Subclasses should override this method to hydrate any directives.
- hydrateDirectives(directives: any): void {}
-
- // This method is not intended to be overridden. Subclasses should instead provide an
- // implementation of `dehydrateDirectives`.
- dehydrate(): void {
- this.dehydrateDirectives(true);
-
- // This is an experimental feature. Works only in Dart.
- this.unsubsribeFromObservables();
-
- this.context = null;
- this.locals = null;
- this.pipes = null;
- }
-
- // Subclasses should override this method to dehydrate any directives. This method should reverse
- // any work done in `hydrateDirectives`.
- dehydrateDirectives(destroyPipes: boolean): void {}
-
- hydrated(): boolean { return this.context !== null; }
-
- callOnAllChangesDone(): void { this.dispatcher.notifyOnAllChangesDone(); }
-
- _detectChangesInLightDomChildren(throwOnChange: boolean): void {
- var c = this.lightDomChildren;
- for (var i = 0; i < c.length; ++i) {
- c[i].runDetectChanges(throwOnChange);
- }
- }
-
- _detectChangesInShadowDomChildren(throwOnChange: boolean): void {
- var c = this.shadowDomChildren;
- for (var i = 0; i < c.length; ++i) {
- c[i].runDetectChanges(throwOnChange);
- }
- }
-
- markAsCheckOnce(): void { this.mode = CHECK_ONCE; }
-
- markPathToRootAsCheckOnce(): void {
- var c: ChangeDetector = this;
- while (isPresent(c) && !StringWrapper.equals(c.mode, DETACHED)) {
- if (StringWrapper.equals(c.mode, CHECKED)) c.mode = CHECK_ONCE;
- c = c.parent;
- }
- }
-
- private unsubsribeFromObservables(): void {
- if (isPresent(this.subscriptions)) {
- for (var i = 0; i < this.subscriptions.length; ++i) {
- var s = this.subscriptions[i];
- if (isPresent(this.subscriptions[i])) {
- s.cancel();
- this.subscriptions[i] = null;
- }
- }
- }
- }
-
- // This is an experimental feature. Works only in Dart.
- protected observe(value: any, index: number): any {
- if (isObservable(value)) {
- if (isBlank(this.subscriptions)) {
- this.subscriptions = ListWrapper.createFixedSize(this.protos.length + 1);
- this.streams = ListWrapper.createFixedSize(this.protos.length + 1);
- }
- if (isBlank(this.subscriptions[index])) {
- this.streams[index] = value.changes;
- this.subscriptions[index] = value.changes.listen((_) => this.ref.requestCheck());
- } else if (this.streams[index] !== value.changes) {
- this.subscriptions[index].cancel();
- this.streams[index] = value.changes;
- this.subscriptions[index] = value.changes.listen((_) => this.ref.requestCheck());
- }
- }
- return value;
- }
-
- protected notifyDispatcher(value: any): void {
- this.dispatcher.notifyOnBinding(this._currentBinding(), value);
- }
-
- protected addChange(changes: StringMap, oldValue: any,
- newValue: any): StringMap {
- if (isBlank(changes)) {
- changes = {};
- }
- changes[this._currentBinding().propertyName] =
- ChangeDetectionUtil.simpleChange(oldValue, newValue);
- return changes;
- }
-
- private _throwError(exception: any, stack: any): void {
- var proto = this._currentBindingProto();
- var c = this.dispatcher.getDebugContext(proto.bindingRecord.elementIndex, proto.directiveIndex);
- var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.directive, c.context,
- c.locals, c.injector, proto.expressionAsString) :
- null;
- throw new ChangeDetectionError(proto, exception, stack, context);
- }
-
- protected throwOnChangeError(oldValue: any, newValue: any): void {
- var change = ChangeDetectionUtil.simpleChange(oldValue, newValue);
- throw new ExpressionChangedAfterItHasBeenCheckedException(this._currentBindingProto(), change,
- null);
- }
-
- protected throwDehydratedError(): void { throw new DehydratedException(); }
-
- private _currentBinding(): BindingRecord { return this._currentBindingProto().bindingRecord; }
-
- private _currentBindingProto(): ProtoRecord {
- return ChangeDetectionUtil.protoByIndex(this.protos, this.firstProtoInCurrentBinding);
- }
-}
diff --git a/modules/angular2/src/change_detection/binding_record.ts b/modules/angular2/src/change_detection/binding_record.ts
deleted file mode 100644
index b92fd4312e7b..000000000000
--- a/modules/angular2/src/change_detection/binding_record.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-import {isPresent, isBlank} from 'angular2/src/facade/lang';
-import {SetterFn} from 'angular2/src/reflection/types';
-import {AST} from './parser/ast';
-import {DirectiveIndex, DirectiveRecord} from './directive_record';
-
-const DIRECTIVE = "directive";
-const DIRECTIVE_LIFECYCLE = "directiveLifecycle";
-const ELEMENT_PROPERTY = "elementProperty";
-const ELEMENT_ATTRIBUTE = "elementAttribute";
-const ELEMENT_CLASS = "elementClass";
-const ELEMENT_STYLE = "elementStyle";
-const TEXT_NODE = "textNode";
-const EVENT = "event";
-const HOST_EVENT = "hostEvent";
-
-export class BindingRecord {
- constructor(public mode: string, public implicitReceiver: any, public ast: AST,
- public elementIndex: number, public propertyName: string, public propertyUnit: string,
- public eventName: string, public setter: SetterFn, public lifecycleEvent: string,
- public directiveRecord: DirectiveRecord) {}
-
- callOnChange(): boolean {
- return isPresent(this.directiveRecord) && this.directiveRecord.callOnChange;
- }
-
- isDefaultChangeDetection(): boolean {
- return isBlank(this.directiveRecord) || this.directiveRecord.isDefaultChangeDetection();
- }
-
- isDirective(): boolean { return this.mode === DIRECTIVE; }
-
- isDirectiveLifecycle(): boolean { return this.mode === DIRECTIVE_LIFECYCLE; }
-
- isElementProperty(): boolean { return this.mode === ELEMENT_PROPERTY; }
-
- isElementAttribute(): boolean { return this.mode === ELEMENT_ATTRIBUTE; }
-
- isElementClass(): boolean { return this.mode === ELEMENT_CLASS; }
-
- isElementStyle(): boolean { return this.mode === ELEMENT_STYLE; }
-
- isTextNode(): boolean { return this.mode === TEXT_NODE; }
-
- static createForDirective(ast: AST, propertyName: string, setter: SetterFn,
- directiveRecord: DirectiveRecord): BindingRecord {
- return new BindingRecord(DIRECTIVE, 0, ast, 0, propertyName, null, null, setter, null,
- directiveRecord);
- }
-
- static createDirectiveOnCheck(directiveRecord: DirectiveRecord): BindingRecord {
- return new BindingRecord(DIRECTIVE_LIFECYCLE, 0, null, 0, null, null, null, null, "onCheck",
- directiveRecord);
- }
-
- static createDirectiveOnInit(directiveRecord: DirectiveRecord): BindingRecord {
- return new BindingRecord(DIRECTIVE_LIFECYCLE, 0, null, 0, null, null, null, null, "onInit",
- directiveRecord);
- }
-
- static createDirectiveOnChange(directiveRecord: DirectiveRecord): BindingRecord {
- return new BindingRecord(DIRECTIVE_LIFECYCLE, 0, null, 0, null, null, null, null, "onChange",
- directiveRecord);
- }
-
- static createForElementProperty(ast: AST, elementIndex: number,
- propertyName: string): BindingRecord {
- return new BindingRecord(ELEMENT_PROPERTY, 0, ast, elementIndex, propertyName, null, null, null,
- null, null);
- }
-
- static createForElementAttribute(ast: AST, elementIndex: number,
- attributeName: string): BindingRecord {
- return new BindingRecord(ELEMENT_ATTRIBUTE, 0, ast, elementIndex, attributeName, null, null,
- null, null, null);
- }
-
- static createForElementClass(ast: AST, elementIndex: number, className: string): BindingRecord {
- return new BindingRecord(ELEMENT_CLASS, 0, ast, elementIndex, className, null, null, null, null,
- null);
- }
-
- static createForElementStyle(ast: AST, elementIndex: number, styleName: string,
- unit: string): BindingRecord {
- return new BindingRecord(ELEMENT_STYLE, 0, ast, elementIndex, styleName, unit, null, null, null,
- null);
- }
-
- static createForHostProperty(directiveIndex: DirectiveIndex, ast: AST,
- propertyName: string): BindingRecord {
- return new BindingRecord(ELEMENT_PROPERTY, directiveIndex, ast, directiveIndex.elementIndex,
- propertyName, null, null, null, null, null);
- }
-
- static createForHostAttribute(directiveIndex: DirectiveIndex, ast: AST,
- attributeName: string): BindingRecord {
- return new BindingRecord(ELEMENT_ATTRIBUTE, directiveIndex, ast, directiveIndex.elementIndex,
- attributeName, null, null, null, null, null);
- }
-
- static createForHostClass(directiveIndex: DirectiveIndex, ast: AST,
- className: string): BindingRecord {
- return new BindingRecord(ELEMENT_CLASS, directiveIndex, ast, directiveIndex.elementIndex,
- className, null, null, null, null, null);
- }
-
- static createForHostStyle(directiveIndex: DirectiveIndex, ast: AST, styleName: string,
- unit: string): BindingRecord {
- return new BindingRecord(ELEMENT_STYLE, directiveIndex, ast, directiveIndex.elementIndex,
- styleName, unit, null, null, null, null);
- }
-
- static createForTextNode(ast: AST, elementIndex: number): BindingRecord {
- return new BindingRecord(TEXT_NODE, 0, ast, elementIndex, null, null, null, null, null, null);
- }
-
- static createForEvent(ast: AST, eventName: string, elementIndex: number): BindingRecord {
- return new BindingRecord(EVENT, 0, ast, elementIndex, null, null, eventName, null, null, null);
- }
-
- static createForHostEvent(ast: AST, eventName: string,
- directiveRecord: DirectiveRecord): BindingRecord {
- var directiveIndex = directiveRecord.directiveIndex;
- return new BindingRecord(EVENT, directiveIndex, ast, directiveIndex.elementIndex, null, null,
- eventName, null, null, directiveRecord);
- }
-}
diff --git a/modules/angular2/src/change_detection/change_detection.ts b/modules/angular2/src/change_detection/change_detection.ts
deleted file mode 100644
index e189844ba0df..000000000000
--- a/modules/angular2/src/change_detection/change_detection.ts
+++ /dev/null
@@ -1,132 +0,0 @@
-import {JitProtoChangeDetector} from './jit_proto_change_detector';
-import {PregenProtoChangeDetector} from './pregen_proto_change_detector';
-import {DynamicProtoChangeDetector} from './proto_change_detector';
-import {IterableDiffers, IterableDifferFactory} from './differs/iterable_differs';
-import {DefaultIterableDifferFactory} from './differs/default_iterable_differ';
-import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
-import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
-import {ChangeDetection, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces';
-import {Injector, Inject, Injectable, OpaqueToken, Optional, Binding} from 'angular2/di';
-import {List, StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
-import {CONST, CONST_EXPR, isPresent, BaseException} from 'angular2/src/facade/lang';
-
-export {
- ASTWithSource,
- AST,
- AstTransformer,
- PropertyRead,
- LiteralArray,
- ImplicitReceiver
-} from './parser/ast';
-
-export {Lexer} from './parser/lexer';
-export {Parser} from './parser/parser';
-export {Locals} from './parser/locals';
-
-export {
- DehydratedException,
- ExpressionChangedAfterItHasBeenCheckedException,
- ChangeDetectionError
-} from './exceptions';
-export {
- ProtoChangeDetector,
- ChangeDetector,
- ChangeDispatcher,
- ChangeDetection,
- ChangeDetectorDefinition,
- DebugContext
-} from './interfaces';
-export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './constants';
-export {DynamicProtoChangeDetector} from './proto_change_detector';
-export {BindingRecord} from './binding_record';
-export {DirectiveIndex, DirectiveRecord} from './directive_record';
-export {DynamicChangeDetector} from './dynamic_change_detector';
-export {ChangeDetectorRef} from './change_detector_ref';
-export {IterableDiffers, IterableDiffer, IterableDifferFactory} from './differs/iterable_differs';
-export {KeyValueDiffers, KeyValueDiffer, KeyValueDifferFactory} from './differs/keyvalue_differs';
-export {PipeTransform, PipeOnDestroy} from './pipe_transform';
-export {WrappedValue} from './change_detection_util';
-
-/**
- * Structural diffing for `Object`s and `Map`s.
- */
-export const keyValDiff: KeyValueDifferFactory[] =
- CONST_EXPR([CONST_EXPR(new DefaultKeyValueDifferFactory())]);
-
-/**
- * Structural diffing for `Iterable` types such as `Array`s.
- */
-export const iterableDiff: IterableDifferFactory[] =
- CONST_EXPR([CONST_EXPR(new DefaultIterableDifferFactory())]);
-
-export const defaultIterableDiffers = CONST_EXPR(new IterableDiffers(iterableDiff));
-
-export const defaultKeyValueDiffers = CONST_EXPR(new KeyValueDiffers(keyValDiff));
-
-/**
- * Map from {@link ChangeDetectorDefinition#id} to a factory method which takes a
- * {@link Pipes} and a {@link ChangeDetectorDefinition} and generates a
- * {@link ProtoChangeDetector} associated with the definition.
- */
-// TODO(kegluneq): Use PregenProtoChangeDetectorFactory rather than Function once possible in
-// dart2js. See https://github.com/dart-lang/sdk/issues/23630 for details.
-export var preGeneratedProtoDetectors: StringMap = {};
-
-export const PROTO_CHANGE_DETECTOR = CONST_EXPR(new OpaqueToken('ProtoChangeDetectors'));
-
-/**
- * Implements change detection using a map of pregenerated proto detectors.
- */
-@Injectable()
-export class PreGeneratedChangeDetection extends ChangeDetection {
- _dynamicChangeDetection: ChangeDetection;
- _protoChangeDetectorFactories: StringMap;
-
- constructor(@Inject(PROTO_CHANGE_DETECTOR) @Optional() protoChangeDetectorsForTest?:
- StringMap) {
- super();
- this._dynamicChangeDetection = new DynamicChangeDetection();
- this._protoChangeDetectorFactories = isPresent(protoChangeDetectorsForTest) ?
- protoChangeDetectorsForTest :
- preGeneratedProtoDetectors;
- }
-
- static isSupported(): boolean { return PregenProtoChangeDetector.isSupported(); }
-
- createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
- var id = definition.id;
- if (StringMapWrapper.contains(this._protoChangeDetectorFactories, id)) {
- return StringMapWrapper.get(this._protoChangeDetectorFactories, id)(definition);
- }
- return this._dynamicChangeDetection.createProtoChangeDetector(definition);
- }
-}
-
-
-/**
- * Implements change detection that does not require `eval()`.
- *
- * This is slower than {@link JitChangeDetection}.
- */
-@Injectable()
-export class DynamicChangeDetection extends ChangeDetection {
- createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
- return new DynamicProtoChangeDetector(definition);
- }
-}
-
-/**
- * Implements faster change detection by generating source code.
- *
- * This requires `eval()`. For change detection that does not require `eval()`, see
- * {@link DynamicChangeDetection} and {@link PreGeneratedChangeDetection}.
- */
-@Injectable()
-@CONST()
-export class JitChangeDetection extends ChangeDetection {
- static isSupported(): boolean { return JitProtoChangeDetector.isSupported(); }
-
- createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
- return new JitProtoChangeDetector(definition);
- }
-}
diff --git a/modules/angular2/src/change_detection/change_detection_jit_generator.dart b/modules/angular2/src/change_detection/change_detection_jit_generator.dart
deleted file mode 100644
index 04069bf1896e..000000000000
--- a/modules/angular2/src/change_detection/change_detection_jit_generator.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-library change_detection.change_detection_jit_generator;
-
-/// Placeholder JIT generator for Dart.
-/// Dart does not support `eval`, so JIT generation is not an option. Instead,
-/// the Dart transformer pre-generates these Change Detector classes and
-/// registers them with the system. See `PreGeneratedChangeDetection`,
-/// `PregenProtoChangeDetector`, and
-/// `src/transform/template_compiler/change_detector_codegen.dart` for details.
-class ChangeDetectorJITGenerator {
- ChangeDetectorJITGenerator(typeName, strategy, records, directiveMementos) {}
-
- generate() {
- throw "Jit Change Detection is not supported in Dart";
- }
-
- static bool isSupported() => false;
-}
diff --git a/modules/angular2/src/change_detection/change_detection_jit_generator.ts b/modules/angular2/src/change_detection/change_detection_jit_generator.ts
deleted file mode 100644
index ba2601812394..000000000000
--- a/modules/angular2/src/change_detection/change_detection_jit_generator.ts
+++ /dev/null
@@ -1,380 +0,0 @@
-import {BaseException, Type, isBlank, isPresent} from 'angular2/src/facade/lang';
-import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
-
-import {AbstractChangeDetector} from './abstract_change_detector';
-import {ChangeDetectionUtil} from './change_detection_util';
-import {DirectiveIndex, DirectiveRecord} from './directive_record';
-
-import {ProtoRecord, RecordType} from './proto_record';
-import {CodegenNameUtil, sanitizeName} from './codegen_name_util';
-import {CodegenLogicUtil} from './codegen_logic_util';
-import {EventBinding} from './event_binding';
-
-
-/**
- * The code generator takes a list of proto records and creates a function/class
- * that "emulates" what the developer would write by hand to implement the same
- * kind of behaviour.
- *
- * This code should be kept in sync with the Dart transformer's
- * `angular2.transform.template_compiler.change_detector_codegen` library. If you make updates
- * here, please make equivalent changes there.
-*/
-var ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
-var UTIL = "ChangeDetectionUtil";
-var IS_CHANGED_LOCAL = "isChanged";
-var CHANGES_LOCAL = "changes";
-
-export class ChangeDetectorJITGenerator {
- _logic: CodegenLogicUtil;
- _names: CodegenNameUtil;
- _typeName: string;
-
- constructor(public id: string, private changeDetectionStrategy: string,
- public records: List, public eventBindings: EventBinding[],
- public directiveRecords: List, private generateCheckNoChanges: boolean) {
- this._names =
- new CodegenNameUtil(this.records, this.eventBindings, this.directiveRecords, UTIL);
- this._logic = new CodegenLogicUtil(this._names, UTIL, changeDetectionStrategy);
- this._typeName = sanitizeName(`ChangeDetector_${this.id}`);
- }
-
- generate(): Function {
- var classDefinition = `
- var ${this._typeName} = function ${this._typeName}(dispatcher, protos, directiveRecords) {
- ${ABSTRACT_CHANGE_DETECTOR}.call(
- this, ${JSON.stringify(this.id)}, dispatcher, protos, directiveRecords,
- "${ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy)}");
- this.dehydrateDirectives(false);
- }
-
- ${this._typeName}.prototype = Object.create(${ABSTRACT_CHANGE_DETECTOR}.prototype);
-
- ${this._typeName}.prototype.detectChangesInRecordsInternal = function(throwOnChange) {
- ${this._names.genInitLocals()}
- var ${IS_CHANGED_LOCAL} = false;
- var ${CHANGES_LOCAL} = null;
-
- ${this.records.map((r) => this._genRecord(r)).join("\n")}
-
- ${this._names.getAlreadyCheckedName()} = true;
- }
-
- ${this._maybeGenHandleEventInternal()}
-
- ${this._genCheckNoChanges()}
-
- ${this._maybeGenCallOnAllChangesDone()}
-
- ${this._maybeGenHydrateDirectives()}
-
- ${this._maybeGenDehydrateDirectives()}
-
- return function(dispatcher) {
- return new ${this._typeName}(dispatcher, protos, directiveRecords);
- }
- `;
- return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos',
- 'directiveRecords', classDefinition)(
- AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords);
- }
-
- _maybeGenHandleEventInternal(): string {
- if (this.eventBindings.length > 0) {
- var handlers = this.eventBindings.map(eb => this._genEventBinding(eb)).join("\n");
- return `
- ${this._typeName}.prototype.handleEventInternal = function(eventName, elIndex, locals) {
- var ${this._names.getPreventDefaultAccesor()} = false;
- ${this._names.genInitEventLocals()}
- ${handlers}
- return ${this._names.getPreventDefaultAccesor()};
- }
- `;
- } else {
- return '';
- }
- }
-
- _genEventBinding(eb: EventBinding): string {
- var recs = eb.records.map(r => this._genEventBindingEval(eb, r)).join("\n");
- return `
- if (eventName === "${eb.eventName}" && elIndex === ${eb.elIndex}) {
- ${recs}
- }`;
- }
-
- _genEventBindingEval(eb: EventBinding, r: ProtoRecord): string {
- if (r.lastInBinding) {
- var evalRecord = this._logic.genEventBindingEvalValue(eb, r);
- var markPath = this._genMarkPathToRootAsCheckOnce(r);
- var prevDefault = this._genUpdatePreventDefault(eb, r);
- return `${evalRecord}\n${markPath}\n${prevDefault}`;
- } else {
- return this._logic.genEventBindingEvalValue(eb, r);
- }
- }
-
- _genMarkPathToRootAsCheckOnce(r: ProtoRecord): string {
- var br = r.bindingRecord;
- if (br.isDefaultChangeDetection()) {
- return "";
- } else {
- return `${this._names.getDetectorName(br.directiveRecord.directiveIndex)}.markPathToRootAsCheckOnce();`;
- }
- }
-
- _genUpdatePreventDefault(eb: EventBinding, r: ProtoRecord): string {
- var local = this._names.getEventLocalName(eb, r.selfIndex);
- return `if (${local} === false) { ${this._names.getPreventDefaultAccesor()} = true};`;
- }
-
- _maybeGenDehydrateDirectives(): string {
- var destroyPipesCode = this._names.genPipeOnDestroy();
- if (destroyPipesCode) {
- destroyPipesCode = `if (destroyPipes) { ${destroyPipesCode} }`;
- }
- var dehydrateFieldsCode = this._names.genDehydrateFields();
- if (!destroyPipesCode && !dehydrateFieldsCode) return '';
- return `${this._typeName}.prototype.dehydrateDirectives = function(destroyPipes) {
- ${destroyPipesCode}
- ${dehydrateFieldsCode}
- }`;
- }
-
- _maybeGenHydrateDirectives(): string {
- var hydrateDirectivesCode = this._genHydrateDirectives();
- var hydrateDetectorsCode = this._genHydrateDetectors();
- if (!hydrateDirectivesCode && !hydrateDetectorsCode) return '';
- return `${this._typeName}.prototype.hydrateDirectives = function(directives) {
- ${hydrateDirectivesCode}
- ${hydrateDetectorsCode}
- }`;
- }
-
- _genHydrateDirectives(): string {
- var directiveFieldNames = this._names.getAllDirectiveNames();
- var lines = ListWrapper.createFixedSize(directiveFieldNames.length);
- for (var i = 0, iLen = directiveFieldNames.length; i < iLen; ++i) {
- lines[i] = `${directiveFieldNames[i]} = directives.getDirectiveFor(
- ${this._names.getDirectivesAccessorName()}[${i}].directiveIndex);`;
- }
- return lines.join('\n');
- }
-
- _genHydrateDetectors(): string {
- var detectorFieldNames = this._names.getAllDetectorNames();
- var lines = ListWrapper.createFixedSize(detectorFieldNames.length);
- for (var i = 0, iLen = detectorFieldNames.length; i < iLen; ++i) {
- lines[i] = `${detectorFieldNames[i]} = directives.getDetectorFor(
- ${this._names.getDirectivesAccessorName()}[${i}].directiveIndex);`;
- }
- return lines.join('\n');
- }
-
- _maybeGenCallOnAllChangesDone(): string {
- var notifications = [];
- var dirs = this.directiveRecords;
-
- // NOTE(kegluneq): Order is important!
- for (var i = dirs.length - 1; i >= 0; --i) {
- var dir = dirs[i];
- if (dir.callOnAllChangesDone) {
- notifications.push(
- `${this._names.getDirectiveName(dir.directiveIndex)}.onAllChangesDone();`);
- }
- }
- if (notifications.length > 0) {
- var directiveNotifications = notifications.join("\n");
- return `
- ${this._typeName}.prototype.callOnAllChangesDone = function() {
- ${ABSTRACT_CHANGE_DETECTOR}.prototype.callOnAllChangesDone.call(this);
- ${directiveNotifications}
- }
- `;
- } else {
- return '';
- }
- }
-
- _genRecord(r: ProtoRecord): string {
- var rec;
- if (r.isLifeCycleRecord()) {
- rec = this._genDirectiveLifecycle(r);
- } else if (r.isPipeRecord()) {
- rec = this._genPipeCheck(r);
- } else {
- rec = this._genReferenceCheck(r);
- }
- return `
- ${this._maybeFirstInBinding(r)}
- ${rec}
- ${this._maybeGenLastInDirective(r)}
- `;
- }
-
- _genDirectiveLifecycle(r: ProtoRecord): string {
- if (r.name === "onCheck") {
- return this._genOnCheck(r);
- } else if (r.name === "onInit") {
- return this._genOnInit(r);
- } else if (r.name === "onChange") {
- return this._genOnChange(r);
- } else {
- throw new BaseException(`Unknown lifecycle event '${r.name}'`);
- }
- }
-
- _genPipeCheck(r: ProtoRecord): string {
- var context = this._names.getLocalName(r.contextIndex);
- var argString = r.args.map((arg) => this._names.getLocalName(arg)).join(", ");
-
- var oldValue = this._names.getFieldName(r.selfIndex);
- var newValue = this._names.getLocalName(r.selfIndex);
-
- var pipe = this._names.getPipeName(r.selfIndex);
- var pipeType = r.name;
- var read = `
- if (${pipe} === ${UTIL}.uninitialized) {
- ${pipe} = ${this._names.getPipesAccessorName()}.get('${pipeType}');
- }
- ${newValue} = ${pipe}.transform(${context}, [${argString}]);
- `;
-
- var check = `
- if (${oldValue} !== ${newValue}) {
- ${newValue} = ${UTIL}.unwrapValue(${newValue})
- ${this._genChangeMarker(r)}
- ${this._genUpdateDirectiveOrElement(r)}
- ${this._genAddToChanges(r)}
- ${oldValue} = ${newValue};
- }
- `;
-
- return r.shouldBeChecked() ? `${read}${check}` : read;
- }
-
- _genReferenceCheck(r: ProtoRecord): string {
- var oldValue = this._names.getFieldName(r.selfIndex);
- var newValue = this._names.getLocalName(r.selfIndex);
- var read = `
- ${this._logic.genPropertyBindingEvalValue(r)}
- `;
-
- var check = `
- if (${newValue} !== ${oldValue}) {
- ${this._genChangeMarker(r)}
- ${this._genUpdateDirectiveOrElement(r)}
- ${this._genAddToChanges(r)}
- ${oldValue} = ${newValue};
- }
- `;
-
- var genCode = r.shouldBeChecked() ? `${read}${check}` : read;
-
- if (r.isPureFunction()) {
- var condition = r.args.map((a) => this._names.getChangeName(a)).join(" || ");
- if (r.isUsedByOtherRecord()) {
- return `if (${condition}) { ${genCode} } else { ${newValue} = ${oldValue}; }`;
- } else {
- return `if (${condition}) { ${genCode} }`;
- }
- } else {
- return genCode;
- }
- }
-
- _genChangeMarker(r: ProtoRecord): string {
- return r.argumentToPureFunction ? `${this._names.getChangeName(r.selfIndex)} = true` : ``;
- }
-
- _genUpdateDirectiveOrElement(r: ProtoRecord): string {
- if (!r.lastInBinding) return "";
-
- var newValue = this._names.getLocalName(r.selfIndex);
- var oldValue = this._names.getFieldName(r.selfIndex);
-
- var br = r.bindingRecord;
- if (br.isDirective()) {
- var directiveProperty =
- `${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.${br.propertyName}`;
- return `
- ${this._genThrowOnChangeCheck(oldValue, newValue)}
- ${directiveProperty} = ${newValue};
- ${IS_CHANGED_LOCAL} = true;
- `;
- } else {
- return `
- ${this._genThrowOnChangeCheck(oldValue, newValue)}
- this.notifyDispatcher(${newValue});
- `;
- }
- }
-
- _genThrowOnChangeCheck(oldValue: string, newValue: string): string {
- if (this.generateCheckNoChanges) {
- return `
- if(throwOnChange) {
- this.throwOnChangeError(${oldValue}, ${newValue});
- }
- `;
- } else {
- return '';
- }
- }
-
- _genCheckNoChanges(): string {
- if (this.generateCheckNoChanges) {
- return `${this._typeName}.prototype.checkNoChanges = function() { this.runDetectChanges(true); }`;
- } else {
- return '';
- }
- }
-
- _genAddToChanges(r: ProtoRecord): string {
- var newValue = this._names.getLocalName(r.selfIndex);
- var oldValue = this._names.getFieldName(r.selfIndex);
- if (!r.bindingRecord.callOnChange()) return "";
- return `${CHANGES_LOCAL} = this.addChange(${CHANGES_LOCAL}, ${oldValue}, ${newValue});`;
- }
-
- _maybeFirstInBinding(r: ProtoRecord): string {
- var prev = ChangeDetectionUtil.protoByIndex(this.records, r.selfIndex - 1);
- var firstInBindng = isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
- return firstInBindng ? `${this._names.getFirstProtoInCurrentBinding()} = ${r.selfIndex};` : '';
- }
-
- _maybeGenLastInDirective(r: ProtoRecord): string {
- if (!r.lastInDirective) return "";
- return `
- ${CHANGES_LOCAL} = null;
- ${this._genNotifyOnPushDetectors(r)}
- ${IS_CHANGED_LOCAL} = false;
- `;
- }
-
- _genOnCheck(r: ProtoRecord): string {
- var br = r.bindingRecord;
- return `if (!throwOnChange) ${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.onCheck();`;
- }
-
- _genOnInit(r: ProtoRecord): string {
- var br = r.bindingRecord;
- return `if (!throwOnChange && !${this._names.getAlreadyCheckedName()}) ${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.onInit();`;
- }
-
- _genOnChange(r: ProtoRecord): string {
- var br = r.bindingRecord;
- return `if (!throwOnChange && ${CHANGES_LOCAL}) ${this._names.getDirectiveName(br.directiveRecord.directiveIndex)}.onChange(${CHANGES_LOCAL});`;
- }
-
- _genNotifyOnPushDetectors(r: ProtoRecord): string {
- var br = r.bindingRecord;
- if (!r.lastInDirective || br.isDefaultChangeDetection()) return "";
- var retVal = `
- if(${IS_CHANGED_LOCAL}) {
- ${this._names.getDetectorName(br.directiveRecord.directiveIndex)}.markAsCheckOnce();
- }
- `;
- return retVal;
- }
-}
diff --git a/modules/angular2/src/change_detection/change_detector_ref.ts b/modules/angular2/src/change_detection/change_detector_ref.ts
deleted file mode 100644
index 781510954cac..000000000000
--- a/modules/angular2/src/change_detection/change_detector_ref.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import {ChangeDetector} from './interfaces';
-import {CHECK_ONCE, DETACHED, CHECK_ALWAYS} from './constants';
-
-/**
- * Controls change detection.
- *
- * {@link ChangeDetectorRef} allows requesting checks for detectors that rely on observables. It
- * also allows detaching and attaching change detector subtrees.
- */
-export class ChangeDetectorRef {
- /**
- * @private
- */
- constructor(private _cd: ChangeDetector) {}
-
- /**
- * Request to check all ON_PUSH ancestors.
- */
- requestCheck(): void { this._cd.markPathToRootAsCheckOnce(); }
-
- /**
- * Detaches the change detector from the change detector tree.
- *
- * The detached change detector will not be checked until it is reattached.
- */
- detach(): void { this._cd.mode = DETACHED; }
-
- /**
- * Reattach the change detector to the change detector tree.
- *
- * This also requests a check of this change detector. This reattached change detector will be
- *checked during the
- * next change detection run.
- */
- reattach(): void {
- this._cd.mode = CHECK_ALWAYS;
- this.requestCheck();
- }
-}
diff --git a/modules/angular2/src/change_detection/coalesce.ts b/modules/angular2/src/change_detection/coalesce.ts
deleted file mode 100644
index d2d77964378b..000000000000
--- a/modules/angular2/src/change_detection/coalesce.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import {isPresent, isBlank, looseIdentical} from 'angular2/src/facade/lang';
-import {List, ListWrapper, Map} from 'angular2/src/facade/collection';
-import {RecordType, ProtoRecord} from './proto_record';
-
-/**
- * Removes "duplicate" records. It assuming that record evaluation does not
- * have side-effects.
- *
- * Records that are not last in bindings are removed and all the indices
- * of the records that depend on them are updated.
- *
- * Records that are last in bindings CANNOT be removed, and instead are
- * replaced with very cheap SELF records.
- */
-export function coalesce(records: ProtoRecord[]): ProtoRecord[] {
- var res: List = [];
- var indexMap: Map = new Map();
-
- for (var i = 0; i < records.length; ++i) {
- var r = records[i];
- var record = _replaceIndices(r, res.length + 1, indexMap);
- var matchingRecord = _findMatching(record, res);
-
- if (isPresent(matchingRecord) && record.lastInBinding) {
- res.push(_selfRecord(record, matchingRecord.selfIndex, res.length + 1));
- indexMap.set(r.selfIndex, matchingRecord.selfIndex);
- matchingRecord.referencedBySelf = true;
-
- } else if (isPresent(matchingRecord) && !record.lastInBinding) {
- if (record.argumentToPureFunction) {
- matchingRecord.argumentToPureFunction = true;
- }
-
- indexMap.set(r.selfIndex, matchingRecord.selfIndex);
-
- } else {
- res.push(record);
- indexMap.set(r.selfIndex, record.selfIndex);
- }
- }
-
- return res;
-}
-
-function _selfRecord(r: ProtoRecord, contextIndex: number, selfIndex: number): ProtoRecord {
- return new ProtoRecord(RecordType.SELF, "self", null, [], r.fixedArgs, contextIndex,
- r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString,
- r.lastInBinding, r.lastInDirective, false, false);
-}
-
-function _findMatching(r: ProtoRecord, rs: List) {
- return ListWrapper.find(
- rs, (rr) => rr.mode !== RecordType.DIRECTIVE_LIFECYCLE && _sameDirIndex(rr, r) &&
- rr.mode === r.mode && looseIdentical(rr.funcOrValue, r.funcOrValue) &&
- rr.contextIndex === r.contextIndex && looseIdentical(rr.name, r.name) &&
- ListWrapper.equals(rr.args, r.args));
-}
-
-function _sameDirIndex(a: ProtoRecord, b: ProtoRecord): boolean {
- var di1 = isBlank(a.directiveIndex) ? null : a.directiveIndex.directiveIndex;
- var ei1 = isBlank(a.directiveIndex) ? null : a.directiveIndex.elementIndex;
-
- var di2 = isBlank(b.directiveIndex) ? null : b.directiveIndex.directiveIndex;
- var ei2 = isBlank(b.directiveIndex) ? null : b.directiveIndex.elementIndex;
-
- return di1 === di2 && ei1 === ei2;
-}
-
-function _replaceIndices(r: ProtoRecord, selfIndex: number, indexMap: Map) {
- var args = ListWrapper.map(r.args, (a) => _map(indexMap, a));
- var contextIndex = _map(indexMap, r.contextIndex);
- return new ProtoRecord(r.mode, r.name, r.funcOrValue, args, r.fixedArgs, contextIndex,
- r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString,
- r.lastInBinding, r.lastInDirective, r.argumentToPureFunction,
- r.referencedBySelf);
-}
-
-function _map(indexMap: Map, value: number) {
- var r = indexMap.get(value);
- return isPresent(r) ? r : value;
-}
diff --git a/modules/angular2/src/change_detection/codegen_logic_util.ts b/modules/angular2/src/change_detection/codegen_logic_util.ts
deleted file mode 100644
index 13842ee596c5..000000000000
--- a/modules/angular2/src/change_detection/codegen_logic_util.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-import {ListWrapper} from 'angular2/src/facade/collection';
-import {BaseException, Json, StringWrapper} from 'angular2/src/facade/lang';
-import {CodegenNameUtil} from './codegen_name_util';
-import {codify, combineGeneratedStrings, rawString} from './codegen_facade';
-import {ProtoRecord, RecordType} from './proto_record';
-
-/**
- * This is an experimental feature. Works only in Dart.
- */
-const ON_PUSH_OBSERVE = "ON_PUSH_OBSERVE";
-
-/**
- * Class responsible for providing change detection logic for chagne detector classes.
- */
-export class CodegenLogicUtil {
- constructor(private _names: CodegenNameUtil, private _utilName: string,
- private _changeDetection: string) {}
-
- /**
- * Generates a statement which updates the local variable representing `protoRec` with the current
- * value of the record. Used by property bindings.
- */
- genPropertyBindingEvalValue(protoRec: ProtoRecord): string {
- return this.genEvalValue(protoRec, idx => this._names.getLocalName(idx),
- this._names.getLocalsAccessorName());
- }
-
- /**
- * Generates a statement which updates the local variable representing `protoRec` with the current
- * value of the record. Used by event bindings.
- */
- genEventBindingEvalValue(eventRecord: any, protoRec: ProtoRecord): string {
- return this.genEvalValue(protoRec, idx => this._names.getEventLocalName(eventRecord, idx),
- "locals");
- }
-
- private genEvalValue(protoRec: ProtoRecord, getLocalName: Function,
- localsAccessor: string): string {
- var context = (protoRec.contextIndex == -1) ?
- this._names.getDirectiveName(protoRec.directiveIndex) :
- getLocalName(protoRec.contextIndex);
- var argString = ListWrapper.map(protoRec.args, (arg) => getLocalName(arg)).join(", ");
-
- var rhs: string;
- switch (protoRec.mode) {
- case RecordType.SELF:
- rhs = context;
- break;
-
- case RecordType.CONST:
- rhs = codify(protoRec.funcOrValue);
- break;
-
- case RecordType.PROPERTY_READ:
- rhs = this._observe(`${context}.${protoRec.name}`, protoRec);
- break;
-
- case RecordType.SAFE_PROPERTY:
- var read = this._observe(`${context}.${protoRec.name}`, protoRec);
- rhs =
- `${this._utilName}.isValueBlank(${context}) ? null : ${this._observe(read, protoRec)}`;
- break;
-
- case RecordType.PROPERTY_WRITE:
- rhs = `${context}.${protoRec.name} = ${getLocalName(protoRec.args[0])}`;
- break;
-
- case RecordType.LOCAL:
- rhs = this._observe(`${localsAccessor}.get(${rawString(protoRec.name)})`, protoRec);
- break;
-
- case RecordType.INVOKE_METHOD:
- rhs = this._observe(`${context}.${protoRec.name}(${argString})`, protoRec);
- break;
-
- case RecordType.SAFE_INVOKE_METHOD:
- var invoke = `${context}.${protoRec.name}(${argString})`;
- rhs =
- `${this._utilName}.isValueBlank(${context}) ? null : ${this._observe(invoke, protoRec)}`;
- break;
-
- case RecordType.INVOKE_CLOSURE:
- rhs = `${context}(${argString})`;
- break;
-
- case RecordType.PRIMITIVE_OP:
- rhs = `${this._utilName}.${protoRec.name}(${argString})`;
- break;
-
- case RecordType.COLLECTION_LITERAL:
- rhs = `${this._utilName}.${protoRec.name}(${argString})`;
- break;
-
- case RecordType.INTERPOLATE:
- rhs = this._genInterpolation(protoRec);
- break;
-
- case RecordType.KEYED_READ:
- rhs = this._observe(`${context}[${getLocalName(protoRec.args[0])}]`, protoRec);
- break;
-
- case RecordType.KEYED_WRITE:
- rhs = `${context}[${getLocalName(protoRec.args[0])}] = ${getLocalName(protoRec.args[1])}`;
- break;
-
- case RecordType.CHAIN:
- rhs = 'null';
- break;
-
- default:
- throw new BaseException(`Unknown operation ${protoRec.mode}`);
- }
- return `${getLocalName(protoRec.selfIndex)} = ${rhs};`;
- }
-
- _observe(exp: string, rec: ProtoRecord): string {
- // This is an experimental feature. Works only in Dart.
- if (StringWrapper.equals(this._changeDetection, ON_PUSH_OBSERVE)) {
- return `this.observe(${exp}, ${rec.selfIndex})`;
- } else {
- return exp;
- }
- }
-
- _genInterpolation(protoRec: ProtoRecord): string {
- var iVals = [];
- for (var i = 0; i < protoRec.args.length; ++i) {
- iVals.push(codify(protoRec.fixedArgs[i]));
- iVals.push(`${this._utilName}.s(${this._names.getLocalName(protoRec.args[i])})`);
- }
- iVals.push(codify(protoRec.fixedArgs[protoRec.args.length]));
- return combineGeneratedStrings(iVals);
- }
-}
diff --git a/modules/angular2/src/change_detection/codegen_name_util.ts b/modules/angular2/src/change_detection/codegen_name_util.ts
deleted file mode 100644
index 8e99ec5d3f2d..000000000000
--- a/modules/angular2/src/change_detection/codegen_name_util.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-import {RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
-import {List, ListWrapper, MapWrapper, Map} from 'angular2/src/facade/collection';
-
-import {DirectiveIndex} from './directive_record';
-
-import {ProtoRecord} from './proto_record';
-import {EventBinding} from './event_binding';
-
-// The names of these fields must be kept in sync with abstract_change_detector.ts or change
-// detection will fail.
-const _ALREADY_CHECKED_ACCESSOR = "alreadyChecked";
-const _CONTEXT_ACCESSOR = "context";
-const _FIRST_PROTO_IN_CURRENT_BINDING = "firstProtoInCurrentBinding";
-const _DIRECTIVES_ACCESSOR = "directiveRecords";
-const _DISPATCHER_ACCESSOR = "dispatcher";
-const _LOCALS_ACCESSOR = "locals";
-const _MODE_ACCESSOR = "mode";
-const _PIPES_ACCESSOR = "pipes";
-const _PROTOS_ACCESSOR = "protos";
-
-// `context` is always first.
-export const CONTEXT_INDEX = 0;
-const _FIELD_PREFIX = 'this.';
-
-var _whiteSpaceRegExp = RegExpWrapper.create("\\W", "g");
-
-/**
- * Returns `s` with all non-identifier characters removed.
- */
-export function sanitizeName(s: string): string {
- return StringWrapper.replaceAll(s, _whiteSpaceRegExp, '');
-}
-
-/**
- * Class responsible for providing field and local variable names for change detector classes.
- * Also provides some convenience functions, for example, declaring variables, destroying pipes,
- * and dehydrating the detector.
- */
-export class CodegenNameUtil {
- /**
- * Record names sanitized for use as fields.
- * See [sanitizeName] for details.
- */
- _sanitizedNames: List;
- _sanitizedEventNames: Map>;
-
- constructor(private records: List, private eventBindings: EventBinding[],
- private directiveRecords: List, private utilName: string) {
- this._sanitizedNames = ListWrapper.createFixedSize(this.records.length + 1);
- this._sanitizedNames[CONTEXT_INDEX] = _CONTEXT_ACCESSOR;
- for (var i = 0, iLen = this.records.length; i < iLen; ++i) {
- this._sanitizedNames[i + 1] = sanitizeName(`${this.records[i].name}${i}`);
- }
-
- this._sanitizedEventNames = new Map();
- for (var ebIndex = 0; ebIndex < eventBindings.length; ++ebIndex) {
- var eb = eventBindings[ebIndex];
- var names = [_CONTEXT_ACCESSOR];
- for (var i = 0, iLen = eb.records.length; i < iLen; ++i) {
- names.push(sanitizeName(`${eb.records[i].name}${i}_${ebIndex}`));
- }
- this._sanitizedEventNames.set(eb, names);
- }
- }
-
- _addFieldPrefix(name: string): string { return `${_FIELD_PREFIX}${name}`; }
-
- getDispatcherName(): string { return this._addFieldPrefix(_DISPATCHER_ACCESSOR); }
-
- getPipesAccessorName(): string { return this._addFieldPrefix(_PIPES_ACCESSOR); }
-
- getProtosName(): string { return this._addFieldPrefix(_PROTOS_ACCESSOR); }
-
- getDirectivesAccessorName(): string { return this._addFieldPrefix(_DIRECTIVES_ACCESSOR); }
-
- getLocalsAccessorName(): string { return this._addFieldPrefix(_LOCALS_ACCESSOR); }
-
- getAlreadyCheckedName(): string { return this._addFieldPrefix(_ALREADY_CHECKED_ACCESSOR); }
-
- getModeName(): string { return this._addFieldPrefix(_MODE_ACCESSOR); }
-
- getFirstProtoInCurrentBinding(): string {
- return this._addFieldPrefix(_FIRST_PROTO_IN_CURRENT_BINDING);
- }
-
- getLocalName(idx: int): string { return `l_${this._sanitizedNames[idx]}`; }
-
- getEventLocalName(eb: EventBinding, idx: int): string {
- return `l_${MapWrapper.get(this._sanitizedEventNames, eb)[idx]}`;
- }
-
- getChangeName(idx: int): string { return `c_${this._sanitizedNames[idx]}`; }
-
- /**
- * Generate a statement initializing local variables used when detecting changes.
- */
- genInitLocals(): string {
- var declarations = [];
- var assignments = [];
- for (var i = 0, iLen = this.getFieldCount(); i < iLen; ++i) {
- if (i == CONTEXT_INDEX) {
- declarations.push(`${this.getLocalName(i)} = ${this.getFieldName(i)}`);
- } else {
- var rec = this.records[i - 1];
- if (rec.argumentToPureFunction) {
- var changeName = this.getChangeName(i);
- declarations.push(`${this.getLocalName(i)},${changeName}`);
- assignments.push(changeName);
- } else {
- declarations.push(`${this.getLocalName(i)}`);
- }
- }
- }
- var assignmentsCode =
- ListWrapper.isEmpty(assignments) ? '' : `${ListWrapper.join(assignments, '=')} = false;`;
- return `var ${ListWrapper.join(declarations, ',')};${assignmentsCode}`;
- }
-
- /**
- * Generate a statement initializing local variables for event handlers.
- */
- genInitEventLocals(): string {
- var res = [`${this.getLocalName(CONTEXT_INDEX)} = ${this.getFieldName(CONTEXT_INDEX)}`];
- MapWrapper.forEach(this._sanitizedEventNames, (names, eb) => {
- for (var i = 0; i < names.length; ++i) {
- if (i !== CONTEXT_INDEX) {
- res.push(`${this.getEventLocalName(eb, i)}`);
- }
- }
- });
- return res.length > 1 ? `var ${res.join(',')};` : '';
- }
-
- getPreventDefaultAccesor(): string { return "preventDefault"; }
-
- getFieldCount(): int { return this._sanitizedNames.length; }
-
- getFieldName(idx: int): string { return this._addFieldPrefix(this._sanitizedNames[idx]); }
-
- getAllFieldNames(): List {
- var fieldList = [];
- for (var k = 0, kLen = this.getFieldCount(); k < kLen; ++k) {
- if (k === 0 || this.records[k - 1].shouldBeChecked()) {
- fieldList.push(this.getFieldName(k));
- }
- }
-
- for (var i = 0, iLen = this.records.length; i < iLen; ++i) {
- var rec = this.records[i];
- if (rec.isPipeRecord()) {
- fieldList.push(this.getPipeName(rec.selfIndex));
- }
- }
-
- for (var j = 0, jLen = this.directiveRecords.length; j < jLen; ++j) {
- var dRec = this.directiveRecords[j];
- fieldList.push(this.getDirectiveName(dRec.directiveIndex));
- if (!dRec.isDefaultChangeDetection()) {
- fieldList.push(this.getDetectorName(dRec.directiveIndex));
- }
- }
- return fieldList;
- }
-
- /**
- * Generates statements which clear all fields so that the change detector is dehydrated.
- */
- genDehydrateFields(): string {
- var fields = this.getAllFieldNames();
- ListWrapper.removeAt(fields, CONTEXT_INDEX);
- if (ListWrapper.isEmpty(fields)) return '';
-
- // At least one assignment.
- fields.push(`${this.utilName}.uninitialized;`);
- return ListWrapper.join(fields, ' = ');
- }
-
- /**
- * Generates statements destroying all pipe variables.
- */
- genPipeOnDestroy(): string {
- return ListWrapper.join(
- ListWrapper.map(
- ListWrapper.filter(this.records, (r) => { return r.isPipeRecord(); }),
- (r) => {
- return `${this.utilName}.callPipeOnDestroy(${this.getPipeName(r.selfIndex)});`;
- }),
- '\n');
- }
-
- getPipeName(idx: int): string {
- return this._addFieldPrefix(`${this._sanitizedNames[idx]}_pipe`);
- }
-
- getAllDirectiveNames(): List {
- return ListWrapper.map(this.directiveRecords, d => this.getDirectiveName(d.directiveIndex));
- }
-
- getDirectiveName(d: DirectiveIndex): string {
- return this._addFieldPrefix(`directive_${d.name}`);
- }
-
- getAllDetectorNames(): List {
- return ListWrapper.map(
- ListWrapper.filter(this.directiveRecords, r => !r.isDefaultChangeDetection()),
- (d) => this.getDetectorName(d.directiveIndex));
- }
-
- getDetectorName(d: DirectiveIndex): string { return this._addFieldPrefix(`detector_${d.name}`); }
-}
diff --git a/modules/angular2/src/change_detection/constants.ts b/modules/angular2/src/change_detection/constants.ts
deleted file mode 100644
index c481ebc8ebea..000000000000
--- a/modules/angular2/src/change_detection/constants.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// TODO:vsavkin Use enums after switching to TypeScript
-import {StringWrapper, normalizeBool, isBlank} from 'angular2/src/facade/lang';
-
-/**
- * CHECK_ONCE means that after calling detectChanges the mode of the change detector
- * will become CHECKED.
- */
-export const CHECK_ONCE: string = "CHECK_ONCE";
-
-/**
- * CHECKED means that the change detector should be skipped until its mode changes to
- * CHECK_ONCE or CHECK_ALWAYS.
- */
-export const CHECKED: string = "CHECKED";
-
-/**
- * CHECK_ALWAYS means that after calling detectChanges the mode of the change detector
- * will remain CHECK_ALWAYS.
- */
-export const CHECK_ALWAYS: string = "ALWAYS_CHECK";
-
-/**
- * DETACHED means that the change detector sub tree is not a part of the main tree and
- * should be skipped.
- */
-export const DETACHED: string = "DETACHED";
-
-/**
- * ON_PUSH means that the change detector's mode will be set to CHECK_ONCE during hydration.
- */
-export const ON_PUSH: string = "ON_PUSH";
-
-/**
- * DEFAULT means that the change detector's mode will be set to CHECK_ALWAYS during hydration.
- */
-export const DEFAULT: string = "DEFAULT";
-
-export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: string): boolean {
- return isBlank(changeDetectionStrategy) || StringWrapper.equals(changeDetectionStrategy, DEFAULT);
-}
\ No newline at end of file
diff --git a/modules/angular2/src/change_detection/directive_record.ts b/modules/angular2/src/change_detection/directive_record.ts
deleted file mode 100644
index 3658414b7295..000000000000
--- a/modules/angular2/src/change_detection/directive_record.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import {StringWrapper, normalizeBool, isBlank} from 'angular2/src/facade/lang';
-import {isDefaultChangeDetectionStrategy} from './constants';
-
-export class DirectiveIndex {
- constructor(public elementIndex: number, public directiveIndex: number) {}
-
- get name() { return `${this.elementIndex}_${this.directiveIndex}`; }
-}
-
-export class DirectiveRecord {
- directiveIndex: DirectiveIndex;
- callOnAllChangesDone: boolean;
- callOnChange: boolean;
- callOnCheck: boolean;
- callOnInit: boolean;
- changeDetection: string;
-
- constructor({directiveIndex, callOnAllChangesDone, callOnChange, callOnCheck, callOnInit,
- changeDetection}: {
- directiveIndex?: DirectiveIndex,
- callOnAllChangesDone?: boolean,
- callOnChange?: boolean,
- callOnCheck?: boolean,
- callOnInit?: boolean,
- changeDetection?: string
- } = {}) {
- this.directiveIndex = directiveIndex;
- this.callOnAllChangesDone = normalizeBool(callOnAllChangesDone);
- this.callOnChange = normalizeBool(callOnChange);
- this.callOnCheck = normalizeBool(callOnCheck);
- this.callOnInit = normalizeBool(callOnInit);
- this.changeDetection = changeDetection;
- }
-
- isDefaultChangeDetection(): boolean {
- return isDefaultChangeDetectionStrategy(this.changeDetection);
- }
-}
\ No newline at end of file
diff --git a/modules/angular2/src/change_detection/dynamic_change_detector.ts b/modules/angular2/src/change_detection/dynamic_change_detector.ts
deleted file mode 100644
index ef6d98d5576f..000000000000
--- a/modules/angular2/src/change_detection/dynamic_change_detector.ts
+++ /dev/null
@@ -1,399 +0,0 @@
-import {
- isPresent,
- isBlank,
- BaseException,
- FunctionWrapper,
- StringWrapper
-} from 'angular2/src/facade/lang';
-import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
-
-import {AbstractChangeDetector} from './abstract_change_detector';
-import {EventBinding} from './event_binding';
-import {BindingRecord} from './binding_record';
-import {Locals} from './parser/locals';
-import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
-
-
-import {ProtoRecord, RecordType} from './proto_record';
-
-export class DynamicChangeDetector extends AbstractChangeDetector {
- values: List;
- changes: List;
- localPipes: List;
- prevContexts: List;
- directives: any = null;
-
- constructor(id: string, changeDetectionStrategy: string, dispatcher: any,
- protos: List, public eventBindings: EventBinding[],
- directiveRecords: List) {
- super(id, dispatcher, protos, directiveRecords,
- ChangeDetectionUtil.changeDetectionMode(changeDetectionStrategy));
- var len = protos.length + 1;
- this.values = ListWrapper.createFixedSize(len);
- this.localPipes = ListWrapper.createFixedSize(len);
- this.prevContexts = ListWrapper.createFixedSize(len);
- this.changes = ListWrapper.createFixedSize(len);
-
- this.dehydrateDirectives(false);
- }
-
- handleEventInternal(eventName: string, elIndex: number, locals: Locals): boolean {
- var preventDefault = false;
-
- this._matchingEventBindings(eventName, elIndex)
- .forEach(rec => {
- var res = this._processEventBinding(rec, locals);
- if (res === false) {
- preventDefault = true;
- }
- });
-
- return preventDefault;
- }
-
- _processEventBinding(eb: EventBinding, locals: Locals): any {
- var values = ListWrapper.createFixedSize(eb.records.length);
- values[0] = this.values[0];
-
- for (var i = 0; i < eb.records.length; ++i) {
- var proto = eb.records[i];
- var res = this._calculateCurrValue(proto, values, locals);
- if (proto.lastInBinding) {
- this._markPathAsCheckOnce(proto);
- return res;
- } else {
- this._writeSelf(proto, res, values);
- }
- }
-
- throw new BaseException("Cannot be reached");
- }
-
- _markPathAsCheckOnce(proto: ProtoRecord): void {
- if (!proto.bindingRecord.isDefaultChangeDetection()) {
- var dir = proto.bindingRecord.directiveRecord;
- this._getDetectorFor(dir.directiveIndex).markPathToRootAsCheckOnce();
- }
- }
-
- _matchingEventBindings(eventName: string, elIndex: number): EventBinding[] {
- return ListWrapper.filter(this.eventBindings,
- eb => eb.eventName == eventName && eb.elIndex === elIndex);
- }
-
- hydrateDirectives(directives: any): void {
- this.values[0] = this.context;
- this.directives = directives;
- }
-
- dehydrateDirectives(destroyPipes: boolean) {
- if (destroyPipes) {
- this._destroyPipes();
- }
- this.values[0] = null;
- this.directives = null;
- ListWrapper.fill(this.values, ChangeDetectionUtil.uninitialized, 1);
- ListWrapper.fill(this.changes, false);
- ListWrapper.fill(this.localPipes, null);
- ListWrapper.fill(this.prevContexts, ChangeDetectionUtil.uninitialized);
- }
-
- _destroyPipes() {
- for (var i = 0; i < this.localPipes.length; ++i) {
- if (isPresent(this.localPipes[i])) {
- ChangeDetectionUtil.callPipeOnDestroy(this.localPipes[i]);
- }
- }
- }
-
- checkNoChanges(): void { this.runDetectChanges(true); }
-
- detectChangesInRecordsInternal(throwOnChange: boolean) {
- var protos = this.protos;
-
- var changes = null;
- var isChanged = false;
- for (var i = 0; i < protos.length; ++i) {
- var proto: ProtoRecord = protos[i];
- var bindingRecord = proto.bindingRecord;
- var directiveRecord = bindingRecord.directiveRecord;
-
- if (this._firstInBinding(proto)) {
- this.firstProtoInCurrentBinding = proto.selfIndex;
- }
-
- if (proto.isLifeCycleRecord()) {
- if (proto.name === "onCheck" && !throwOnChange) {
- this._getDirectiveFor(directiveRecord.directiveIndex).onCheck();
- } else if (proto.name === "onInit" && !throwOnChange && !this.alreadyChecked) {
- this._getDirectiveFor(directiveRecord.directiveIndex).onInit();
- } else if (proto.name === "onChange" && isPresent(changes) && !throwOnChange) {
- this._getDirectiveFor(directiveRecord.directiveIndex).onChange(changes);
- }
-
- } else {
- var change = this._check(proto, throwOnChange, this.values, this.locals);
- if (isPresent(change)) {
- this._updateDirectiveOrElement(change, bindingRecord);
- isChanged = true;
- changes = this._addChange(bindingRecord, change, changes);
- }
- }
-
- if (proto.lastInDirective) {
- changes = null;
- if (isChanged && !bindingRecord.isDefaultChangeDetection()) {
- this._getDetectorFor(directiveRecord.directiveIndex).markAsCheckOnce();
- }
-
- isChanged = false;
- }
- }
-
- this.alreadyChecked = true;
- }
-
- _firstInBinding(r: ProtoRecord): boolean {
- var prev = ChangeDetectionUtil.protoByIndex(this.protos, r.selfIndex - 1);
- return isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
- }
-
- callOnAllChangesDone() {
- super.callOnAllChangesDone();
- var dirs = this.directiveRecords;
- for (var i = dirs.length - 1; i >= 0; --i) {
- var dir = dirs[i];
- if (dir.callOnAllChangesDone) {
- this._getDirectiveFor(dir.directiveIndex).onAllChangesDone();
- }
- }
- }
-
- _updateDirectiveOrElement(change, bindingRecord) {
- if (isBlank(bindingRecord.directiveRecord)) {
- this.dispatcher.notifyOnBinding(bindingRecord, change.currentValue);
- } else {
- var directiveIndex = bindingRecord.directiveRecord.directiveIndex;
- bindingRecord.setter(this._getDirectiveFor(directiveIndex), change.currentValue);
- }
- }
-
- _addChange(bindingRecord: BindingRecord, change, changes) {
- if (bindingRecord.callOnChange()) {
- return super.addChange(changes, change.previousValue, change.currentValue);
- } else {
- return changes;
- }
- }
-
- _getDirectiveFor(directiveIndex) { return this.directives.getDirectiveFor(directiveIndex); }
-
- _getDetectorFor(directiveIndex) { return this.directives.getDetectorFor(directiveIndex); }
-
- _check(proto: ProtoRecord, throwOnChange: boolean, values: any[], locals: Locals): SimpleChange {
- if (proto.isPipeRecord()) {
- return this._pipeCheck(proto, throwOnChange, values);
- } else {
- return this._referenceCheck(proto, throwOnChange, values, locals);
- }
- }
-
- _referenceCheck(proto: ProtoRecord, throwOnChange: boolean, values: any[], locals: Locals) {
- if (this._pureFuncAndArgsDidNotChange(proto)) {
- this._setChanged(proto, false);
- return null;
- }
-
- var currValue = this.observe(this._calculateCurrValue(proto, values, locals), proto.selfIndex);
- if (proto.shouldBeChecked()) {
- var prevValue = this._readSelf(proto, values);
- if (!isSame(prevValue, currValue)) {
- if (proto.lastInBinding) {
- var change = ChangeDetectionUtil.simpleChange(prevValue, currValue);
- if (throwOnChange) this.throwOnChangeError(prevValue, currValue);
-
- this._writeSelf(proto, currValue, values);
- this._setChanged(proto, true);
- return change;
- } else {
- this._writeSelf(proto, currValue, values);
- this._setChanged(proto, true);
- return null;
- }
- } else {
- this._setChanged(proto, false);
- return null;
- }
-
- } else {
- this._writeSelf(proto, currValue, values);
- this._setChanged(proto, true);
- return null;
- }
- }
-
- _calculateCurrValue(proto: ProtoRecord, values: any[], locals: Locals) {
- switch (proto.mode) {
- case RecordType.SELF:
- return this._readContext(proto, values);
-
- case RecordType.CONST:
- return proto.funcOrValue;
-
- case RecordType.PROPERTY_READ:
- var context = this._readContext(proto, values);
- return proto.funcOrValue(context);
-
- case RecordType.SAFE_PROPERTY:
- var context = this._readContext(proto, values);
- return isBlank(context) ? null : proto.funcOrValue(context);
-
- case RecordType.PROPERTY_WRITE:
- var context = this._readContext(proto, values);
- var value = this._readArgs(proto, values)[0];
- proto.funcOrValue(context, value);
- return value;
-
- case RecordType.KEYED_WRITE:
- var context = this._readContext(proto, values);
- var key = this._readArgs(proto, values)[0];
- var value = this._readArgs(proto, values)[1];
- context[key] = value;
- return value;
-
- case RecordType.LOCAL:
- return locals.get(proto.name);
-
- case RecordType.INVOKE_METHOD:
- var context = this._readContext(proto, values);
- var args = this._readArgs(proto, values);
- return proto.funcOrValue(context, args);
-
- case RecordType.SAFE_INVOKE_METHOD:
- var context = this._readContext(proto, values);
- if (isBlank(context)) {
- return null;
- }
- var args = this._readArgs(proto, values);
- return proto.funcOrValue(context, args);
-
- case RecordType.KEYED_READ:
- var arg = this._readArgs(proto, values)[0];
- return this._readContext(proto, values)[arg];
-
- case RecordType.CHAIN:
- var args = this._readArgs(proto, values);
- return args[args.length - 1];
-
- case RecordType.INVOKE_CLOSURE:
- return FunctionWrapper.apply(this._readContext(proto, values),
- this._readArgs(proto, values));
-
- case RecordType.INTERPOLATE:
- case RecordType.PRIMITIVE_OP:
- case RecordType.COLLECTION_LITERAL:
- return FunctionWrapper.apply(proto.funcOrValue, this._readArgs(proto, values));
-
- default:
- throw new BaseException(`Unknown operation ${proto.mode}`);
- }
- }
-
- _pipeCheck(proto: ProtoRecord, throwOnChange: boolean, values: any[]) {
- var context = this._readContext(proto, values);
- var args = this._readArgs(proto, values);
-
- var pipe = this._pipeFor(proto, context);
- var currValue = pipe.transform(context, args);
-
- if (proto.shouldBeChecked()) {
- var prevValue = this._readSelf(proto, values);
- if (!isSame(prevValue, currValue)) {
- currValue = ChangeDetectionUtil.unwrapValue(currValue);
-
- if (proto.lastInBinding) {
- var change = ChangeDetectionUtil.simpleChange(prevValue, currValue);
- if (throwOnChange) this.throwOnChangeError(prevValue, currValue);
-
- this._writeSelf(proto, currValue, values);
- this._setChanged(proto, true);
-
- return change;
-
- } else {
- this._writeSelf(proto, currValue, values);
- this._setChanged(proto, true);
- return null;
- }
- } else {
- this._setChanged(proto, false);
- return null;
- }
- } else {
- this._writeSelf(proto, currValue, values);
- this._setChanged(proto, true);
- return null;
- }
- }
-
- _pipeFor(proto: ProtoRecord, context) {
- var storedPipe = this._readPipe(proto);
- if (isPresent(storedPipe)) return storedPipe;
-
- var pipe = this.pipes.get(proto.name);
- this._writePipe(proto, pipe);
- return pipe;
- }
-
- _readContext(proto: ProtoRecord, values: any[]) {
- if (proto.contextIndex == -1) {
- return this._getDirectiveFor(proto.directiveIndex);
- } else {
- return values[proto.contextIndex];
- }
-
- return values[proto.contextIndex];
- }
-
- _readSelf(proto: ProtoRecord, values: any[]) { return values[proto.selfIndex]; }
-
- _writeSelf(proto: ProtoRecord, value, values: any[]) { values[proto.selfIndex] = value; }
-
- _readPipe(proto: ProtoRecord) { return this.localPipes[proto.selfIndex]; }
-
- _writePipe(proto: ProtoRecord, value) { this.localPipes[proto.selfIndex] = value; }
-
- _setChanged(proto: ProtoRecord, value: boolean) {
- if (proto.argumentToPureFunction) this.changes[proto.selfIndex] = value;
- }
-
- _pureFuncAndArgsDidNotChange(proto: ProtoRecord): boolean {
- return proto.isPureFunction() && !this._argsChanged(proto);
- }
-
- _argsChanged(proto: ProtoRecord): boolean {
- var args = proto.args;
- for (var i = 0; i < args.length; ++i) {
- if (this.changes[args[i]]) {
- return true;
- }
- }
- return false;
- }
-
- _readArgs(proto: ProtoRecord, values: any[]) {
- var res = ListWrapper.createFixedSize(proto.args.length);
- var args = proto.args;
- for (var i = 0; i < args.length; ++i) {
- res[i] = values[args[i]];
- }
- return res;
- }
-}
-
-function isSame(a, b): boolean {
- if (a === b) return true;
- if (a instanceof String && b instanceof String && a == b) return true;
- if ((a !== a) && (b !== b)) return true;
- return false;
-}
diff --git a/modules/angular2/src/change_detection/exceptions.ts b/modules/angular2/src/change_detection/exceptions.ts
deleted file mode 100644
index 520da217eda3..000000000000
--- a/modules/angular2/src/change_detection/exceptions.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import {ProtoRecord} from './proto_record';
-import {BaseException} from "angular2/src/facade/lang";
-
-/**
- * An error thrown if application changes model breaking the top-down data flow.
- *
- * Angular expects that the data flows from top (root) component to child (leaf) components.
- * This is known as directed acyclic graph. This allows Angular to only execute change detection
- * once and prevents loops in change detection data flow.
- *
- * This exception is only thrown in dev mode.
- */
-export class ExpressionChangedAfterItHasBeenCheckedException extends BaseException {
- constructor(proto: ProtoRecord, change: any, context: any) {
- super(`Expression '${proto.expressionAsString}' has changed after it was checked. ` +
- `Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`);
- }
-}
-
-/**
- * Thrown when an expression evaluation raises an exception.
- *
- * This error wraps the original exception, this is done to attach expression location information.
- */
-export class ChangeDetectionError extends BaseException {
- /**
- * Location of the expression.
- */
- location: string;
-
- constructor(proto: ProtoRecord, originalException: any, originalStack: any, context: any) {
- super(`${originalException} in [${proto.expressionAsString}]`, originalException, originalStack,
- context);
- this.location = proto.expressionAsString;
- }
-}
-
-/**
- * Thrown when change detector executes on dehydrated view.
- *
- * This is angular internal error.
- */
-export class DehydratedException extends BaseException {
- constructor() { super('Attempt to detect changes on a dehydrated detector.'); }
-}
diff --git a/modules/angular2/src/change_detection/interfaces.ts b/modules/angular2/src/change_detection/interfaces.ts
deleted file mode 100644
index b5d45ebf3e1b..000000000000
--- a/modules/angular2/src/change_detection/interfaces.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import {List} from 'angular2/src/facade/collection';
-import {CONST} from 'angular2/src/facade/lang';
-import {Locals} from './parser/locals';
-import {BindingRecord} from './binding_record';
-import {DirectiveIndex, DirectiveRecord} from './directive_record';
-import {ChangeDetectorRef} from './change_detector_ref';
-
-/**
- * Interface used by Angular to control the change detection strategy for an application.
- *
- * Angular implements the following change detection strategies by default:
- *
- * - {@link DynamicChangeDetection}: slower, but does not require `eval()`.
- * - {@link JitChangeDetection}: faster, but requires `eval()`.
- *
- * In JavaScript, you should always use `JitChangeDetection`, unless you are in an environment that
- *has
- * [CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP), such as a Chrome Extension.
- *
- * In Dart, use `DynamicChangeDetection` during development. The Angular transformer generates an
- *analog to the
- * `JitChangeDetection` strategy at compile time.
- *
- *
- * See: {@link DynamicChangeDetection}, {@link JitChangeDetection},
- * {@link PreGeneratedChangeDetection}
- *
- * # Example
- * ```javascript
- * bootstrap(MyApp, [bind(ChangeDetection).toClass(DynamicChangeDetection)]);
- * ```
- */
-@CONST()
-export class ChangeDetection {
- createProtoChangeDetector(definition: ChangeDetectorDefinition): ProtoChangeDetector {
- return null;
- }
-}
-
-export class DebugContext {
- constructor(public element: any, public componentElement: any, public directive: any,
- public context: any, public locals: any, public injector: any) {}
-}
-
-export interface ChangeDispatcher {
- getDebugContext(elementIndex: number, directiveIndex: DirectiveIndex): DebugContext;
- notifyOnBinding(bindingRecord: BindingRecord, value: any): void;
- notifyOnAllChangesDone(): void;
-}
-
-export interface ChangeDetector {
- parent: ChangeDetector;
- mode: string;
- ref: ChangeDetectorRef;
-
- addChild(cd: ChangeDetector): void;
- addShadowDomChild(cd: ChangeDetector): void;
- removeChild(cd: ChangeDetector): void;
- removeShadowDomChild(cd: ChangeDetector): void;
- remove(): void;
- hydrate(context: any, locals: Locals, directives: any, pipes: any): void;
- dehydrate(): void;
- markPathToRootAsCheckOnce(): void;
-
- handleEvent(eventName: string, elIndex: number, locals: Locals);
- detectChanges(): void;
- checkNoChanges(): void;
-}
-
-export interface ProtoChangeDetector { instantiate(dispatcher: ChangeDispatcher): ChangeDetector; }
-
-export class ChangeDetectorDefinition {
- constructor(public id: string, public strategy: string, public variableNames: List,
- public bindingRecords: BindingRecord[], public eventRecords: BindingRecord[],
- public directiveRecords: DirectiveRecord[], public generateCheckNoChanges: boolean) {}
-}
diff --git a/modules/angular2/src/change_detection/jit_proto_change_detector.ts b/modules/angular2/src/change_detection/jit_proto_change_detector.ts
deleted file mode 100644
index df009b5cc430..000000000000
--- a/modules/angular2/src/change_detection/jit_proto_change_detector.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import {ListWrapper} from 'angular2/src/facade/collection';
-
-import {ProtoChangeDetector, ChangeDetector, ChangeDetectorDefinition} from './interfaces';
-import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
-
-import {coalesce} from './coalesce';
-import {createPropertyRecords, createEventRecords} from './proto_change_detector';
-
-export class JitProtoChangeDetector implements ProtoChangeDetector {
- _factory: Function;
-
- constructor(private definition: ChangeDetectorDefinition) {
- this._factory = this._createFactory(definition);
- }
-
- static isSupported(): boolean { return true; }
-
- instantiate(dispatcher: any): ChangeDetector { return this._factory(dispatcher); }
-
- _createFactory(definition: ChangeDetectorDefinition) {
- var propertyBindingRecords = createPropertyRecords(definition);
- var eventBindingRecords = createEventRecords(definition);
- return new ChangeDetectorJITGenerator(
- definition.id, definition.strategy, propertyBindingRecords, eventBindingRecords,
- this.definition.directiveRecords, this.definition.generateCheckNoChanges)
- .generate();
- }
-}
diff --git a/modules/angular2/src/change_detection/observable_facade.dart b/modules/angular2/src/change_detection/observable_facade.dart
deleted file mode 100644
index 4f48465cebcb..000000000000
--- a/modules/angular2/src/change_detection/observable_facade.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-import 'package:observe/observe.dart';
-
-bool isObservable(value) => value is Observable;
\ No newline at end of file
diff --git a/modules/angular2/src/change_detection/pipe_lifecycle_reflector.dart b/modules/angular2/src/change_detection/pipe_lifecycle_reflector.dart
deleted file mode 100644
index 9fb8545f7104..000000000000
--- a/modules/angular2/src/change_detection/pipe_lifecycle_reflector.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-library angular2.core.compiler.pipe_lifecycle_reflector;
-
-import 'package:angular2/src/change_detection/pipe_transform.dart';
-
-bool implementsOnDestroy(Object pipe) => pipe is PipeOnDestroy;
diff --git a/modules/angular2/src/change_detection/pipe_lifecycle_reflector.ts b/modules/angular2/src/change_detection/pipe_lifecycle_reflector.ts
deleted file mode 100644
index 6f6863cd3bbe..000000000000
--- a/modules/angular2/src/change_detection/pipe_lifecycle_reflector.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function implementsOnDestroy(pipe: any): boolean {
- return pipe.constructor.prototype.onDestroy;
-}
diff --git a/modules/angular2/src/change_detection/pipe_transform.ts b/modules/angular2/src/change_detection/pipe_transform.ts
deleted file mode 100644
index 557a3cbf2dcc..000000000000
--- a/modules/angular2/src/change_detection/pipe_transform.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import {ABSTRACT, BaseException, CONST, Type} from 'angular2/src/facade/lang';
-
-/**
- * An interface which all pipes must implement.
- *
- * #Example
- *
- * ```
- * class DoublePipe implements PipeTransform {
- * transform(value, args = []) {
- * return `${value}${value}`;
- * }
- * }
- * ```
- */
-export interface PipeTransform { transform(value: any, args: List): any; }
-
-/**
- * An interface that stateful pipes should implement.
- *
- * #Example
- *
- * ```
- * class StatefulPipe implements PipeTransform, PipeOnDestroy {
- * connection;
- *
- * onDestroy() {
- * this.connection.release();
- * }
- *
- * transform(value, args = []) {
- * this.connection = createConnection();
- * // ...
- * return someValue;
- * }
- * }
- * ```
- */
-export interface PipeOnDestroy { onDestroy(): void; }
diff --git a/modules/angular2/src/change_detection/pipes.ts b/modules/angular2/src/change_detection/pipes.ts
deleted file mode 100644
index b9eb15ee0c4e..000000000000
--- a/modules/angular2/src/change_detection/pipes.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import {PipeTransform} from './pipe_transform';
-
-export interface Pipes { get(name: string): PipeTransform; }
\ No newline at end of file
diff --git a/modules/angular2/src/change_detection/pregen_proto_change_detector.dart b/modules/angular2/src/change_detection/pregen_proto_change_detector.dart
deleted file mode 100644
index bdb9a7546dc9..000000000000
--- a/modules/angular2/src/change_detection/pregen_proto_change_detector.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-library angular2.src.change_detection.pregen_proto_change_detector;
-
-import 'package:angular2/src/change_detection/coalesce.dart';
-import 'package:angular2/src/change_detection/directive_record.dart';
-import 'package:angular2/src/change_detection/interfaces.dart';
-import 'package:angular2/src/change_detection/proto_change_detector.dart';
-import 'package:angular2/src/change_detection/proto_record.dart';
-import 'package:angular2/src/facade/lang.dart' show looseIdentical;
-
-export 'dart:core' show List;
-export 'package:angular2/src/change_detection/abstract_change_detector.dart'
- show AbstractChangeDetector;
-export 'package:angular2/src/change_detection/change_detection.dart'
- show preGeneratedProtoDetectors;
-export 'package:angular2/src/change_detection/directive_record.dart'
- show DirectiveIndex, DirectiveRecord;
-export 'package:angular2/src/change_detection/interfaces.dart'
- show ChangeDetector, ChangeDetectorDefinition, ProtoChangeDetector;
-export 'package:angular2/src/change_detection/pipes.dart' show Pipes;
-export 'package:angular2/src/change_detection/proto_record.dart'
- show ProtoRecord;
-export 'package:angular2/src/change_detection/change_detection_util.dart'
- show ChangeDetectionUtil;
-export 'package:angular2/src/facade/lang.dart' show looseIdentical;
-
-typedef ProtoChangeDetector PregenProtoChangeDetectorFactory(
- ChangeDetectorDefinition definition);
-
-typedef ChangeDetector InstantiateMethod(dynamic dispatcher,
- List protoRecords, List directiveRecords);
-
-/// Implementation of [ProtoChangeDetector] for use by pre-generated change
-/// detectors in Angular 2 Dart.
-/// Classes generated by the `TemplateCompiler` use this. The `export`s above
-/// allow the generated code to `import` a single library and get all
-/// dependencies.
-class PregenProtoChangeDetector extends ProtoChangeDetector {
- /// The [ChangeDetectorDefinition#id]. Strictly informational.
- final String id;
-
- /// Closure used to generate an actual [ChangeDetector].
- final InstantiateMethod _instantiateMethod;
-
- // [ChangeDetector] dependencies.
- final List _protoRecords;
- final List _directiveRecords;
-
- /// Internal ctor.
- PregenProtoChangeDetector._(this.id, this._instantiateMethod,
- this._protoRecords, this._directiveRecords);
-
- static bool isSupported() => true;
-
- factory PregenProtoChangeDetector(
- InstantiateMethod instantiateMethod, ChangeDetectorDefinition def) {
- // TODO(kegluneq): Pre-generate these (#2067).
- var recordBuilder = new ProtoRecordBuilder();
- def.bindingRecords.forEach((b) {
- recordBuilder.add(b, def.variableNames);
- });
- var protoRecords = coalesce(recordBuilder.records);
- return new PregenProtoChangeDetector._(
- def.id, instantiateMethod, protoRecords, def.directiveRecords);
- }
-
- @override
- instantiate(dynamic dispatcher) =>
- _instantiateMethod(dispatcher, _protoRecords, _directiveRecords);
-}
-
-/// Provided as an optimization to cut down on '!' characters in generated
-/// change detectors. See https://github.com/angular/angular/issues/3248 for
-/// for details.
-bool looseNotIdentical(a, b) => !looseIdentical(a, b);
diff --git a/modules/angular2/src/change_detection/pregen_proto_change_detector.ts b/modules/angular2/src/change_detection/pregen_proto_change_detector.ts
deleted file mode 100644
index 52df89cb0242..000000000000
--- a/modules/angular2/src/change_detection/pregen_proto_change_detector.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import {BaseException} from 'angular2/src/facade/lang';
-
-import {ProtoChangeDetector, ChangeDetector} from './interfaces';
-import {coalesce} from './coalesce';
-
-export {Function as PregenProtoChangeDetectorFactory};
-
-export class PregenProtoChangeDetector implements ProtoChangeDetector {
- static isSupported(): boolean { return false; }
-
- instantiate(dispatcher: any): ChangeDetector {
- throw new BaseException('Pregen change detection not supported in Js');
- }
-}
diff --git a/modules/angular2/src/change_detection/proto_change_detector.ts b/modules/angular2/src/change_detection/proto_change_detector.ts
deleted file mode 100644
index 28e8c246c3b5..000000000000
--- a/modules/angular2/src/change_detection/proto_change_detector.ts
+++ /dev/null
@@ -1,428 +0,0 @@
-import {BaseException, Type, isBlank, isPresent, isString} from 'angular2/src/facade/lang';
-import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
-
-import {
- PropertyRead,
- PropertyWrite,
- KeyedWrite,
- AST,
- ASTWithSource,
- AstVisitor,
- Binary,
- Chain,
- Conditional,
- If,
- BindingPipe,
- FunctionCall,
- ImplicitReceiver,
- Interpolation,
- KeyedRead,
- LiteralArray,
- LiteralMap,
- LiteralPrimitive,
- MethodCall,
- PrefixNot,
- SafePropertyRead,
- SafeMethodCall
-} from './parser/ast';
-
-import {ChangeDetector, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces';
-import {ChangeDetectionUtil} from './change_detection_util';
-import {DynamicChangeDetector} from './dynamic_change_detector';
-import {BindingRecord} from './binding_record';
-import {DirectiveRecord, DirectiveIndex} from './directive_record';
-import {EventBinding} from './event_binding';
-
-import {coalesce} from './coalesce';
-import {ProtoRecord, RecordType} from './proto_record';
-
-export class DynamicProtoChangeDetector implements ProtoChangeDetector {
- _propertyBindingRecords: ProtoRecord[];
- _eventBindingRecords: EventBinding[];
-
- constructor(private definition: ChangeDetectorDefinition) {
- this._propertyBindingRecords = createPropertyRecords(definition);
- this._eventBindingRecords = createEventRecords(definition);
- }
-
- instantiate(dispatcher: any): ChangeDetector {
- return new DynamicChangeDetector(this.definition.id, this.definition.strategy, dispatcher,
- this._propertyBindingRecords, this._eventBindingRecords,
- this.definition.directiveRecords);
- }
-}
-
-export function createPropertyRecords(definition: ChangeDetectorDefinition): ProtoRecord[] {
- var recordBuilder = new ProtoRecordBuilder();
- ListWrapper.forEach(definition.bindingRecords,
- (b) => { recordBuilder.add(b, definition.variableNames); });
- return coalesce(recordBuilder.records);
-}
-
-export function createEventRecords(definition: ChangeDetectorDefinition): EventBinding[] {
- // TODO: vsavkin: remove $event when the compiler handles render-side variables properly
- var varNames = ListWrapper.concat(['$event'], definition.variableNames);
- return definition.eventRecords.map(er => {
- var records = _ConvertAstIntoProtoRecords.create(er, varNames);
- var dirIndex = er.implicitReceiver instanceof DirectiveIndex ? er.implicitReceiver : null;
- return new EventBinding(er.eventName, er.elementIndex, dirIndex, records);
- });
-}
-
-export class ProtoRecordBuilder {
- records: List;
-
- constructor() { this.records = []; }
-
- add(b: BindingRecord, variableNames: List = null) {
- var oldLast = ListWrapper.last(this.records);
- if (isPresent(oldLast) && oldLast.bindingRecord.directiveRecord == b.directiveRecord) {
- oldLast.lastInDirective = false;
- }
- var numberOfRecordsBefore = this.records.length;
- this._appendRecords(b, variableNames);
- var newLast = ListWrapper.last(this.records);
- if (isPresent(newLast) && newLast !== oldLast) {
- newLast.lastInBinding = true;
- newLast.lastInDirective = true;
- this._setArgumentToPureFunction(numberOfRecordsBefore);
- }
- }
-
- _setArgumentToPureFunction(startIndex: number): void {
- for (var i = startIndex; i < this.records.length; ++i) {
- var rec = this.records[i];
- if (rec.isPureFunction()) {
- rec.args.forEach(recordIndex => this.records[recordIndex - 1].argumentToPureFunction =
- true);
- }
- }
- }
-
- _appendRecords(b: BindingRecord, variableNames: List) {
- if (b.isDirectiveLifecycle()) {
- this.records.push(new ProtoRecord(RecordType.DIRECTIVE_LIFECYCLE, b.lifecycleEvent, null, [],
- [], -1, null, this.records.length + 1, b, null, false,
- false, false, false));
- } else {
- _ConvertAstIntoProtoRecords.append(this.records, b, variableNames);
- }
- }
-}
-
-class _ConvertAstIntoProtoRecords implements AstVisitor {
- constructor(private _records: List, private _bindingRecord: BindingRecord,
- private _expressionAsString: string, private _variableNames: List) {}
-
- static append(records: List, b: BindingRecord, variableNames: List) {
- var c = new _ConvertAstIntoProtoRecords(records, b, b.ast.toString(), variableNames);
- b.ast.visit(c);
- }
-
- static create(b: BindingRecord, variableNames: List): ProtoRecord[] {
- var rec = [];
- _ConvertAstIntoProtoRecords.append(rec, b, variableNames);
- rec[rec.length - 1].lastInBinding = true;
- return rec;
- }
-
- visitImplicitReceiver(ast: ImplicitReceiver): any { return this._bindingRecord.implicitReceiver; }
-
- visitInterpolation(ast: Interpolation): number {
- var args = this._visitAll(ast.expressions);
- return this._addRecord(RecordType.INTERPOLATE, "interpolate", _interpolationFn(ast.strings),
- args, ast.strings, 0);
- }
-
- visitLiteralPrimitive(ast: LiteralPrimitive): number {
- return this._addRecord(RecordType.CONST, "literal", ast.value, [], null, 0);
- }
-
- visitPropertyRead(ast: PropertyRead): number {
- var receiver = ast.receiver.visit(this);
- if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name) &&
- ast.receiver instanceof ImplicitReceiver) {
- return this._addRecord(RecordType.LOCAL, ast.name, ast.name, [], null, receiver);
- } else {
- return this._addRecord(RecordType.PROPERTY_READ, ast.name, ast.getter, [], null, receiver);
- }
- }
-
- visitPropertyWrite(ast: PropertyWrite): number {
- if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name) &&
- ast.receiver instanceof ImplicitReceiver) {
- throw new BaseException(`Cannot reassign a variable binding ${ast.name}`);
- } else {
- var receiver = ast.receiver.visit(this);
- var value = ast.value.visit(this);
- return this._addRecord(RecordType.PROPERTY_WRITE, ast.name, ast.setter, [value], null,
- receiver);
- }
- }
-
- visitKeyedWrite(ast: KeyedWrite): number {
- var obj = ast.obj.visit(this);
- var key = ast.key.visit(this);
- var value = ast.value.visit(this);
- return this._addRecord(RecordType.KEYED_WRITE, null, null, [key, value], null, obj);
- }
-
- visitSafePropertyRead(ast: SafePropertyRead): number {
- var receiver = ast.receiver.visit(this);
- return this._addRecord(RecordType.SAFE_PROPERTY, ast.name, ast.getter, [], null, receiver);
- }
-
- visitMethodCall(ast: MethodCall): number {
- var receiver = ast.receiver.visit(this);
- var args = this._visitAll(ast.args);
- if (isPresent(this._variableNames) && ListWrapper.contains(this._variableNames, ast.name)) {
- var target = this._addRecord(RecordType.LOCAL, ast.name, ast.name, [], null, receiver);
- return this._addRecord(RecordType.INVOKE_CLOSURE, "closure", null, args, null, target);
- } else {
- return this._addRecord(RecordType.INVOKE_METHOD, ast.name, ast.fn, args, null, receiver);
- }
- }
-
- visitSafeMethodCall(ast: SafeMethodCall): number {
- var receiver = ast.receiver.visit(this);
- var args = this._visitAll(ast.args);
- return this._addRecord(RecordType.SAFE_INVOKE_METHOD, ast.name, ast.fn, args, null, receiver);
- }
-
- visitFunctionCall(ast: FunctionCall): number {
- var target = ast.target.visit(this);
- var args = this._visitAll(ast.args);
- return this._addRecord(RecordType.INVOKE_CLOSURE, "closure", null, args, null, target);
- }
-
- visitLiteralArray(ast: LiteralArray): number {
- var primitiveName = `arrayFn${ast.expressions.length}`;
- return this._addRecord(RecordType.COLLECTION_LITERAL, primitiveName,
- _arrayFn(ast.expressions.length), this._visitAll(ast.expressions), null,
- 0);
- }
-
- visitLiteralMap(ast: LiteralMap): number {
- return this._addRecord(RecordType.COLLECTION_LITERAL, _mapPrimitiveName(ast.keys),
- ChangeDetectionUtil.mapFn(ast.keys), this._visitAll(ast.values), null,
- 0);
- }
-
- visitBinary(ast: Binary): number {
- var left = ast.left.visit(this);
- var right = ast.right.visit(this);
- return this._addRecord(RecordType.PRIMITIVE_OP, _operationToPrimitiveName(ast.operation),
- _operationToFunction(ast.operation), [left, right], null, 0);
- }
-
- visitPrefixNot(ast: PrefixNot): number {
- var exp = ast.expression.visit(this);
- return this._addRecord(RecordType.PRIMITIVE_OP, "operation_negate",
- ChangeDetectionUtil.operation_negate, [exp], null, 0);
- }
-
- visitConditional(ast: Conditional): number {
- var c = ast.condition.visit(this);
- var t = ast.trueExp.visit(this);
- var f = ast.falseExp.visit(this);
- return this._addRecord(RecordType.PRIMITIVE_OP, "cond", ChangeDetectionUtil.cond, [c, t, f],
- null, 0);
- }
-
- visitPipe(ast: BindingPipe): number {
- var value = ast.exp.visit(this);
- var args = this._visitAll(ast.args);
- return this._addRecord(RecordType.PIPE, ast.name, ast.name, args, null, value);
- }
-
- visitKeyedRead(ast: KeyedRead): number {
- var obj = ast.obj.visit(this);
- var key = ast.key.visit(this);
- return this._addRecord(RecordType.KEYED_READ, "keyedAccess", ChangeDetectionUtil.keyedAccess,
- [key], null, obj);
- }
-
- visitChain(ast: Chain): number {
- var args = ast.expressions.map(e => e.visit(this));
- return this._addRecord(RecordType.CHAIN, "chain", null, args, null, 0);
- }
-
- visitIf(ast: If) { throw new BaseException('Not supported'); }
-
- _visitAll(asts: List) {
- var res = ListWrapper.createFixedSize(asts.length);
- for (var i = 0; i < asts.length; ++i) {
- res[i] = asts[i].visit(this);
- }
- return res;
- }
-
- _addRecord(type, name, funcOrValue, args, fixedArgs, context) {
- var selfIndex = this._records.length + 1;
- if (context instanceof DirectiveIndex) {
- this._records.push(new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context,
- selfIndex, this._bindingRecord, this._expressionAsString,
- false, false, false, false));
- } else {
- this._records.push(new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null,
- selfIndex, this._bindingRecord, this._expressionAsString,
- false, false, false, false));
- }
- return selfIndex;
- }
-}
-
-
-function _arrayFn(length: number): Function {
- switch (length) {
- case 0:
- return ChangeDetectionUtil.arrayFn0;
- case 1:
- return ChangeDetectionUtil.arrayFn1;
- case 2:
- return ChangeDetectionUtil.arrayFn2;
- case 3:
- return ChangeDetectionUtil.arrayFn3;
- case 4:
- return ChangeDetectionUtil.arrayFn4;
- case 5:
- return ChangeDetectionUtil.arrayFn5;
- case 6:
- return ChangeDetectionUtil.arrayFn6;
- case 7:
- return ChangeDetectionUtil.arrayFn7;
- case 8:
- return ChangeDetectionUtil.arrayFn8;
- case 9:
- return ChangeDetectionUtil.arrayFn9;
- default:
- throw new BaseException(`Does not support literal maps with more than 9 elements`);
- }
-}
-
-function _mapPrimitiveName(keys: List) {
- var stringifiedKeys =
- ListWrapper.join(ListWrapper.map(keys, (k) => isString(k) ? `"${k}"` : `${k}`), ", ");
- return `mapFn([${stringifiedKeys}])`;
-}
-
-function _operationToPrimitiveName(operation: string): string {
- switch (operation) {
- case '+':
- return "operation_add";
- case '-':
- return "operation_subtract";
- case '*':
- return "operation_multiply";
- case '/':
- return "operation_divide";
- case '%':
- return "operation_remainder";
- case '==':
- return "operation_equals";
- case '!=':
- return "operation_not_equals";
- case '===':
- return "operation_identical";
- case '!==':
- return "operation_not_identical";
- case '<':
- return "operation_less_then";
- case '>':
- return "operation_greater_then";
- case '<=':
- return "operation_less_or_equals_then";
- case '>=':
- return "operation_greater_or_equals_then";
- case '&&':
- return "operation_logical_and";
- case '||':
- return "operation_logical_or";
- default:
- throw new BaseException(`Unsupported operation ${operation}`);
- }
-}
-
-function _operationToFunction(operation: string): Function {
- switch (operation) {
- case '+':
- return ChangeDetectionUtil.operation_add;
- case '-':
- return ChangeDetectionUtil.operation_subtract;
- case '*':
- return ChangeDetectionUtil.operation_multiply;
- case '/':
- return ChangeDetectionUtil.operation_divide;
- case '%':
- return ChangeDetectionUtil.operation_remainder;
- case '==':
- return ChangeDetectionUtil.operation_equals;
- case '!=':
- return ChangeDetectionUtil.operation_not_equals;
- case '===':
- return ChangeDetectionUtil.operation_identical;
- case '!==':
- return ChangeDetectionUtil.operation_not_identical;
- case '<':
- return ChangeDetectionUtil.operation_less_then;
- case '>':
- return ChangeDetectionUtil.operation_greater_then;
- case '<=':
- return ChangeDetectionUtil.operation_less_or_equals_then;
- case '>=':
- return ChangeDetectionUtil.operation_greater_or_equals_then;
- case '&&':
- return ChangeDetectionUtil.operation_logical_and;
- case '||':
- return ChangeDetectionUtil.operation_logical_or;
- default:
- throw new BaseException(`Unsupported operation ${operation}`);
- }
-}
-
-function s(v): string {
- return isPresent(v) ? `${v}` : '';
-}
-
-function _interpolationFn(strings: List) {
- var length = strings.length;
- var c0 = length > 0 ? strings[0] : null;
- var c1 = length > 1 ? strings[1] : null;
- var c2 = length > 2 ? strings[2] : null;
- var c3 = length > 3 ? strings[3] : null;
- var c4 = length > 4 ? strings[4] : null;
- var c5 = length > 5 ? strings[5] : null;
- var c6 = length > 6 ? strings[6] : null;
- var c7 = length > 7 ? strings[7] : null;
- var c8 = length > 8 ? strings[8] : null;
- var c9 = length > 9 ? strings[9] : null;
- switch (length - 1) {
- case 1:
- return (a1) => c0 + s(a1) + c1;
- case 2:
- return (a1, a2) => c0 + s(a1) + c1 + s(a2) + c2;
- case 3:
- return (a1, a2, a3) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3;
- case 4:
- return (a1, a2, a3, a4) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4;
- case 5:
- return (a1, a2, a3, a4, a5) =>
- c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5;
- case 6:
- return (a1, a2, a3, a4, a5, a6) =>
- c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6;
- case 7:
- return (a1, a2, a3, a4, a5, a6, a7) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) +
- c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7;
- case 8:
- return (a1, a2, a3, a4, a5, a6, a7, a8) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) +
- c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7 + s(a8) +
- c8;
- case 9:
- return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 +
- s(a4) + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) +
- c7 + s(a8) + c8 + s(a9) + c9;
- default:
- throw new BaseException(`Does not support more than 9 expressions`);
- }
-}
diff --git a/modules/angular2/src/change_detection/proto_record.ts b/modules/angular2/src/change_detection/proto_record.ts
deleted file mode 100644
index 4f53cb385227..000000000000
--- a/modules/angular2/src/change_detection/proto_record.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import {List} from 'angular2/src/facade/collection';
-import {BindingRecord} from './binding_record';
-import {DirectiveIndex} from './directive_record';
-
-export enum RecordType {
- SELF,
- CONST,
- PRIMITIVE_OP,
- PROPERTY_READ,
- PROPERTY_WRITE,
- LOCAL,
- INVOKE_METHOD,
- INVOKE_CLOSURE,
- KEYED_READ,
- KEYED_WRITE,
- PIPE,
- INTERPOLATE,
- SAFE_PROPERTY,
- COLLECTION_LITERAL,
- SAFE_INVOKE_METHOD,
- DIRECTIVE_LIFECYCLE,
- CHAIN
-}
-
-export class ProtoRecord {
- constructor(public mode: RecordType, public name: string, public funcOrValue,
- public args: List, public fixedArgs: List, public contextIndex: number,
- public directiveIndex: DirectiveIndex, public selfIndex: number,
- public bindingRecord: BindingRecord, public expressionAsString: string,
- public lastInBinding: boolean, public lastInDirective: boolean,
- public argumentToPureFunction: boolean, public referencedBySelf: boolean) {}
-
- isPureFunction(): boolean {
- return this.mode === RecordType.INTERPOLATE || this.mode === RecordType.COLLECTION_LITERAL;
- }
-
- isUsedByOtherRecord(): boolean { return !this.lastInBinding || this.referencedBySelf; }
-
- shouldBeChecked(): boolean {
- return this.argumentToPureFunction || this.lastInBinding || this.isPureFunction();
- }
-
- isPipeRecord(): boolean { return this.mode === RecordType.PIPE; }
-
- isLifeCycleRecord(): boolean { return this.mode === RecordType.DIRECTIVE_LIFECYCLE; }
-}
diff --git a/modules/angular2/src/common/common_directives.ts b/modules/angular2/src/common/common_directives.ts
new file mode 100644
index 000000000000..089395fe2acd
--- /dev/null
+++ b/modules/angular2/src/common/common_directives.ts
@@ -0,0 +1,49 @@
+import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
+
+import {FORM_DIRECTIVES} from './forms';
+import {CORE_DIRECTIVES} from './directives';
+
+/**
+ * A collection of Angular core directives that are likely to be used in each and every Angular
+ * application. This includes core directives (e.g., NgIf and NgFor), and forms directives (e.g.,
+ * NgModel).
+ *
+ * This collection can be used to quickly enumerate all the built-in directives in the `directives`
+ * property of the `@Component` or `@View` decorators.
+ *
+ * ### Example
+ *
+ * Instead of writing:
+ *
+ * ```typescript
+ * import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm} from
+ * 'angular2/common';
+ * import {OtherDirective} from './myDirectives';
+ *
+ * @Component({
+ * selector: 'my-component',
+ * templateUrl: 'myComponent.html',
+ * directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm,
+ * OtherDirective]
+ * })
+ * export class MyComponent {
+ * ...
+ * }
+ * ```
+ * one could import all the common directives at once:
+ *
+ * ```typescript
+ * import {COMMON_DIRECTIVES} from 'angular2/common';
+ * import {OtherDirective} from './myDirectives';
+ *
+ * @Component({
+ * selector: 'my-component',
+ * templateUrl: 'myComponent.html',
+ * directives: [COMMON_DIRECTIVES, OtherDirective]
+ * })
+ * export class MyComponent {
+ * ...
+ * }
+ * ```
+ */
+export const COMMON_DIRECTIVES: Type[][] = CONST_EXPR([CORE_DIRECTIVES, FORM_DIRECTIVES]);
diff --git a/modules/angular2/src/common/directives.ts b/modules/angular2/src/common/directives.ts
new file mode 100644
index 000000000000..c777bae2dd3b
--- /dev/null
+++ b/modules/angular2/src/common/directives.ts
@@ -0,0 +1,12 @@
+/**
+ * @module
+ * @description
+ * Common directives shipped with Angular.
+ */
+export {NgClass} from './directives/ng_class';
+export {NgFor} from './directives/ng_for';
+export {NgIf} from './directives/ng_if';
+export {NgStyle} from './directives/ng_style';
+export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
+export * from './directives/observable_list_diff';
+export {CORE_DIRECTIVES} from './directives/core_directives';
\ No newline at end of file
diff --git a/modules/angular2/src/common/directives/core_directives.ts b/modules/angular2/src/common/directives/core_directives.ts
new file mode 100644
index 000000000000..61f9e776127e
--- /dev/null
+++ b/modules/angular2/src/common/directives/core_directives.ts
@@ -0,0 +1,49 @@
+import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
+import {NgClass} from './ng_class';
+import {NgFor} from './ng_for';
+import {NgIf} from './ng_if';
+import {NgStyle} from './ng_style';
+import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
+
+/**
+ * A collection of Angular core directives that are likely to be used in each and every Angular
+ * application.
+ *
+ * This collection can be used to quickly enumerate all the built-in directives in the `directives`
+ * property of the `@View` annotation.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/yakGwpCdUkg0qfzX5m8g?p=preview))
+ *
+ * Instead of writing:
+ *
+ * ```typescript
+ * import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from 'angular2/common';
+ * import {OtherDirective} from './myDirectives';
+ *
+ * @Component({
+ * selector: 'my-component',
+ * templateUrl: 'myComponent.html',
+ * directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, OtherDirective]
+ * })
+ * export class MyComponent {
+ * ...
+ * }
+ * ```
+ * one could import all the core directives at once:
+ *
+ * ```typescript
+ * import {CORE_DIRECTIVES} from 'angular2/common';
+ * import {OtherDirective} from './myDirectives';
+ *
+ * @Component({
+ * selector: 'my-component',
+ * templateUrl: 'myComponent.html',
+ * directives: [CORE_DIRECTIVES, OtherDirective]
+ * })
+ * export class MyComponent {
+ * ...
+ * }
+ * ```
+ */
+export const CORE_DIRECTIVES: Type[] =
+ CONST_EXPR([NgClass, NgFor, NgIf, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]);
diff --git a/modules/angular2/src/common/directives/ng_class.ts b/modules/angular2/src/common/directives/ng_class.ts
new file mode 100644
index 000000000000..cae1ca01e6ca
--- /dev/null
+++ b/modules/angular2/src/common/directives/ng_class.ts
@@ -0,0 +1,179 @@
+import {isPresent, isString, StringWrapper, isBlank, isArray} from 'angular2/src/facade/lang';
+import {
+ DoCheck,
+ OnDestroy,
+ Directive,
+ ElementRef,
+ IterableDiffer,
+ IterableDiffers,
+ KeyValueDiffer,
+ KeyValueDiffers,
+ Renderer
+} from 'angular2/core';
+import {StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collection';
+
+/**
+ * The `NgClass` directive conditionally adds and removes CSS classes on an HTML element based on
+ * an expression's evaluation result.
+ *
+ * The result of an expression evaluation is interpreted differently depending on type of
+ * the expression evaluation result:
+ * - `string` - all the CSS classes listed in a string (space delimited) are added
+ * - `Array` - all the CSS classes (Array elements) are added
+ * - `Object` - each key corresponds to a CSS class name while values are interpreted as expressions
+ * evaluating to `Boolean`. If a given expression evaluates to `true` a corresponding CSS class
+ * is added - otherwise it is removed.
+ *
+ * While the `NgClass` directive can interpret expressions evaluating to `string`, `Array`
+ * or `Object`, the `Object`-based version is the most often used and has an advantage of keeping
+ * all the CSS class names in a template.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/a4YdtmWywhJ33uqfpPPn?p=preview)):
+ *
+ * ```
+ * import {Component} from 'angular2/core';
+ * import {NgClass} from 'angular2/common';
+ *
+ * @Component({
+ * selector: 'toggle-button',
+ * inputs: ['isDisabled'],
+ * template: `
+ *
+ * Click me!
+ *
`,
+ * styles: [`
+ * .button {
+ * width: 120px;
+ * border: medium solid black;
+ * }
+ *
+ * .active {
+ * background-color: red;
+ * }
+ *
+ * .disabled {
+ * color: gray;
+ * border: medium solid gray;
+ * }
+ * `]
+ * directives: [NgClass]
+ * })
+ * class ToggleButton {
+ * isOn = false;
+ * isDisabled = false;
+ *
+ * toggle(newState) {
+ * if (!this.isDisabled) {
+ * this.isOn = newState;
+ * }
+ * }
+ * }
+ * ```
+ */
+@Directive({selector: '[ngClass]', inputs: ['rawClass: ngClass', 'initialClasses: class']})
+export class NgClass implements DoCheck, OnDestroy {
+ private _differ: any;
+ private _mode: string;
+ private _initialClasses = [];
+ private _rawClass;
+
+ constructor(private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
+ private _ngEl: ElementRef, private _renderer: Renderer) {}
+
+ set initialClasses(v) {
+ this._applyInitialClasses(true);
+ this._initialClasses = isPresent(v) && isString(v) ? v.split(' ') : [];
+ this._applyInitialClasses(false);
+ this._applyClasses(this._rawClass, false);
+ }
+
+ set rawClass(v) {
+ this._cleanupClasses(this._rawClass);
+
+ if (isString(v)) {
+ v = v.split(' ');
+ }
+
+ this._rawClass = v;
+ if (isPresent(v)) {
+ if (isListLikeIterable(v)) {
+ this._differ = this._iterableDiffers.find(v).create(null);
+ this._mode = 'iterable';
+ } else {
+ this._differ = this._keyValueDiffers.find(v).create(null);
+ this._mode = 'keyValue';
+ }
+ } else {
+ this._differ = null;
+ }
+ }
+
+ ngDoCheck(): void {
+ if (isPresent(this._differ)) {
+ var changes = this._differ.diff(this._rawClass);
+ if (isPresent(changes)) {
+ if (this._mode == 'iterable') {
+ this._applyIterableChanges(changes);
+ } else {
+ this._applyKeyValueChanges(changes);
+ }
+ }
+ }
+ }
+
+ ngOnDestroy(): void { this._cleanupClasses(this._rawClass); }
+
+ private _cleanupClasses(rawClassVal): void {
+ this._applyClasses(rawClassVal, true);
+ this._applyInitialClasses(false);
+ }
+
+ private _applyKeyValueChanges(changes: any): void {
+ changes.forEachAddedItem((record) => { this._toggleClass(record.key, record.currentValue); });
+ changes.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); });
+ changes.forEachRemovedItem((record) => {
+ if (record.previousValue) {
+ this._toggleClass(record.key, false);
+ }
+ });
+ }
+
+ private _applyIterableChanges(changes: any): void {
+ changes.forEachAddedItem((record) => { this._toggleClass(record.item, true); });
+ changes.forEachRemovedItem((record) => { this._toggleClass(record.item, false); });
+ }
+
+ private _applyInitialClasses(isCleanup: boolean) {
+ this._initialClasses.forEach(className => this._toggleClass(className, !isCleanup));
+ }
+
+ private _applyClasses(rawClassVal: string[] | Set| {[key: string]: string},
+ isCleanup: boolean) {
+ if (isPresent(rawClassVal)) {
+ if (isArray(rawClassVal)) {
+ (rawClassVal).forEach(className => this._toggleClass(className, !isCleanup));
+ } else if (rawClassVal instanceof Set) {
+ (>rawClassVal).forEach(className => this._toggleClass(className, !isCleanup));
+ } else {
+ StringMapWrapper.forEach(<{[k: string]: string}>rawClassVal, (expVal, className) => {
+ if (expVal) this._toggleClass(className, !isCleanup);
+ });
+ }
+ }
+ }
+
+ private _toggleClass(className: string, enabled): void {
+ className = className.trim();
+ if (className.length > 0) {
+ if (className.indexOf(' ') > -1) {
+ var classes = className.split(/\s+/g);
+ for (var i = 0, len = classes.length; i < len; i++) {
+ this._renderer.setElementClass(this._ngEl.nativeElement, classes[i], enabled);
+ }
+ } else {
+ this._renderer.setElementClass(this._ngEl.nativeElement, className, enabled);
+ }
+ }
+ }
+}
diff --git a/modules/angular2/src/common/directives/ng_for.ts b/modules/angular2/src/common/directives/ng_for.ts
new file mode 100644
index 000000000000..ec768c498194
--- /dev/null
+++ b/modules/angular2/src/common/directives/ng_for.ts
@@ -0,0 +1,163 @@
+import {
+ DoCheck,
+ Directive,
+ ChangeDetectorRef,
+ IterableDiffer,
+ IterableDiffers,
+ ViewContainerRef,
+ TemplateRef,
+ EmbeddedViewRef
+} from 'angular2/core';
+import {isPresent, isBlank} from 'angular2/src/facade/lang';
+
+/**
+ * The `NgFor` directive instantiates a template once per item from an iterable. The context for
+ * each instantiated template inherits from the outer context with the given loop variable set
+ * to the current item from the iterable.
+ *
+ * # Local Variables
+ *
+ * `NgFor` provides several exported values that can be aliased to local variables:
+ *
+ * * `index` will be set to the current loop iteration for each template context.
+ * * `last` will be set to a boolean value indicating whether the item is the last one in the
+ * iteration.
+ * * `even` will be set to a boolean value indicating whether this item has an even index.
+ * * `odd` will be set to a boolean value indicating whether this item has an odd index.
+ *
+ * # Change Propagation
+ *
+ * When the contents of the iterator changes, `NgFor` makes the corresponding changes to the DOM:
+ *
+ * * When an item is added, a new instance of the template is added to the DOM.
+ * * When an item is removed, its template instance is removed from the DOM.
+ * * When items are reordered, their respective templates are reordered in the DOM.
+ * * Otherwise, the DOM element for that item will remain the same.
+ *
+ * Angular uses object identity to track insertions and deletions within the iterator and reproduce
+ * those changes in the DOM. This has important implications for animations and any stateful
+ * controls
+ * (such as ` ` elements which accept user input) that are present. Inserted rows can be
+ * animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state such
+ * as user input.
+ *
+ * It is possible for the identities of elements in the iterator to change while the data does not.
+ * This can happen, for example, if the iterator produced from an RPC to the server, and that
+ * RPC is re-run. Even if the data hasn't changed, the second response will produce objects with
+ * different identities, and Angular will tear down the entire DOM and rebuild it (as if all old
+ * elements were deleted and all new elements inserted). This is an expensive operation and should
+ * be avoided if possible.
+ *
+ * # Syntax
+ *
+ * - `... `
+ * - `... `
+ * - `... `
+ *
+ * ### Example
+ *
+ * See a [live demo](http://plnkr.co/edit/KVuXxDp0qinGDyo307QW?p=preview) for a more detailed
+ * example.
+ */
+@Directive({selector: '[ngFor][ngForOf]', inputs: ['ngForOf', 'ngForTemplate']})
+export class NgFor implements DoCheck {
+ /** @internal */
+ _ngForOf: any;
+ private _differ: IterableDiffer;
+
+ constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef,
+ private _iterableDiffers: IterableDiffers, private _cdr: ChangeDetectorRef) {}
+
+ set ngForOf(value: any) {
+ this._ngForOf = value;
+ if (isBlank(this._differ) && isPresent(value)) {
+ this._differ = this._iterableDiffers.find(value).create(this._cdr);
+ }
+ }
+
+ set ngForTemplate(value: TemplateRef) {
+ if (isPresent(value)) {
+ this._templateRef = value;
+ }
+ }
+
+ ngDoCheck() {
+ if (isPresent(this._differ)) {
+ var changes = this._differ.diff(this._ngForOf);
+ if (isPresent(changes)) this._applyChanges(changes);
+ }
+ }
+
+ private _applyChanges(changes) {
+ // TODO(rado): check if change detection can produce a change record that is
+ // easier to consume than current.
+ var recordViewTuples = [];
+ changes.forEachRemovedItem((removedRecord) =>
+ recordViewTuples.push(new RecordViewTuple(removedRecord, null)));
+
+ changes.forEachMovedItem((movedRecord) =>
+ recordViewTuples.push(new RecordViewTuple(movedRecord, null)));
+
+ var insertTuples = this._bulkRemove(recordViewTuples);
+
+ changes.forEachAddedItem((addedRecord) =>
+ insertTuples.push(new RecordViewTuple(addedRecord, null)));
+
+ this._bulkInsert(insertTuples);
+
+ for (var i = 0; i < insertTuples.length; i++) {
+ this._perViewChange(insertTuples[i].view, insertTuples[i].record);
+ }
+
+ for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
+ var viewRef = this._viewContainer.get(i);
+ viewRef.setLocal('last', i === ilen - 1);
+ }
+ }
+
+ private _perViewChange(view, record) {
+ view.setLocal('\$implicit', record.item);
+ view.setLocal('index', record.currentIndex);
+ view.setLocal('even', (record.currentIndex % 2 == 0));
+ view.setLocal('odd', (record.currentIndex % 2 == 1));
+ }
+
+ private _bulkRemove(tuples: RecordViewTuple[]): RecordViewTuple[] {
+ tuples.sort((a, b) => a.record.previousIndex - b.record.previousIndex);
+ var movedTuples = [];
+ for (var i = tuples.length - 1; i >= 0; i--) {
+ var tuple = tuples[i];
+ // separate moved views from removed views.
+ if (isPresent(tuple.record.currentIndex)) {
+ tuple.view = this._viewContainer.detach(tuple.record.previousIndex);
+ movedTuples.push(tuple);
+ } else {
+ this._viewContainer.remove(tuple.record.previousIndex);
+ }
+ }
+ return movedTuples;
+ }
+
+ private _bulkInsert(tuples: RecordViewTuple[]): RecordViewTuple[] {
+ tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex);
+ for (var i = 0; i < tuples.length; i++) {
+ var tuple = tuples[i];
+ if (isPresent(tuple.view)) {
+ this._viewContainer.insert(tuple.view, tuple.record.currentIndex);
+ } else {
+ tuple.view =
+ this._viewContainer.createEmbeddedView(this._templateRef, tuple.record.currentIndex);
+ }
+ }
+ return tuples;
+ }
+}
+
+class RecordViewTuple {
+ view: EmbeddedViewRef;
+ record: any;
+ constructor(record, view) {
+ this.record = record;
+ this.view = view;
+ }
+}
diff --git a/modules/angular2/src/common/directives/ng_if.ts b/modules/angular2/src/common/directives/ng_if.ts
new file mode 100644
index 000000000000..f4bbfea1c484
--- /dev/null
+++ b/modules/angular2/src/common/directives/ng_if.ts
@@ -0,0 +1,41 @@
+import {Directive, ViewContainerRef, TemplateRef} from 'angular2/core';
+import {isBlank} from 'angular2/src/facade/lang';
+
+/**
+ * Removes or recreates a portion of the DOM tree based on an {expression}.
+ *
+ * If the expression assigned to `ngIf` evaluates to a false value then the element
+ * is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)):
+ *
+ * ```
+ * 0" class="error">
+ *
+ * {{errorCount}} errors detected
+ *
+ * ```
+ *
+ * ### Syntax
+ *
+ * - `...
`
+ * - `...
`
+ * - `...
`
+ */
+@Directive({selector: '[ngIf]', inputs: ['ngIf']})
+export class NgIf {
+ private _prevCondition: boolean = null;
+
+ constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef) {}
+
+ set ngIf(newCondition /* boolean */) {
+ if (newCondition && (isBlank(this._prevCondition) || !this._prevCondition)) {
+ this._prevCondition = true;
+ this._viewContainer.createEmbeddedView(this._templateRef);
+ } else if (!newCondition && (isBlank(this._prevCondition) || this._prevCondition)) {
+ this._prevCondition = false;
+ this._viewContainer.clear();
+ }
+ }
+}
diff --git a/modules/angular2/src/common/directives/ng_style.ts b/modules/angular2/src/common/directives/ng_style.ts
new file mode 100644
index 000000000000..99d658a0f903
--- /dev/null
+++ b/modules/angular2/src/common/directives/ng_style.ts
@@ -0,0 +1,97 @@
+import {
+ DoCheck,
+ KeyValueDiffer,
+ KeyValueDiffers,
+ ElementRef,
+ Directive,
+ Renderer
+} from 'angular2/core';
+import {isPresent, isBlank, print} from 'angular2/src/facade/lang';
+
+/**
+ * The `NgStyle` directive changes styles based on a result of expression evaluation.
+ *
+ * An expression assigned to the `ngStyle` property must evaluate to an object and the
+ * corresponding element styles are updated based on changes to this object. Style names to update
+ * are taken from the object's keys, and values - from the corresponding object's values.
+ *
+ * ### Syntax
+ *
+ * - `
`
+ * - `
` - here the `styleExp` must evaluate to an object
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/YamGS6GkUh9GqWNQhCyM?p=preview)):
+ *
+ * ```
+ * import {Component} from 'angular2/core';
+ * import {NgStyle} from 'angular2/common';
+ *
+ * @Component({
+ * selector: 'ngStyle-example',
+ * template: `
+ *
+ * Change style of this text!
+ *
+ *
+ *
+ *
+ * Italic:
+ * Bold:
+ * Size:
+ * `,
+ * directives: [NgStyle]
+ * })
+ * export class NgStyleExample {
+ * style = 'normal';
+ * weight = 'normal';
+ * size = '20px';
+ *
+ * changeStyle($event: any) {
+ * this.style = $event.target.checked ? 'italic' : 'normal';
+ * }
+ *
+ * changeWeight($event: any) {
+ * this.weight = $event.target.checked ? 'bold' : 'normal';
+ * }
+ * }
+ * ```
+ *
+ * In this example the `font-style`, `font-size` and `font-weight` styles will be updated
+ * based on the `style` property's value changes.
+ */
+@Directive({selector: '[ngStyle]', inputs: ['rawStyle: ngStyle']})
+export class NgStyle implements DoCheck {
+ /** @internal */
+ _rawStyle;
+ /** @internal */
+ _differ: KeyValueDiffer;
+
+ constructor(private _differs: KeyValueDiffers, private _ngEl: ElementRef,
+ private _renderer: Renderer) {}
+
+ set rawStyle(v) {
+ this._rawStyle = v;
+ if (isBlank(this._differ) && isPresent(v)) {
+ this._differ = this._differs.find(this._rawStyle).create(null);
+ }
+ }
+
+ ngDoCheck() {
+ if (isPresent(this._differ)) {
+ var changes = this._differ.diff(this._rawStyle);
+ if (isPresent(changes)) {
+ this._applyChanges(changes);
+ }
+ }
+ }
+
+ private _applyChanges(changes: any): void {
+ changes.forEachAddedItem((record) => { this._setStyle(record.key, record.currentValue); });
+ changes.forEachChangedItem((record) => { this._setStyle(record.key, record.currentValue); });
+ changes.forEachRemovedItem((record) => { this._setStyle(record.key, null); });
+ }
+
+ private _setStyle(name: string, val: string): void {
+ this._renderer.setElementStyle(this._ngEl.nativeElement, name, val);
+ }
+}
diff --git a/modules/angular2/src/common/directives/ng_switch.ts b/modules/angular2/src/common/directives/ng_switch.ts
new file mode 100644
index 000000000000..469a9dbca23f
--- /dev/null
+++ b/modules/angular2/src/common/directives/ng_switch.ts
@@ -0,0 +1,203 @@
+import {Directive, Host, ViewContainerRef, TemplateRef} from 'angular2/core';
+import {isPresent, isBlank, normalizeBlank, CONST_EXPR} from 'angular2/src/facade/lang';
+import {ListWrapper, Map} from 'angular2/src/facade/collection';
+
+const _WHEN_DEFAULT = CONST_EXPR(new Object());
+
+/** @internal */
+export class SwitchView {
+ constructor(private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef) {}
+
+ create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
+
+ destroy(): void { this._viewContainerRef.clear(); }
+}
+
+/**
+ * Adds or removes DOM sub-trees when their match expressions match the switch expression.
+ *
+ * Elements within `NgSwitch` but without `NgSwitchWhen` or `NgSwitchDefault` directives will be
+ * preserved at the location as specified in the template.
+ *
+ * `NgSwitch` simply inserts nested elements based on which match expression matches the value
+ * obtained from the evaluated switch expression. In other words, you define a container element
+ * (where you place the directive with a switch expression on the
+ * **`[ngSwitch]="..."` attribute**), define any inner elements inside of the directive and
+ * place a `[ngSwitchWhen]` attribute per element.
+ *
+ * The `ngSwitchWhen` property is used to inform `NgSwitch` which element to display when the
+ * expression is evaluated. If a matching expression is not found via a `ngSwitchWhen` property
+ * then an element with the `ngSwitchDefault` attribute is displayed.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/DQMTII95CbuqWrl3lYAs?p=preview))
+ *
+ * ```typescript
+ * @Component({selector: 'app'})
+ * @View({
+ * template: `
+ * Value = {{value}}
+ * Increment
+ *
+ *
+ *
increment to start
+ *
0, increment again
+ *
1, increment again
+ *
2, stop incrementing
+ *
> 2, STOP!
+ *
+ *
+ *
+ *
+ *
+ * increment to start
+ * 0, increment again
+ * 1, increment again
+ * 2, stop incrementing
+ * > 2, STOP!
+ *
+ * `,
+ * directives: [NgSwitch, NgSwitchWhen, NgSwitchDefault]
+ * })
+ * export class App {
+ * value = 'init';
+ *
+ * inc() {
+ * this.value = this.value === 'init' ? 0 : this.value + 1;
+ * }
+ * }
+ *
+ * bootstrap(App).catch(err => console.error(err));
+ * ```
+ */
+@Directive({selector: '[ngSwitch]', inputs: ['ngSwitch']})
+export class NgSwitch {
+ private _switchValue: any;
+ private _useDefault: boolean = false;
+ private _valueViews = new Map();
+ private _activeViews: SwitchView[] = [];
+
+ set ngSwitch(value) {
+ // Empty the currently active ViewContainers
+ this._emptyAllActiveViews();
+
+ // Add the ViewContainers matching the value (with a fallback to default)
+ this._useDefault = false;
+ var views = this._valueViews.get(value);
+ if (isBlank(views)) {
+ this._useDefault = true;
+ views = normalizeBlank(this._valueViews.get(_WHEN_DEFAULT));
+ }
+ this._activateViews(views);
+
+ this._switchValue = value;
+ }
+
+ /** @internal */
+ _onWhenValueChanged(oldWhen, newWhen, view: SwitchView): void {
+ this._deregisterView(oldWhen, view);
+ this._registerView(newWhen, view);
+
+ if (oldWhen === this._switchValue) {
+ view.destroy();
+ ListWrapper.remove(this._activeViews, view);
+ } else if (newWhen === this._switchValue) {
+ if (this._useDefault) {
+ this._useDefault = false;
+ this._emptyAllActiveViews();
+ }
+ view.create();
+ this._activeViews.push(view);
+ }
+
+ // Switch to default when there is no more active ViewContainers
+ if (this._activeViews.length === 0 && !this._useDefault) {
+ this._useDefault = true;
+ this._activateViews(this._valueViews.get(_WHEN_DEFAULT));
+ }
+ }
+
+ /** @internal */
+ _emptyAllActiveViews(): void {
+ var activeContainers = this._activeViews;
+ for (var i = 0; i < activeContainers.length; i++) {
+ activeContainers[i].destroy();
+ }
+ this._activeViews = [];
+ }
+
+ /** @internal */
+ _activateViews(views: SwitchView[]): void {
+ // TODO(vicb): assert(this._activeViews.length === 0);
+ if (isPresent(views)) {
+ for (var i = 0; i < views.length; i++) {
+ views[i].create();
+ }
+ this._activeViews = views;
+ }
+ }
+
+ /** @internal */
+ _registerView(value, view: SwitchView): void {
+ var views = this._valueViews.get(value);
+ if (isBlank(views)) {
+ views = [];
+ this._valueViews.set(value, views);
+ }
+ views.push(view);
+ }
+
+ /** @internal */
+ _deregisterView(value, view: SwitchView): void {
+ // `_WHEN_DEFAULT` is used a marker for non-registered whens
+ if (value === _WHEN_DEFAULT) return;
+ var views = this._valueViews.get(value);
+ if (views.length == 1) {
+ this._valueViews.delete(value);
+ } else {
+ ListWrapper.remove(views, view);
+ }
+ }
+}
+
+/**
+ * Insert the sub-tree when the `ngSwitchWhen` expression evaluates to the same value as the
+ * enclosing switch expression.
+ *
+ * If multiple match expression match the switch expression value, all of them are displayed.
+ *
+ * See {@link NgSwitch} for more details and example.
+ */
+@Directive({selector: '[ngSwitchWhen]', inputs: ['ngSwitchWhen']})
+export class NgSwitchWhen {
+ // `_WHEN_DEFAULT` is used as a marker for a not yet initialized value
+ /** @internal */
+ _value: any = _WHEN_DEFAULT;
+ /** @internal */
+ _view: SwitchView;
+ private _switch: NgSwitch;
+
+ constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
+ @Host() ngSwitch: NgSwitch) {
+ this._switch = ngSwitch;
+ this._view = new SwitchView(viewContainer, templateRef);
+ }
+
+ set ngSwitchWhen(value) {
+ this._switch._onWhenValueChanged(this._value, value, this._view);
+ this._value = value;
+ }
+}
+
+/**
+ * Default case statements are displayed when no match expression matches the switch expression
+ * value.
+ *
+ * See {@link NgSwitch} for more details and example.
+ */
+@Directive({selector: '[ngSwitchDefault]'})
+export class NgSwitchDefault {
+ constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
+ @Host() sswitch: NgSwitch) {
+ sswitch._registerView(_WHEN_DEFAULT, new SwitchView(viewContainer, templateRef));
+ }
+}
diff --git a/modules/angular2/src/directives/observable_list_diff.dart b/modules/angular2/src/common/directives/observable_list_diff.dart
similarity index 90%
rename from modules/angular2/src/directives/observable_list_diff.dart
rename to modules/angular2/src/common/directives/observable_list_diff.dart
index c9bdc1b81277..cca7057facaf 100644
--- a/modules/angular2/src/directives/observable_list_diff.dart
+++ b/modules/angular2/src/common/directives/observable_list_diff.dart
@@ -1,8 +1,8 @@
library angular2.directives.observable_list_iterable_diff;
import 'package:observe/observe.dart' show ObservableList;
-import 'package:angular2/change_detection.dart';
-import 'package:angular2/src/change_detection/differs/default_iterable_differ.dart';
+import 'package:angular2/core.dart';
+import 'package:angular2/src/core/change_detection/differs/default_iterable_differ.dart';
import 'dart:async';
class ObservableListDiff extends DefaultIterableDiffer {
@@ -35,7 +35,7 @@ class ObservableListDiff extends DefaultIterableDiffer {
if (_subscription != null) _subscription.cancel();
_subscription = collection.changes.listen((_) {
_updated = true;
- _ref.requestCheck();
+ _ref.markForCheck();
});
_updated = false;
return super.diff(collection);
diff --git a/modules/angular2/src/common/directives/observable_list_diff.ts b/modules/angular2/src/common/directives/observable_list_diff.ts
new file mode 100644
index 000000000000..ee99cf404765
--- /dev/null
+++ b/modules/angular2/src/common/directives/observable_list_diff.ts
@@ -0,0 +1,10 @@
+// TS does not have Observables
+
+// I need to be here to make TypeScript think this is a module.
+import {} from 'angular2/src/facade/lang';
+
+/**
+ * This module exists in Dart, but not in Typescript. This exported symbol
+ * is only here to help Typescript think this is a module.
+ */
+export var workaround_empty_observable_list_diff: any;
diff --git a/modules/angular2/src/common/forms.ts b/modules/angular2/src/common/forms.ts
new file mode 100644
index 000000000000..e18ef145e8b3
--- /dev/null
+++ b/modules/angular2/src/common/forms.ts
@@ -0,0 +1,42 @@
+/**
+ * @module
+ * @description
+ * This module is used for handling user input, by defining and building a {@link ControlGroup} that
+ * consists of
+ * {@link Control} objects, and mapping them onto the DOM. {@link Control} objects can then be used
+ * to read information
+ * from the form DOM elements.
+ *
+ * This module is not included in the `angular2` module; you must import the forms module
+ * explicitly.
+ *
+ */
+export {AbstractControl, Control, ControlGroup, ControlArray} from './forms/model';
+
+export {AbstractControlDirective} from './forms/directives/abstract_control_directive';
+export {Form} from './forms/directives/form_interface';
+export {ControlContainer} from './forms/directives/control_container';
+export {NgControlName} from './forms/directives/ng_control_name';
+export {NgFormControl} from './forms/directives/ng_form_control';
+export {NgModel} from './forms/directives/ng_model';
+export {NgControl} from './forms/directives/ng_control';
+export {NgControlGroup} from './forms/directives/ng_control_group';
+export {NgFormModel} from './forms/directives/ng_form_model';
+export {NgForm} from './forms/directives/ng_form';
+export {ControlValueAccessor, NG_VALUE_ACCESSOR} from './forms/directives/control_value_accessor';
+export {DefaultValueAccessor} from './forms/directives/default_value_accessor';
+export {NgControlStatus} from './forms/directives/ng_control_status';
+export {CheckboxControlValueAccessor} from './forms/directives/checkbox_value_accessor';
+export {
+ NgSelectOption,
+ SelectControlValueAccessor
+} from './forms/directives/select_control_value_accessor';
+export {FORM_DIRECTIVES} from './forms/directives';
+export {NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validators} from './forms/validators';
+export {
+ RequiredValidator,
+ MinLengthValidator,
+ MaxLengthValidator,
+ Validator
+} from './forms/directives/validators';
+export {FormBuilder, FORM_PROVIDERS, FORM_BINDINGS} from './forms/form_builder';
\ No newline at end of file
diff --git a/modules/angular2/src/common/forms/directives.ts b/modules/angular2/src/common/forms/directives.ts
new file mode 100644
index 000000000000..0a3bcbbd5ae1
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives.ts
@@ -0,0 +1,71 @@
+import {Type, CONST_EXPR} from 'angular2/src/facade/lang';
+import {NgControlName} from './directives/ng_control_name';
+import {NgFormControl} from './directives/ng_form_control';
+import {NgModel} from './directives/ng_model';
+import {NgControlGroup} from './directives/ng_control_group';
+import {NgFormModel} from './directives/ng_form_model';
+import {NgForm} from './directives/ng_form';
+import {DefaultValueAccessor} from './directives/default_value_accessor';
+import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
+import {NumberValueAccessor} from './directives/number_value_accessor';
+import {NgControlStatus} from './directives/ng_control_status';
+import {
+ SelectControlValueAccessor,
+ NgSelectOption
+} from './directives/select_control_value_accessor';
+import {RequiredValidator, MinLengthValidator, MaxLengthValidator} from './directives/validators';
+
+export {NgControlName} from './directives/ng_control_name';
+export {NgFormControl} from './directives/ng_form_control';
+export {NgModel} from './directives/ng_model';
+export {NgControlGroup} from './directives/ng_control_group';
+export {NgFormModel} from './directives/ng_form_model';
+export {NgForm} from './directives/ng_form';
+export {DefaultValueAccessor} from './directives/default_value_accessor';
+export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
+export {NumberValueAccessor} from './directives/number_value_accessor';
+export {NgControlStatus} from './directives/ng_control_status';
+export {
+ SelectControlValueAccessor,
+ NgSelectOption
+} from './directives/select_control_value_accessor';
+export {RequiredValidator, MinLengthValidator, MaxLengthValidator} from './directives/validators';
+export {NgControl} from './directives/ng_control';
+export {ControlValueAccessor} from './directives/control_value_accessor';
+
+/**
+ *
+ * A list of all the form directives used as part of a `@View` annotation.
+ *
+ * This is a shorthand for importing them each individually.
+ *
+ * ### Example
+ *
+ * ```typescript
+ * @Component({
+ * selector: 'my-app',
+ * directives: [FORM_DIRECTIVES]
+ * })
+ * class MyApp {}
+ * ```
+ */
+export const FORM_DIRECTIVES: Type[] = CONST_EXPR([
+ NgControlName,
+ NgControlGroup,
+
+ NgFormControl,
+ NgModel,
+ NgFormModel,
+ NgForm,
+
+ NgSelectOption,
+ DefaultValueAccessor,
+ NumberValueAccessor,
+ CheckboxControlValueAccessor,
+ SelectControlValueAccessor,
+ NgControlStatus,
+
+ RequiredValidator,
+ MinLengthValidator,
+ MaxLengthValidator
+]);
diff --git a/modules/angular2/src/common/forms/directives/abstract_control_directive.ts b/modules/angular2/src/common/forms/directives/abstract_control_directive.ts
new file mode 100644
index 000000000000..a31a05ed11a4
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/abstract_control_directive.ts
@@ -0,0 +1,30 @@
+import {AbstractControl} from '../model';
+import {isPresent} from 'angular2/src/facade/lang';
+import {unimplemented} from 'angular2/src/facade/exceptions';
+
+/**
+ * Base class for control directives.
+ *
+ * Only used internally in the forms module.
+ */
+export abstract class AbstractControlDirective {
+ get control(): AbstractControl { return unimplemented(); }
+
+ get value(): any { return isPresent(this.control) ? this.control.value : null; }
+
+ get valid(): boolean { return isPresent(this.control) ? this.control.valid : null; }
+
+ get errors(): {[key: string]: any} {
+ return isPresent(this.control) ? this.control.errors : null;
+ }
+
+ get pristine(): boolean { return isPresent(this.control) ? this.control.pristine : null; }
+
+ get dirty(): boolean { return isPresent(this.control) ? this.control.dirty : null; }
+
+ get touched(): boolean { return isPresent(this.control) ? this.control.touched : null; }
+
+ get untouched(): boolean { return isPresent(this.control) ? this.control.untouched : null; }
+
+ get path(): string[] { return null; }
+}
diff --git a/modules/angular2/src/common/forms/directives/checkbox_value_accessor.ts b/modules/angular2/src/common/forms/directives/checkbox_value_accessor.ts
new file mode 100644
index 000000000000..094326839236
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/checkbox_value_accessor.ts
@@ -0,0 +1,34 @@
+import {Directive, Renderer, ElementRef, Self, forwardRef, Provider} from 'angular2/core';
+
+import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+const CHECKBOX_VALUE_ACCESSOR = CONST_EXPR(new Provider(
+ NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => CheckboxControlValueAccessor), multi: true}));
+
+/**
+ * The accessor for writing a value and listening to changes on a checkbox input element.
+ *
+ * ### Example
+ * ```
+ *
+ * ```
+ */
+@Directive({
+ selector:
+ 'input[type=checkbox][ngControl],input[type=checkbox][ngFormControl],input[type=checkbox][ngModel]',
+ host: {'(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()'},
+ bindings: [CHECKBOX_VALUE_ACCESSOR]
+})
+export class CheckboxControlValueAccessor implements ControlValueAccessor {
+ onChange = (_) => {};
+ onTouched = () => {};
+
+ constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
+
+ writeValue(value: any): void {
+ this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value);
+ }
+ registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
+ registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
+}
diff --git a/modules/angular2/src/common/forms/directives/control_container.ts b/modules/angular2/src/common/forms/directives/control_container.ts
new file mode 100644
index 000000000000..a84ad46430ee
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/control_container.ts
@@ -0,0 +1,21 @@
+import {Form} from './form_interface';
+import {AbstractControlDirective} from './abstract_control_directive';
+
+/**
+ * A directive that contains multiple {@link NgControl}s.
+ *
+ * Only used by the forms module.
+ */
+export class ControlContainer extends AbstractControlDirective {
+ name: string;
+
+ /**
+ * Get the form to which this container belongs.
+ */
+ get formDirective(): Form { return null; }
+
+ /**
+ * Get the path to this container.
+ */
+ get path(): string[] { return null; }
+}
diff --git a/modules/angular2/src/common/forms/directives/control_value_accessor.ts b/modules/angular2/src/common/forms/directives/control_value_accessor.ts
new file mode 100644
index 000000000000..90820f7d7071
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/control_value_accessor.ts
@@ -0,0 +1,34 @@
+import {OpaqueToken} from 'angular2/core';
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+/**
+ * A bridge between a control and a native element.
+ *
+ * A `ControlValueAccessor` abstracts the operations of writing a new value to a
+ * DOM element representing an input control.
+ *
+ * Please see {@link DefaultValueAccessor} for more information.
+ */
+export interface ControlValueAccessor {
+ /**
+ * Write a new value to the element.
+ */
+ writeValue(obj: any): void;
+
+ /**
+ * Set the function to be called when the control receives a change event.
+ */
+ registerOnChange(fn: any): void;
+
+ /**
+ * Set the function to be called when the control receives a touch event.
+ */
+ registerOnTouched(fn: any): void;
+}
+
+/**
+ * Used to provide a {@link ControlValueAccessor} for form controls.
+ *
+ * See {@link DefaultValueAccessor} for how to implement one.
+ */
+export const NG_VALUE_ACCESSOR: OpaqueToken = CONST_EXPR(new OpaqueToken("NgValueAccessor"));
\ No newline at end of file
diff --git a/modules/angular2/src/common/forms/directives/default_value_accessor.ts b/modules/angular2/src/common/forms/directives/default_value_accessor.ts
new file mode 100644
index 000000000000..1cc88993a526
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/default_value_accessor.ts
@@ -0,0 +1,39 @@
+import {Directive, ElementRef, Renderer, Self, forwardRef, Provider} from 'angular2/core';
+import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
+import {isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
+
+const DEFAULT_VALUE_ACCESSOR = CONST_EXPR(new Provider(
+ NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => DefaultValueAccessor), multi: true}));
+
+/**
+ * The default accessor for writing a value and listening to changes that is used by the
+ * {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
+ *
+ * ### Example
+ * ```
+ *
+ * ```
+ */
+@Directive({
+ selector:
+ 'input:not([type=checkbox])[ngControl],textarea[ngControl],input:not([type=checkbox])[ngFormControl],textarea[ngFormControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
+ // TODO: vsavkin replace the above selector with the one below it once
+ // https://github.com/angular/angular/issues/3011 is implemented
+ // selector: '[ngControl],[ngModel],[ngFormControl]',
+ host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
+ bindings: [DEFAULT_VALUE_ACCESSOR]
+})
+export class DefaultValueAccessor implements ControlValueAccessor {
+ onChange = (_) => {};
+ onTouched = () => {};
+
+ constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
+
+ writeValue(value: any): void {
+ var normalizedValue = isBlank(value) ? '' : value;
+ this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
+ }
+
+ registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
+ registerOnTouched(fn: () => void): void { this.onTouched = fn; }
+}
diff --git a/modules/angular2/src/common/forms/directives/form_interface.ts b/modules/angular2/src/common/forms/directives/form_interface.ts
new file mode 100644
index 000000000000..7e3f04651c81
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/form_interface.ts
@@ -0,0 +1,45 @@
+import {NgControl} from './ng_control';
+import {NgControlGroup} from './ng_control_group';
+import {Control, ControlGroup} from '../model';
+
+/**
+ * An interface that {@link NgFormModel} and {@link NgForm} implement.
+ *
+ * Only used by the forms module.
+ */
+export interface Form {
+ /**
+ * Add a control to this form.
+ */
+ addControl(dir: NgControl): void;
+
+ /**
+ * Remove a control from this form.
+ */
+ removeControl(dir: NgControl): void;
+
+ /**
+ * Look up the {@link Control} associated with a particular {@link NgControl}.
+ */
+ getControl(dir: NgControl): Control;
+
+ /**
+ * Add a group of controls to this form.
+ */
+ addControlGroup(dir: NgControlGroup): void;
+
+ /**
+ * Remove a group of controls from this form.
+ */
+ removeControlGroup(dir: NgControlGroup): void;
+
+ /**
+ * Look up the {@link ControlGroup} associated with a particular {@link NgControlGroup}.
+ */
+ getControlGroup(dir: NgControlGroup): ControlGroup;
+
+ /**
+ * Update the model for a particular control with a new value.
+ */
+ updateModel(dir: NgControl, value: any): void;
+}
\ No newline at end of file
diff --git a/modules/angular2/src/common/forms/directives/ng_control.ts b/modules/angular2/src/common/forms/directives/ng_control.ts
new file mode 100644
index 000000000000..b43bff5dc01d
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/ng_control.ts
@@ -0,0 +1,19 @@
+import {ControlValueAccessor} from './control_value_accessor';
+import {AbstractControlDirective} from './abstract_control_directive';
+import {unimplemented} from 'angular2/src/facade/exceptions';
+
+/**
+ * A base class that all control directive extend.
+ * It binds a {@link Control} object to a DOM element.
+ *
+ * Used internally by Angular forms.
+ */
+export abstract class NgControl extends AbstractControlDirective {
+ name: string = null;
+ valueAccessor: ControlValueAccessor = null;
+
+ get validator(): Function { return unimplemented(); }
+ get asyncValidator(): Function { return unimplemented(); }
+
+ abstract viewToModelUpdate(newValue: any): void;
+}
diff --git a/modules/angular2/src/common/forms/directives/ng_control_group.ts b/modules/angular2/src/common/forms/directives/ng_control_group.ts
new file mode 100644
index 000000000000..84d6fa04f4d4
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/ng_control_group.ts
@@ -0,0 +1,112 @@
+import {
+ OnInit,
+ OnDestroy,
+ Directive,
+ Optional,
+ Inject,
+ Host,
+ SkipSelf,
+ forwardRef,
+ Provider,
+ Self
+} from 'angular2/core';
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+
+import {ControlContainer} from './control_container';
+import {controlPath, composeValidators, composeAsyncValidators} from './shared';
+import {ControlGroup} from '../model';
+import {Form} from './form_interface';
+import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
+
+const controlGroupProvider =
+ CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgControlGroup)}));
+
+/**
+ * Creates and binds a control group to a DOM element.
+ *
+ * This directive can only be used as a child of {@link NgForm} or {@link NgFormModel}.
+ *
+ * ### Example ([live demo](http://plnkr.co/edit/7EJ11uGeaggViYM6T5nq?p=preview))
+ *
+ * ```typescript
+ * @Component({
+ * selector: 'my-app',
+ * directives: [FORM_DIRECTIVES],
+ * })
+ * @View({
+ * template: `
+ *
+ *
Angular2 Control & ControlGroup Example
+ *
+ *
+ * `,
+ * directives: [FORM_DIRECTIVES]
+ * })
+ * export class App {
+ * valueOf(cg: NgControlGroup): string {
+ * if (cg.control == null) {
+ * return null;
+ * }
+ * return JSON.stringify(cg.control.value, null, 2);
+ * }
+ * }
+ * ```
+ *
+ * This example declares a control group for a user's name. The value and validation state of
+ * this group can be accessed separately from the overall form.
+ */
+@Directive({
+ selector: '[ngControlGroup]',
+ providers: [controlGroupProvider],
+ inputs: ['name: ngControlGroup'],
+ exportAs: 'ngForm'
+})
+export class NgControlGroup extends ControlContainer implements OnInit,
+ OnDestroy {
+ /** @internal */
+ _parent: ControlContainer;
+
+ constructor(@Host() @SkipSelf() parent: ControlContainer,
+ @Optional() @Self() @Inject(NG_VALIDATORS) private _validators: any[],
+ @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[]) {
+ super();
+ this._parent = parent;
+ }
+
+ ngOnInit(): void { this.formDirective.addControlGroup(this); }
+
+ ngOnDestroy(): void { this.formDirective.removeControlGroup(this); }
+
+ /**
+ * Get the {@link ControlGroup} backing this binding.
+ */
+ get control(): ControlGroup { return this.formDirective.getControlGroup(this); }
+
+ /**
+ * Get the path to this control group.
+ */
+ get path(): string[] { return controlPath(this.name, this._parent); }
+
+ /**
+ * Get the {@link Form} to which this group belongs.
+ */
+ get formDirective(): Form { return this._parent.formDirective; }
+
+ get validator(): Function { return composeValidators(this._validators); }
+
+ get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
+}
diff --git a/modules/angular2/src/common/forms/directives/ng_control_name.ts b/modules/angular2/src/common/forms/directives/ng_control_name.ts
new file mode 100644
index 000000000000..e54c847a0a7e
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/ng_control_name.ts
@@ -0,0 +1,144 @@
+import {CONST_EXPR} from 'angular2/src/facade/lang';
+import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
+
+import {
+ OnChanges,
+ OnDestroy,
+ SimpleChange,
+ Query,
+ Directive,
+ forwardRef,
+ Host,
+ SkipSelf,
+ Provider,
+ Inject,
+ Optional,
+ Self
+} from 'angular2/core';
+
+import {ControlContainer} from './control_container';
+import {NgControl} from './ng_control';
+import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
+import {
+ controlPath,
+ composeValidators,
+ composeAsyncValidators,
+ isPropertyUpdated,
+ selectValueAccessor
+} from './shared';
+import {Control} from '../model';
+import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
+
+
+const controlNameBinding =
+ CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgControlName)}));
+
+/**
+ * Creates and binds a control with a specified name to a DOM element.
+ *
+ * This directive can only be used as a child of {@link NgForm} or {@link NgFormModel}.
+
+ * ### Example
+ *
+ * In this example, we create the login and password controls.
+ * We can work with each control separately: check its validity, get its value, listen to its
+ * changes.
+ *
+ * ```
+ * @Component({
+ * selector: "login-comp",
+ * directives: [FORM_DIRECTIVES],
+ * template: `
+ *
+ * `})
+ * class LoginComp {
+ * onLogIn(value): void {
+ * // value === {login: 'some login', password: 'some password'}
+ * }
+ * }
+ * ```
+ *
+ * We can also use ngModel to bind a domain model to the form.
+ *
+ * ```
+ * @Component({
+ * selector: "login-comp",
+ * directives: [FORM_DIRECTIVES],
+ * template: `
+ *
+ * `})
+ * class LoginComp {
+ * credentials: {login:string, password:string};
+ *
+ * onLogIn(): void {
+ * // this.credentials.login === "some login"
+ * // this.credentials.password === "some password"
+ * }
+ * }
+ * ```
+ */
+@Directive({
+ selector: '[ngControl]',
+ bindings: [controlNameBinding],
+ inputs: ['name: ngControl', 'model: ngModel'],
+ outputs: ['update: ngModelChange'],
+ exportAs: 'ngForm'
+})
+export class NgControlName extends NgControl implements OnChanges,
+ OnDestroy {
+ /** @internal */
+ update = new EventEmitter();
+ model: any;
+ viewModel: any;
+ private _added = false;
+
+ constructor(@Host() @SkipSelf() private _parent: ControlContainer,
+ @Optional() @Self() @Inject(NG_VALIDATORS) private _validators:
+ /* Array */ any[],
+ @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators:
+ /* Array */ any[],
+ @Optional() @Self() @Inject(NG_VALUE_ACCESSOR)
+ valueAccessors: ControlValueAccessor[]) {
+ super();
+ this.valueAccessor = selectValueAccessor(this, valueAccessors);
+ }
+
+ ngOnChanges(changes: {[key: string]: SimpleChange}) {
+ if (!this._added) {
+ this.formDirective.addControl(this);
+ this._added = true;
+ }
+ if (isPropertyUpdated(changes, this.viewModel)) {
+ this.viewModel = this.model;
+ this.formDirective.updateModel(this, this.model);
+ }
+ }
+
+ ngOnDestroy(): void { this.formDirective.removeControl(this); }
+
+ viewToModelUpdate(newValue: any): void {
+ this.viewModel = newValue;
+ ObservableWrapper.callEmit(this.update, newValue);
+ }
+
+ get path(): string[] { return controlPath(this.name, this._parent); }
+
+ get formDirective(): any { return this._parent.formDirective; }
+
+ get validator(): Function { return composeValidators(this._validators); }
+
+ get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
+
+ get control(): Control { return this.formDirective.getControl(this); }
+}
diff --git a/modules/angular2/src/common/forms/directives/ng_control_status.ts b/modules/angular2/src/common/forms/directives/ng_control_status.ts
new file mode 100644
index 000000000000..38b7ccdabb4c
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/ng_control_status.ts
@@ -0,0 +1,43 @@
+import {Directive, Self} from 'angular2/core';
+import {NgControl} from './ng_control';
+import {isBlank, isPresent} from 'angular2/src/facade/lang';
+
+/**
+ * Directive automatically applied to Angular forms that sets CSS classes
+ * based on control status (valid/invalid/dirty/etc).
+ */
+@Directive({
+ selector: '[ngControl],[ngModel],[ngFormControl]',
+ host: {
+ '[class.ng-untouched]': 'ngClassUntouched',
+ '[class.ng-touched]': 'ngClassTouched',
+ '[class.ng-pristine]': 'ngClassPristine',
+ '[class.ng-dirty]': 'ngClassDirty',
+ '[class.ng-valid]': 'ngClassValid',
+ '[class.ng-invalid]': 'ngClassInvalid'
+ }
+})
+export class NgControlStatus {
+ private _cd: NgControl;
+
+ constructor(@Self() cd: NgControl) { this._cd = cd; }
+
+ get ngClassUntouched(): boolean {
+ return isPresent(this._cd.control) ? this._cd.control.untouched : false;
+ }
+ get ngClassTouched(): boolean {
+ return isPresent(this._cd.control) ? this._cd.control.touched : false;
+ }
+ get ngClassPristine(): boolean {
+ return isPresent(this._cd.control) ? this._cd.control.pristine : false;
+ }
+ get ngClassDirty(): boolean {
+ return isPresent(this._cd.control) ? this._cd.control.dirty : false;
+ }
+ get ngClassValid(): boolean {
+ return isPresent(this._cd.control) ? this._cd.control.valid : false;
+ }
+ get ngClassInvalid(): boolean {
+ return isPresent(this._cd.control) ? !this._cd.control.valid : false;
+ }
+}
diff --git a/modules/angular2/src/common/forms/directives/ng_form.ts b/modules/angular2/src/common/forms/directives/ng_form.ts
new file mode 100644
index 000000000000..639bbf4a58c8
--- /dev/null
+++ b/modules/angular2/src/common/forms/directives/ng_form.ts
@@ -0,0 +1,171 @@
+import {
+ PromiseWrapper,
+ ObservableWrapper,
+ EventEmitter,
+ PromiseCompleter
+} from 'angular2/src/facade/async';
+import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
+import {isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
+import {Directive, forwardRef, Provider, Optional, Inject, Self} from 'angular2/core';
+import {NgControl} from './ng_control';
+import {Form} from './form_interface';
+import {NgControlGroup} from './ng_control_group';
+import {ControlContainer} from './control_container';
+import {AbstractControl, ControlGroup, Control} from '../model';
+import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared';
+import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
+
+const formDirectiveProvider =
+ CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgForm)}));
+
+/**
+ * If `NgForm` is bound in a component, `