refactor(render): ts’ify render api

This commit is contained in:
Tobias Bosch 2015-05-18 11:57:20 -07:00
parent bd8724e652
commit 1beadb8607
56 changed files with 938 additions and 948 deletions

View File

@ -2,12 +2,17 @@
* This file contains declarations of global symbols we reference in our code * This file contains declarations of global symbols we reference in our code
*/ */
/// <reference path="typings/hammerjs/hammerjs"/>
/// <reference path="typings/zone/zone.d.ts"/>
declare var assert: any; declare var assert: any;
declare var global: Window; declare var global: Window;
type int = number; type int = number;
interface List<T> extends Array<T> {} interface List<T> extends Array<T> {}
interface StringMap<K,V> extends Object {}
interface Window { interface Window {
Object: typeof Object; Object: typeof Object;
Array: typeof Array; Array: typeof Array;
@ -20,4 +25,6 @@ interface Window {
assert: typeof assert; assert: typeof assert;
gc(): void; gc(): void;
Reflect: any; Reflect: any;
zone: Zone;
Hammer: HammerStatic;
} }

View File

@ -6,6 +6,7 @@ import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding
import {ElementBinder} from './element_binder'; import {ElementBinder} from './element_binder';
import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang'; import {IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import * as renderApi from 'angular2/src/render/api'; import * as renderApi from 'angular2/src/render/api';
import {EventDispatcher} from 'angular2/src/render/api';
export class AppViewContainer { export class AppViewContainer {
views: List<AppView>; views: List<AppView>;
@ -21,8 +22,7 @@ export class AppViewContainer {
* *
*/ */
@IMPLEMENTS(ChangeDispatcher) @IMPLEMENTS(ChangeDispatcher)
// TODO(tbosch): this is not supported in dart2js (no '.' is allowed) @IMPLEMENTS(EventDispatcher)
// @IMPLEMENTS(renderApi.EventDispatcher)
export class AppView { export class AppView {
render:renderApi.RenderViewRef; render:renderApi.RenderViewRef;
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector /// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector

View File

@ -1,17 +0,0 @@
// TODO(vicb): implement this class properly
// The current stub implementation is only here to please cjs tests
export class NgZone {
constructor({enableLongStackTrace}) {
}
initCallbacks({onTurnStart, onTurnDone, onScheduleMicrotask, onErrorHandler} = {}) {
}
run(fn) {
return fn();
}
runOutsideAngular(fn) {
return fn();
}
}

View File

@ -19,12 +19,12 @@ export class NgZone {
// onTurnDone hook at the end of the current VM turn. // onTurnDone hook at the end of the current VM turn.
_innerZone; _innerZone;
_onTurnStart:Function; _onTurnStart: () => void;
_onTurnDone:Function; _onTurnDone: () => void;
_onErrorHandler:Function; _onErrorHandler: (error, stack) => void;
// Number of microtasks pending from _innerZone (& descendants) // Number of microtasks pending from _innerZone (& descendants)
_pendingMicrotask: number; _pendingMicrotasks: number;
// Whether some code has been executed in the _innerZone (& descendants) in the current turn // Whether some code has been executed in the _innerZone (& descendants) in the current turn
_hasExecutedCodeInInnerZone: boolean; _hasExecutedCodeInInnerZone: boolean;
// run() call depth in _mountZone. 0 at the end of a macrotask // run() call depth in _mountZone. 0 at the end of a macrotask
@ -33,6 +33,10 @@ export class NgZone {
// }); // });
_nestedRun: number; _nestedRun: number;
// TODO(vicb): implement this class properly for node.js environment
// This disabled flag is only here to please cjs tests
_disabled: boolean;
/** /**
* Associates with this * Associates with this
* *
@ -51,18 +55,30 @@ export class NgZone {
this._hasExecutedCodeInInnerZone = false; this._hasExecutedCodeInInnerZone = false;
this._nestedRun = 0; this._nestedRun = 0;
if (global.zone) {
this._disabled = false;
this._mountZone = global.zone; this._mountZone = global.zone;
this._innerZone = this._createInnerZone(this._mountZone, enableLongStackTrace) this._innerZone = this._createInnerZone(this._mountZone, enableLongStackTrace)
} else {
this._disabled = true;
this._mountZone = null;
}
} }
/** /**
* Initializes the zone hooks. * Initializes the zone hooks.
* *
* @param {Function} onTurnStart called before code executes in the inner zone for each VM turn * @param {() => void} onTurnStart called before code executes in the inner zone for each VM turn
* @param {Function} onTurnDone called at the end of a VM turn if code has executed in the inner zone * @param {() => void} onTurnDone called at the end of a VM turn if code has executed in the inner
* @param {Function} onErrorHandler called when an exception is thrown by a macro or micro task * zone
* @param {(error, stack) => void} onErrorHandler called when an exception is thrown by a macro or
* micro task
*/ */
initCallbacks({onTurnStart, onTurnDone, onErrorHandler} = {}) { initCallbacks({onTurnStart, onTurnDone, onErrorHandler}: {
onTurnStart?: () => void,
onTurnDone?: () => void,
onErrorHandler?: (error, stack) => void
} = {}) {
this._onTurnStart = normalizeBlank(onTurnStart); this._onTurnStart = normalizeBlank(onTurnStart);
this._onTurnDone = normalizeBlank(onTurnDone); this._onTurnDone = normalizeBlank(onTurnDone);
this._onErrorHandler = normalizeBlank(onErrorHandler); this._onErrorHandler = normalizeBlank(onErrorHandler);
@ -78,13 +94,18 @@ export class NgZone {
* var zone: NgZone = [ref to the application zone]; * var zone: NgZone = [ref to the application zone];
* *
* zone.run(() => { * zone.run(() => {
* // the change detection will run after this function and the microtasks it enqueues have executed. * // the change detection will run after this function and the microtasks it enqueues have
* executed.
* }); * });
* ``` * ```
*/ */
run(fn) { run(fn) {
if (this._disabled) {
return fn();
} else {
return this._innerZone.run(fn); return this._innerZone.run(fn);
} }
}
/** /**
* Runs `fn` in the outer zone and returns whatever it returns. * Runs `fn` in the outer zone and returns whatever it returns.
@ -103,29 +124,27 @@ export class NgZone {
* ``` * ```
*/ */
runOutsideAngular(fn) { runOutsideAngular(fn) {
if (this._disabled) {
return fn();
} else {
return this._mountZone.run(fn); return this._mountZone.run(fn);
} }
}
_createInnerZone(zone, enableLongStackTrace) { _createInnerZone(zone, enableLongStackTrace) {
var ngZone = this; var ngZone = this;
var errorHandling; var errorHandling;
if (enableLongStackTrace) { if (enableLongStackTrace) {
errorHandling = StringMapWrapper.merge(Zone.longStackTraceZone, { errorHandling = StringMapWrapper.merge(Zone.longStackTraceZone,
onError: function (e) { {onError: function(e) { ngZone._onError(this, e) }});
ngZone._onError(this, e)
}
});
} else { } else {
errorHandling = { errorHandling = {
onError: function (e) { onError: function(e) { ngZone._onError(this, e) }
ngZone._onError(this, e)
}
}; };
} }
return zone return zone.fork(errorHandling)
.fork(errorHandling)
.fork({ .fork({
'$run': function(parentRun) { '$run': function(parentRun) {
return function() { return function() {
@ -140,8 +159,10 @@ export class NgZone {
return parentRun.apply(this, arguments); return parentRun.apply(this, arguments);
} finally { } finally {
ngZone._nestedRun--; ngZone._nestedRun--;
// If there are no more pending microtasks, we are at the end of a VM turn (or in onTurnStart) // If there are no more pending microtasks, we are at the end of a VM turn (or in
// _nestedRun will be 0 at the end of a macrotasks (it could be > 0 when there are nested calls // onTurnStart)
// _nestedRun will be 0 at the end of a macrotasks (it could be > 0 when there are
// nested calls
// to run()). // to run()).
if (ngZone._pendingMicrotasks == 0 && ngZone._nestedRun == 0) { if (ngZone._pendingMicrotasks == 0 && ngZone._nestedRun == 0) {
if (ngZone._onTurnDone && ngZone._hasExecutedCodeInInnerZone) { if (ngZone._onTurnDone && ngZone._hasExecutedCodeInInnerZone) {

View File

@ -273,7 +273,7 @@ defaultDoc() {
getBoundingClientRect(el) { getBoundingClientRect(el) {
return el.getBoundingClientRect(); return el.getBoundingClientRect();
} }
getTitle() { getTitle(): string {
return document.title; return document.title;
} }
setTitle(newTitle: string) { setTitle(newTitle: string) {

View File

@ -81,7 +81,7 @@ export class DomAdapter {
removeStyle(element, stylename: string) { throw _abstract(); } removeStyle(element, stylename: string) { throw _abstract(); }
getStyle(element, stylename: string) { throw _abstract(); } getStyle(element, stylename: string) { throw _abstract(); }
tagName(element): string { throw _abstract(); } tagName(element): string { throw _abstract(); }
attributeMap(element) { throw _abstract(); } attributeMap(element): Map<string, string> { throw _abstract(); }
hasAttribute(element, attribute: string): boolean { throw _abstract(); } hasAttribute(element, attribute: string): boolean { throw _abstract(); }
getAttribute(element, attribute: string): string { throw _abstract(); } getAttribute(element, attribute: string): string { throw _abstract(); }
setAttribute(element, name: string, value: string) { throw _abstract(); } setAttribute(element, name: string, value: string) { throw _abstract(); }
@ -90,7 +90,7 @@ export class DomAdapter {
createHtmlDocument() { throw _abstract(); } createHtmlDocument() { throw _abstract(); }
defaultDoc(): any { throw _abstract(); } defaultDoc(): any { throw _abstract(); }
getBoundingClientRect(el) { throw _abstract(); } getBoundingClientRect(el) { throw _abstract(); }
getTitle() { throw _abstract(); } getTitle(): string { throw _abstract(); }
setTitle(newTitle: string) { throw _abstract(); } setTitle(newTitle: string) { throw _abstract(); }
elementMatches(n, selector: string): boolean { throw _abstract(); } elementMatches(n, selector: string): boolean { throw _abstract(); }
isTemplateElement(el: any): boolean { throw _abstract(); } isTemplateElement(el: any): boolean { throw _abstract(); }

View File

@ -50,7 +50,11 @@ export class ElementBinder {
propertyBindings, variableBindings, propertyBindings, variableBindings,
eventBindings, textBindings, eventBindings, textBindings,
readAttributes readAttributes
}) { }:{index?:number, parentIndex?:number, distanceToParent?:number,
directives?:List<DirectiveBinder>, nestedProtoView?:ProtoViewDto,
propertyBindings?:Map<string, ASTWithSource>, variableBindings?:Map<string, ASTWithSource>,
eventBindings?:List<EventBinding>, textBindings?:List<ASTWithSource>,
readAttributes?:Map<string, string>}={}) {
this.index = index; this.index = index;
this.parentIndex = parentIndex; this.parentIndex = parentIndex;
this.distanceToParent = distanceToParent; this.distanceToParent = distanceToParent;
@ -66,7 +70,7 @@ export class ElementBinder {
export class DirectiveBinder { export class DirectiveBinder {
// Index into the array of directives in the View instance // Index into the array of directives in the View instance
directiveIndex:any; directiveIndex: number;
propertyBindings: Map<string, ASTWithSource>; propertyBindings: Map<string, ASTWithSource>;
// Note: this contains a preprocessed AST // Note: this contains a preprocessed AST
// that replaced the values that should be extracted from the element // that replaced the values that should be extracted from the element
@ -75,6 +79,9 @@ export class DirectiveBinder {
hostPropertyBindings: Map<string, ASTWithSource>; hostPropertyBindings: Map<string, ASTWithSource>;
constructor({ constructor({
directiveIndex, propertyBindings, eventBindings, hostPropertyBindings directiveIndex, propertyBindings, eventBindings, hostPropertyBindings
}:{
directiveIndex?:number, propertyBindings?:Map<string, ASTWithSource>,
eventBindings?:List<EventBinding>, hostPropertyBindings?:Map<string, ASTWithSource>
}) { }) {
this.directiveIndex = directiveIndex; this.directiveIndex = directiveIndex;
this.propertyBindings = propertyBindings; this.propertyBindings = propertyBindings;
@ -100,7 +107,12 @@ export class ProtoViewDto {
variableBindings: Map<string, string>; variableBindings: Map<string, string>;
type: number; type: number;
constructor({render, elementBinders, variableBindings, type}={}) { constructor({
render, elementBinders, variableBindings, type
}:{
render?:RenderProtoViewRef, elementBinders?:List<ElementBinder>,
variableBindings?:Map<string, string>, type?:number
}) {
this.render = render; this.render = render;
this.elementBinders = elementBinders; this.elementBinders = elementBinders;
this.variableBindings = variableBindings; this.variableBindings = variableBindings;
@ -126,10 +138,16 @@ export class DirectiveMetadata {
callOnChange: boolean; callOnChange: boolean;
callOnAllChangesDone: boolean; callOnAllChangesDone: boolean;
changeDetection: string; changeDetection: string;
constructor({id, selector, compileChildren, events, hostListeners, hostProperties, constructor({
id, selector, compileChildren, events, hostListeners, hostProperties,
hostAttributes, hostActions, properties, readAttributes, type, hostAttributes, hostActions, properties, readAttributes, type,
callOnDestroy, callOnChange, callOnAllChangesDone, callOnDestroy, callOnChange, callOnAllChangesDone,
changeDetection changeDetection
}:{
id?:string, selector?:string, compileChildren?:boolean, events?:List<string>, hostListeners?:Map<string, string>, hostProperties?:Map<string, string>,
hostAttributes?:Map<string, string>, hostActions?:Map<string, string>, properties?:Map<string, string>, readAttributes?:List<string>, type?:number,
callOnDestroy?:boolean, callOnChange?:boolean, callOnAllChangesDone?:boolean,
changeDetection?:string
}) { }) {
this.id = id; this.id = id;
this.selector = selector; this.selector = selector;
@ -150,12 +168,10 @@ export class DirectiveMetadata {
} }
// An opaque reference to a DomProtoView // An opaque reference to a DomProtoView
export class RenderProtoViewRef { export class RenderProtoViewRef {}
}
// An opaque reference to a DomView // An opaque reference to a DomView
export class RenderViewRef { export class RenderViewRef {}
}
export class ViewDefinition { export class ViewDefinition {
componentId: string; componentId: string;
@ -163,7 +179,11 @@ export class ViewDefinition {
template: string; template: string;
directives: List<DirectiveMetadata>; directives: List<DirectiveMetadata>;
constructor({componentId, absUrl, template, directives}) { constructor({
componentId, absUrl, template, directives
}:{
componentId?:string, absUrl?:string, template?:string, directives?:List<DirectiveMetadata>
}) {
this.componentId = componentId; this.componentId = componentId;
this.absUrl = absUrl; this.absUrl = absUrl;
this.template = template; this.template = template;
@ -175,7 +195,7 @@ export class RenderCompiler {
/** /**
* Creats a ProtoViewDto that contains a single nested component with the given componentId. * Creats a ProtoViewDto that contains a single nested component with the given componentId.
*/ */
compileHost(componentId):Promise<ProtoViewDto> { return null; } compileHost(directiveMetadata: DirectiveMetadata): Promise<ProtoViewDto> { return null; }
/** /**
* Compiles a single DomProtoView. Non recursive so that * Compiles a single DomProtoView. Non recursive so that
@ -188,110 +208,107 @@ export class RenderCompiler {
export class Renderer { export class Renderer {
/** /**
* Creates a root host view that includes the given element. * Creates a root host view that includes the given element.
* @param {RenderProtoViewRef} hostProtoViewRef a RenderProtoViewRef of type ProtoViewDto.HOST_VIEW_TYPE * @param {RenderProtoViewRef} hostProtoViewRef a RenderProtoViewRef of type
* @param {any} hostElementSelector css selector for the host element (will be queried against the main document) * ProtoViewDto.HOST_VIEW_TYPE
* @param {any} hostElementSelector css selector for the host element (will be queried against the
* main document)
* @return {RenderViewRef} the created view * @return {RenderViewRef} the created view
*/ */
createRootHostView(hostProtoViewRef:RenderProtoViewRef, hostElementSelector:string):RenderViewRef { createRootHostView(hostProtoViewRef: RenderProtoViewRef,
hostElementSelector: string): RenderViewRef {
return null; return null;
} }
/** /**
* Detaches a free host view's element from the DOM. * Detaches a free host view's element from the DOM.
*/ */
detachFreeHostView(parentHostViewRef:RenderViewRef, hostViewRef:RenderViewRef) { detachFreeHostView(parentHostViewRef: RenderViewRef, hostViewRef: RenderViewRef) {}
}
/** /**
* Creates a regular view out of the given ProtoView * Creates a regular view out of the given ProtoView
*/ */
createView(protoViewRef:RenderProtoViewRef):RenderViewRef { createView(protoViewRef: RenderProtoViewRef): RenderViewRef { return null; }
return null;
}
/** /**
* Destroys the given view after it has been dehydrated and detached * Destroys the given view after it has been dehydrated and detached
*/ */
destroyView(viewRef:RenderViewRef) { destroyView(viewRef: RenderViewRef) {}
}
/** /**
* Attaches a componentView into the given hostView at the given element * Attaches a componentView into the given hostView at the given element
*/ */
attachComponentView(hostViewRef:RenderViewRef, elementIndex:number, componentViewRef:RenderViewRef) { attachComponentView(hostViewRef: RenderViewRef, elementIndex: number,
} componentViewRef: RenderViewRef) {}
/** /**
* Detaches a componentView into the given hostView at the given element * Detaches a componentView into the given hostView at the given element
*/ */
detachComponentView(hostViewRef:RenderViewRef, boundElementIndex:number, componentViewRef:RenderViewRef) { detachComponentView(hostViewRef: RenderViewRef, boundElementIndex: number,
} componentViewRef: RenderViewRef) {}
/** /**
* Attaches a view into a ViewContainer (in the given parentView at the given element) at the given index. * Attaches a view into a ViewContainer (in the given parentView at the given element) at the
* given index.
*/ */
attachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) { attachViewInContainer(parentViewRef: RenderViewRef, boundElementIndex: number, atIndex: number,
} viewRef: RenderViewRef) {}
/** /**
* Detaches a view into a ViewContainer (in the given parentView at the given element) at the given index. * Detaches a view into a ViewContainer (in the given parentView at the given element) at the
* given index.
*/ */
// TODO(tbosch): this should return a promise as it can be animated! // TODO(tbosch): this should return a promise as it can be animated!
detachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) { detachViewInContainer(parentViewRef: RenderViewRef, boundElementIndex: number, atIndex: number,
} viewRef: RenderViewRef) {}
/** /**
* Hydrates a view after it has been attached. Hydration/dehydration is used for reusing views inside of the view pool. * Hydrates a view after it has been attached. Hydration/dehydration is used for reusing views
* inside of the view pool.
*/ */
hydrateView(viewRef:RenderViewRef) { hydrateView(viewRef: RenderViewRef) {}
}
/** /**
* Dehydrates a view after it has been attached. Hydration/dehydration is used for reusing views inside of the view pool. * Dehydrates a view after it has been attached. Hydration/dehydration is used for reusing views
* inside of the view pool.
*/ */
dehydrateView(viewRef:RenderViewRef) { dehydrateView(viewRef: RenderViewRef) {}
}
/** /**
* Sets a property on an element. * Sets a property on an element.
* Note: This will fail if the property was not mentioned previously as a host property * Note: This will fail if the property was not mentioned previously as a host property
* in the ProtoView * in the ProtoView
*/ */
setElementProperty(viewRef:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void { setElementProperty(viewRef: RenderViewRef, elementIndex: number, propertyName: string,
} propertyValue: any) {}
/** /**
* Calls an action. * Calls an action.
* Note: This will fail if the action was not mentioned previously as a host action * Note: This will fail if the action was not mentioned previously as a host action
* in the ProtoView * in the ProtoView
*/ */
callAction(viewRef:RenderViewRef, elementIndex:number, actionExpression:string, actionArgs:any):void { callAction(viewRef: RenderViewRef, elementIndex: number, actionExpression: string,
} actionArgs: any) {}
/** /**
* Sets the value of a text node. * Sets the value of a text node.
*/ */
setText(viewRef:RenderViewRef, textNodeIndex:number, text:string):void { setText(viewRef: RenderViewRef, textNodeIndex: number, text: string) {}
}
/** /**
* Sets the dispatcher for all events of the given view * Sets the dispatcher for all events of the given view
*/ */
setEventDispatcher(viewRef:RenderViewRef, dispatcher:any/*api.EventDispatcher*/):void { setEventDispatcher(viewRef: RenderViewRef, dispatcher: EventDispatcher) {}
}
} }
/** /**
* A dispatcher for all events happening in a view. * A dispatcher for all events happening in a view.
*/ */
export class EventDispatcher { export interface EventDispatcher {
/** /**
* Called when an event was triggered for a on-* attribute on an element. * Called when an event was triggered for a on-* attribute on an element.
* @param {Map<string, any>} locals Locals to be used to evaluate the * @param {Map<string, any>} locals Locals to be used to evaluate the
* event expressions * event expressions
*/ */
dispatchEvent( dispatchEvent(elementIndex: number, eventName: string, locals: Map<string, any>);
elementIndex:number, eventName:string, locals:Map<string, any>
):void {}
} }

View File

@ -31,9 +31,7 @@ export class CompileControl {
this._ignoreCurrentElement = false; this._ignoreCurrentElement = false;
for (var i = startStepIndex; for (var i = startStepIndex; i < this._steps.length && !this._ignoreCurrentElement; i++) {
i < this._steps.length && !this._ignoreCurrentElement;
i++) {
var step = this._steps[i]; var step = this._steps[i];
this._parent = parent; this._parent = parent;
this._currentStepIndex = i; this._currentStepIndex = i;
@ -71,7 +69,5 @@ export class CompileControl {
* When a step calls `ignoreCurrentElement`, no further steps are executed on the current * When a step calls `ignoreCurrentElement`, no further steps are executed on the current
* element and no `CompileElement` is added to the result list. * element and no `CompileElement` is added to the result list.
*/ */
ignoreCurrentElement() { ignoreCurrentElement() { this._ignoreCurrentElement = true; }
this._ignoreCurrentElement = true;
}
} }

View File

@ -1,6 +1,13 @@
import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {int, isBlank, isPresent, Type, StringJoiner, assertionsEnabled} from 'angular2/src/facade/lang'; import {
int,
isBlank,
isPresent,
Type,
StringJoiner,
assertionsEnabled
} from 'angular2/src/facade/lang';
import {ProtoViewBuilder, ElementBinderBuilder} from '../view/proto_view_builder'; import {ProtoViewBuilder, ElementBinderBuilder} from '../view/proto_view_builder';
@ -11,14 +18,15 @@ import {ProtoViewBuilder, ElementBinderBuilder} from '../view/proto_view_builder
*/ */
export class CompileElement { export class CompileElement {
element; element;
_attrs:Map; _attrs: Map<string, string>;
_classList:List; _classList: List<string>;
isViewRoot: boolean; isViewRoot: boolean;
inheritedProtoView: ProtoViewBuilder; inheritedProtoView: ProtoViewBuilder;
distanceToInheritedBinder: number; distanceToInheritedBinder: number;
inheritedElementBinder: ElementBinderBuilder; inheritedElementBinder: ElementBinderBuilder;
compileChildren: boolean; compileChildren: boolean;
elementDescription: string; // e.g. '<div [class]="foo">' : used to provide context in case of error elementDescription: string; // e.g. '<div [class]="foo">' : used to provide context in case of
// error
constructor(element, compilationUnit = '') { constructor(element, compilationUnit = '') {
this.element = element; this.element = element;
@ -50,7 +58,8 @@ export class CompileElement {
bindElement() { bindElement() {
if (!this.isBound()) { if (!this.isBound()) {
var parentBinder = this.inheritedElementBinder; var parentBinder = this.inheritedElementBinder;
this.inheritedElementBinder = this.inheritedProtoView.bindElement(this.element, this.elementDescription); this.inheritedElementBinder =
this.inheritedProtoView.bindElement(this.element, this.elementDescription);
if (isPresent(parentBinder)) { if (isPresent(parentBinder)) {
this.inheritedElementBinder.setParent(parentBinder, this.distanceToInheritedBinder); this.inheritedElementBinder.setParent(parentBinder, this.distanceToInheritedBinder);
} }
@ -59,9 +68,7 @@ export class CompileElement {
return this.inheritedElementBinder; return this.inheritedElementBinder;
} }
refreshAttrs() { refreshAttrs() { this._attrs = null; }
this._attrs = null;
}
attrs(): Map<string, string> { attrs(): Map<string, string> {
if (isBlank(this._attrs)) { if (isBlank(this._attrs)) {
@ -70,9 +77,7 @@ export class CompileElement {
return this._attrs; return this._attrs;
} }
refreshClassList() { refreshClassList() { this._classList = null; }
this._classList = null;
}
classList(): List<string> { classList(): List<string> {
if (isBlank(this._classList)) { if (isBlank(this._classList)) {
@ -84,7 +89,6 @@ export class CompileElement {
} }
return this._classList; return this._classList;
} }
} }
// return an HTML representation of an element start tag - without its content // return an HTML representation of an element start tag - without its content

View File

@ -13,11 +13,10 @@ import {ProtoViewDto} from '../../api';
*/ */
export class CompilePipeline { export class CompilePipeline {
_control: CompileControl; _control: CompileControl;
constructor(steps:List<CompileStep>) { constructor(steps: List<CompileStep>) { this._control = new CompileControl(steps); }
this._control = new CompileControl(steps);
}
process(rootElement, protoViewType:number = null, compilationCtxtDescription:string = ''):List { process(rootElement, protoViewType: number = null,
compilationCtxtDescription: string = ''): List<CompileElement> {
if (isBlank(protoViewType)) { if (isBlank(protoViewType)) {
protoViewType = ProtoViewDto.COMPONENT_VIEW_TYPE; protoViewType = ProtoViewDto.COMPONENT_VIEW_TYPE;
} }
@ -25,13 +24,12 @@ export class CompilePipeline {
var rootCompileElement = new CompileElement(rootElement, compilationCtxtDescription); var rootCompileElement = new CompileElement(rootElement, compilationCtxtDescription);
rootCompileElement.inheritedProtoView = new ProtoViewBuilder(rootElement, protoViewType); rootCompileElement.inheritedProtoView = new ProtoViewBuilder(rootElement, protoViewType);
rootCompileElement.isViewRoot = true; rootCompileElement.isViewRoot = true;
this._process(results, null, rootCompileElement, this._process(results, null, rootCompileElement, compilationCtxtDescription);
compilationCtxtDescription
);
return results; return results;
} }
_process(results, parent:CompileElement, current:CompileElement, compilationCtxtDescription:string = '') { _process(results, parent: CompileElement, current: CompileElement,
compilationCtxtDescription: string = '') {
var additionalChildren = this._control.internalProcess(results, 0, parent, current); var additionalChildren = this._control.internalProcess(results, 0, parent, current);
if (current.compileChildren) { if (current.compileChildren) {

View File

@ -5,6 +5,7 @@ import * as compileControlModule from './compile_control';
* One part of the compile process. * One part of the compile process.
* Is guaranteed to be called in depth first order * Is guaranteed to be called in depth first order
*/ */
export class CompileStep { export interface CompileStep {
process(parent:CompileElement, current:CompileElement, control:compileControlModule.CompileControl) {} process(parent: CompileElement, current: CompileElement,
control: compileControlModule.CompileControl): void;
} }

View File

@ -12,7 +12,7 @@ import {ShadowDomCompileStep} from '../shadow_dom/shadow_dom_compile_step';
import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy'; import {ShadowDomStrategy} from '../shadow_dom/shadow_dom_strategy';
export class CompileStepFactory { export class CompileStepFactory {
createSteps(template: ViewDefinition, subTaskPromises: List<Promise>):List<CompileStep> { createSteps(template: ViewDefinition, subTaskPromises: List<Promise<any>>): List<CompileStep> {
return null; return null;
} }
} }
@ -27,7 +27,7 @@ export class DefaultStepFactory extends CompileStepFactory {
this._shadowDomStrategy = shadowDomStrategy; this._shadowDomStrategy = shadowDomStrategy;
} }
createSteps(template: ViewDefinition, subTaskPromises: List<Promise>) { createSteps(template: ViewDefinition, subTaskPromises: List<Promise<any>>) {
return [ return [
new ViewSplitter(this._parser), new ViewSplitter(this._parser),
new PropertyBindingParser(this._parser), new PropertyBindingParser(this._parser),

View File

@ -1,10 +1,16 @@
import {Injectable} from 'angular2/src/di/annotations_impl'; import {Injectable} from 'angular2/di';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
import {BaseException, isPresent} from 'angular2/src/facade/lang'; import {BaseException, isPresent} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {ViewDefinition, ProtoViewDto, DirectiveMetadata, RenderCompiler, RenderProtoViewRef} from '../../api'; import {
ViewDefinition,
ProtoViewDto,
DirectiveMetadata,
RenderCompiler,
RenderProtoViewRef
} from '../../api';
import {CompilePipeline} from './compile_pipeline'; import {CompilePipeline} from './compile_pipeline';
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory'; import {CompileStepFactory, DefaultStepFactory} from './compile_step_factory';
@ -28,24 +34,25 @@ export class DomCompiler extends RenderCompiler {
compile(template: ViewDefinition): Promise<ProtoViewDto> { compile(template: ViewDefinition): Promise<ProtoViewDto> {
var tplPromise = this._templateLoader.load(template); var tplPromise = this._templateLoader.load(template);
return PromiseWrapper.then(tplPromise, return PromiseWrapper.then(
(el) => this._compileTemplate(template, el, ProtoViewDto.COMPONENT_VIEW_TYPE), tplPromise, (el) => this._compileTemplate(template, el, ProtoViewDto.COMPONENT_VIEW_TYPE),
(_) => { throw new BaseException(`Failed to load the template "${template.componentId}"`); } (_) => {
); throw new BaseException(`Failed to load the template "${template.componentId}"`);
});
} }
compileHost(directiveMetadata: DirectiveMetadata): Promise<ProtoViewDto> { compileHost(directiveMetadata: DirectiveMetadata): Promise<ProtoViewDto> {
var hostViewDef = new ViewDefinition({ var hostViewDef = new ViewDefinition({
componentId: directiveMetadata.id, componentId: directiveMetadata.id,
absUrl: null, absUrl: null, template: null,
template: null,
directives: [directiveMetadata] directives: [directiveMetadata]
}); });
var element = DOM.createElement(directiveMetadata.selector); var element = DOM.createElement(directiveMetadata.selector);
return this._compileTemplate(hostViewDef, element, ProtoViewDto.HOST_VIEW_TYPE); return this._compileTemplate(hostViewDef, element, ProtoViewDto.HOST_VIEW_TYPE);
} }
_compileTemplate(viewDef: ViewDefinition, tplElement, protoViewType:number):Promise<ProtoViewDto> { _compileTemplate(viewDef: ViewDefinition, tplElement,
protoViewType: number): Promise<ProtoViewDto> {
var subTaskPromises = []; var subTaskPromises = [];
var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises)); var pipeline = new CompilePipeline(this._stepFactory.createSteps(viewDef, subTaskPromises));
var compileElements = pipeline.process(tplElement, protoViewType, viewDef.componentId); var compileElements = pipeline.process(tplElement, protoViewType, viewDef.componentId);
@ -62,7 +69,8 @@ export class DomCompiler extends RenderCompiler {
@Injectable() @Injectable()
export class DefaultDomCompiler extends DomCompiler { export class DefaultDomCompiler extends DomCompiler {
constructor(parser:Parser, shadowDomStrategy:ShadowDomStrategy, templateLoader: TemplateLoader) { constructor(parser: Parser, shadowDomStrategy: ShadowDomStrategy,
templateLoader: TemplateLoader) {
super(new DefaultStepFactory(parser, shadowDomStrategy), templateLoader); super(new DefaultStepFactory(parser, shadowDomStrategy), templateLoader);
} }
} }

View File

@ -1,4 +1,11 @@
import {isPresent, isBlank, BaseException, assertionsEnabled, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang'; import {
isPresent,
isBlank,
BaseException,
assertionsEnabled,
RegExpWrapper,
StringWrapper
} from 'angular2/src/facade/lang';
import {List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {Parser} from 'angular2/change_detection'; import {Parser} from 'angular2/change_detection';
@ -16,13 +23,12 @@ import {dashCaseToCamelCase, camelCaseToDashCase, EVENT_TARGET_SEPARATOR} from '
* Parses the directives on a single element. Assumes ViewSplitter has already created * Parses the directives on a single element. Assumes ViewSplitter has already created
* <template> elements for template directives. * <template> elements for template directives.
*/ */
export class DirectiveParser extends CompileStep { export class DirectiveParser implements CompileStep {
_selectorMatcher: SelectorMatcher; _selectorMatcher: SelectorMatcher;
_directives: List<DirectiveMetadata>; _directives: List<DirectiveMetadata>;
_parser: Parser; _parser: Parser;
constructor(parser: Parser, directives: List<DirectiveMetadata>) { constructor(parser: Parser, directives: List<DirectiveMetadata>) {
super();
this._parser = parser; this._parser = parser;
this._selectorMatcher = new SelectorMatcher(); this._selectorMatcher = new SelectorMatcher();
this._directives = directives; this._directives = directives;
@ -37,7 +43,8 @@ export class DirectiveParser extends CompileStep {
_ensureComponentOnlyHasElementSelector(selector, directive) { _ensureComponentOnlyHasElementSelector(selector, directive) {
var isElementSelector = selector.length === 1 && selector[0].isElementSelector(); var isElementSelector = selector.length === 1 && selector[0].isElementSelector();
if (!isElementSelector && directive.type === DirectiveMetadata.COMPONENT_TYPE) { if (!isElementSelector && directive.type === DirectiveMetadata.COMPONENT_TYPE) {
throw new BaseException(`Component '${directive.id}' can only have an element selector, but had '${directive.selector}'`); throw new BaseException(
`Component '${directive.id}' can only have an element selector, but had '${directive.selector}'`);
} }
} }
@ -52,9 +59,8 @@ export class DirectiveParser extends CompileStep {
cssSelector.addClassName(classList[i]); cssSelector.addClassName(classList[i]);
} }
MapWrapper.forEach(attrs, (attrValue, attrName) => { MapWrapper.forEach(attrs,
cssSelector.addAttribute(attrName, attrValue); (attrValue, attrName) => { cssSelector.addAttribute(attrName, attrValue); });
});
var componentDirective; var componentDirective;
var foundDirectiveIndices = []; var foundDirectiveIndices = [];
@ -66,7 +72,8 @@ export class DirectiveParser extends CompileStep {
// components need to go first, so it is easier to locate them in the result. // components need to go first, so it is easier to locate them in the result.
ListWrapper.insert(foundDirectiveIndices, 0, directiveIndex); ListWrapper.insert(foundDirectiveIndices, 0, directiveIndex);
if (isPresent(componentDirective)) { if (isPresent(componentDirective)) {
throw new BaseException(`Only one component directive is allowed per element - check ${current.elementDescription}`); throw new BaseException(
`Only one component directive is allowed per element - check ${current.elementDescription}`);
} }
componentDirective = directive; componentDirective = directive;
elementBinder.setComponentId(directive.id); elementBinder.setComponentId(directive.id);
@ -95,7 +102,8 @@ export class DirectiveParser extends CompileStep {
} }
if (isPresent(directive.hostProperties)) { if (isPresent(directive.hostProperties)) {
MapWrapper.forEach(directive.hostProperties, (hostPropertyName, directivePropertyName) => { MapWrapper.forEach(directive.hostProperties, (hostPropertyName, directivePropertyName) => {
this._bindHostProperty(hostPropertyName, directivePropertyName, current, directiveBinderBuilder); this._bindHostProperty(hostPropertyName, directivePropertyName, current,
directiveBinderBuilder);
}); });
} }
if (isPresent(directive.hostAttributes)) { if (isPresent(directive.hostAttributes)) {
@ -104,9 +112,8 @@ export class DirectiveParser extends CompileStep {
}); });
} }
if (isPresent(directive.readAttributes)) { if (isPresent(directive.readAttributes)) {
ListWrapper.forEach(directive.readAttributes, (attrName) => { ListWrapper.forEach(directive.readAttributes,
elementBinder.readAttribute(attrName); (attrName) => { elementBinder.readAttribute(attrName); });
});
} }
}); });
} }
@ -115,27 +122,21 @@ export class DirectiveParser extends CompileStep {
var pipes = this._splitBindConfig(bindConfig); var pipes = this._splitBindConfig(bindConfig);
var elProp = ListWrapper.removeAt(pipes, 0); var elProp = ListWrapper.removeAt(pipes, 0);
var bindingAst = MapWrapper.get( var bindingAst =
compileElement.bindElement().propertyBindings, MapWrapper.get(compileElement.bindElement().propertyBindings, dashCaseToCamelCase(elProp));
dashCaseToCamelCase(elProp)
);
if (isBlank(bindingAst)) { if (isBlank(bindingAst)) {
var attributeValue = MapWrapper.get(compileElement.attrs(), camelCaseToDashCase(elProp)); var attributeValue = MapWrapper.get(compileElement.attrs(), camelCaseToDashCase(elProp));
if (isPresent(attributeValue)) { if (isPresent(attributeValue)) {
bindingAst = this._parser.wrapLiteralPrimitive( bindingAst =
attributeValue, this._parser.wrapLiteralPrimitive(attributeValue, compileElement.elementDescription);
compileElement.elementDescription
);
} }
} }
// Bindings are optional, so this binding only needs to be set up if an expression is given. // Bindings are optional, so this binding only needs to be set up if an expression is given.
if (isPresent(bindingAst)) { if (isPresent(bindingAst)) {
var fullExpAstWithBindPipes = this._parser.addPipes(bindingAst, pipes); var fullExpAstWithBindPipes = this._parser.addPipes(bindingAst, pipes);
directiveBinderBuilder.bindProperty( directiveBinderBuilder.bindProperty(dirProperty, fullExpAstWithBindPipes);
dirProperty, fullExpAstWithBindPipes
);
} }
} }
@ -154,7 +155,8 @@ export class DirectiveParser extends CompileStep {
directiveBinderBuilder.bindHostAction(actionName, actionExpression, ast); directiveBinderBuilder.bindHostAction(actionName, actionExpression, ast);
} }
_bindHostProperty(hostPropertyName, directivePropertyName, compileElement, directiveBinderBuilder) { _bindHostProperty(hostPropertyName, directivePropertyName, compileElement,
directiveBinderBuilder) {
var ast = this._parser.parseBinding(directivePropertyName, var ast = this._parser.parseBinding(directivePropertyName,
`hostProperties of ${compileElement.elementDescription}`); `hostProperties of ${compileElement.elementDescription}`);
directiveBinderBuilder.bindHostProperty(hostPropertyName, ast); directiveBinderBuilder.bindHostProperty(hostPropertyName, ast);
@ -162,9 +164,8 @@ export class DirectiveParser extends CompileStep {
_addHostAttribute(attrName, attrValue, compileElement) { _addHostAttribute(attrName, attrValue, compileElement) {
if (StringWrapper.equals(attrName, 'class')) { if (StringWrapper.equals(attrName, 'class')) {
ListWrapper.forEach(attrValue.split(' '), (className) => { ListWrapper.forEach(attrValue.split(' '),
DOM.addClass(compileElement.element, className); (className) => { DOM.addClass(compileElement.element, className); });
});
} else if (!DOM.hasAttribute(compileElement.element, attrName)) { } else if (!DOM.hasAttribute(compileElement.element, attrName)) {
DOM.setAttribute(compileElement.element, attrName, attrValue); DOM.setAttribute(compileElement.element, attrName, attrValue);
} }
@ -174,4 +175,3 @@ export class DirectiveParser extends CompileStep {
return ListWrapper.map(bindConfig.split('|'), (s) => s.trim()); return ListWrapper.map(bindConfig.split('|'), (s) => s.trim());
} }
} }

View File

@ -22,13 +22,10 @@ var BIND_NAME_REGEXP = RegExpWrapper.create(
/** /**
* Parses the property bindings on a single element. * Parses the property bindings on a single element.
*/ */
export class PropertyBindingParser extends CompileStep { export class PropertyBindingParser implements CompileStep {
_parser: Parser; _parser: Parser;
constructor(parser:Parser) { constructor(parser: Parser) { this._parser = parser; }
super();
this._parser = parser;
}
process(parent: CompileElement, current: CompileElement, control: CompileControl) { process(parent: CompileElement, current: CompileElement, control: CompileControl) {
var attrs = current.attrs(); var attrs = current.attrs();
@ -40,7 +37,8 @@ export class PropertyBindingParser extends CompileStep {
if (isPresent(bindParts[1])) { // match: bind-prop if (isPresent(bindParts[1])) { // match: bind-prop
this._bindProperty(bindParts[5], attrValue, current, newAttrs); this._bindProperty(bindParts[5], attrValue, current, newAttrs);
} else if (isPresent(bindParts[2])) { // match: var-name / var-name="iden" / #name / #name="iden" } else if (isPresent(
bindParts[2])) { // match: var-name / var-name="iden" / #name / #name="iden"
var identifier = bindParts[5]; var identifier = bindParts[5];
var value = attrValue == '' ? '\$implicit' : attrValue; var value = attrValue == '' ? '\$implicit' : attrValue;
this._bindVariable(identifier, value, current, newAttrs); this._bindVariable(identifier, value, current, newAttrs);
@ -63,18 +61,15 @@ export class PropertyBindingParser extends CompileStep {
this._bindEvent(bindParts[8], attrValue, current, newAttrs); this._bindEvent(bindParts[8], attrValue, current, newAttrs);
} }
} else { } else {
var expr = this._parser.parseInterpolation( var expr = this._parser.parseInterpolation(attrValue, current.elementDescription);
attrValue, current.elementDescription
);
if (isPresent(expr)) { if (isPresent(expr)) {
this._bindPropertyAst(attrName, expr, current, newAttrs); this._bindPropertyAst(attrName, expr, current, newAttrs);
} }
} }
}); });
MapWrapper.forEach(newAttrs, (attrValue, attrName) => { MapWrapper.forEach(newAttrs,
MapWrapper.set(attrs, attrName, attrValue); (attrValue, attrName) => { MapWrapper.set(attrs, attrName, attrValue); });
});
} }
_bindVariable(identifier, value, current: CompileElement, newAttrs) { _bindVariable(identifier, value, current: CompileElement, newAttrs) {
@ -83,12 +78,8 @@ export class PropertyBindingParser extends CompileStep {
} }
_bindProperty(name, expression, current: CompileElement, newAttrs) { _bindProperty(name, expression, current: CompileElement, newAttrs) {
this._bindPropertyAst( this._bindPropertyAst(name, this._parser.parseBinding(expression, current.elementDescription),
name, current, newAttrs);
this._parser.parseBinding(expression, current.elementDescription),
current,
newAttrs
);
} }
_bindPropertyAst(name, ast, current: CompileElement, newAttrs) { _bindPropertyAst(name, ast, current: CompileElement, newAttrs) {
@ -104,10 +95,9 @@ export class PropertyBindingParser extends CompileStep {
_bindEvent(name, expression, current: CompileElement, newAttrs) { _bindEvent(name, expression, current: CompileElement, newAttrs) {
current.bindElement().bindEvent( current.bindElement().bindEvent(
dashCaseToCamelCase(name), this._parser.parseAction(expression, current.elementDescription) dashCaseToCamelCase(name),
); this._parser.parseAction(expression, current.elementDescription));
// Don't detect directives for event names for now, // Don't detect directives for event names for now,
// so don't add the event name to the CompileElement.attrs // so don't add the event name to the CompileElement.attrs
} }
} }

View File

@ -1,12 +1,19 @@
import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {List, Map, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank, RegExpWrapper, RegExpMatcherWrapper, StringWrapper, BaseException} from 'angular2/src/facade/lang'; import {
isPresent,
isBlank,
RegExpWrapper,
RegExpMatcherWrapper,
StringWrapper,
BaseException
} from 'angular2/src/facade/lang';
const _EMPTY_ATTR_VALUE = ''; const _EMPTY_ATTR_VALUE = '';
// TODO: Can't use `const` here as // TODO: Can't use `const` here as
// in Dart this is not transpiled into `final` yet... // in Dart this is not transpiled into `final` yet...
var _SELECTOR_REGEXP = var _SELECTOR_REGEXP = RegExpWrapper.create(
RegExpWrapper.create('(\\:not\\()|' + //":not(" '(\\:not\\()|' + //":not("
'([-\\w]+)|' + // "tag" '([-\\w]+)|' + // "tag"
'(?:\\.([-\\w]+))|' + // ".class" '(?:\\.([-\\w]+))|' + // ".class"
'(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]" or "[name*=value]" '(?:\\[([-\\w*]+)(?:=([^\\]]*))?\\])|' + // "[name]", "[name=value]" or "[name*=value]"
@ -20,17 +27,16 @@ var _SELECTOR_REGEXP =
*/ */
export class CssSelector { export class CssSelector {
element: string; element: string;
classNames:List; classNames: List<string>;
attrs:List; attrs: List<string>;
notSelector: CssSelector; notSelector: CssSelector;
static parse(selector: string): List<CssSelector> { static parse(selector: string): List<CssSelector> {
var results = ListWrapper.create(); var results = ListWrapper.create();
var _addResult = (res, cssSel) => { var _addResult = (res, cssSel) => {
if (isPresent(cssSel.notSelector) && isBlank(cssSel.element) if (isPresent(cssSel.notSelector) && isBlank(cssSel.element) &&
&& ListWrapper.isEmpty(cssSel.classNames) && ListWrapper.isEmpty(cssSel.attrs)) { ListWrapper.isEmpty(cssSel.classNames) && ListWrapper.isEmpty(cssSel.attrs)) {
cssSel.element = "*"; cssSel.element = "*";
} } ListWrapper.push(res, cssSel);
ListWrapper.push(res, cssSel);
} }
var cssSelector = new CssSelector(); var cssSelector = new CssSelector();
var matcher = RegExpWrapper.matcher(_SELECTOR_REGEXP, selector); var matcher = RegExpWrapper.matcher(_SELECTOR_REGEXP, selector);
@ -70,10 +76,8 @@ export class CssSelector {
} }
isElementSelector(): boolean { isElementSelector(): boolean {
return isPresent(this.element) && return isPresent(this.element) && ListWrapper.isEmpty(this.classNames) &&
ListWrapper.isEmpty(this.classNames) && ListWrapper.isEmpty(this.attrs) && isBlank(this.notSelector);
ListWrapper.isEmpty(this.attrs) &&
isBlank(this.notSelector);
} }
setElement(element: string = null) { setElement(element: string = null) {
@ -110,7 +114,7 @@ export class CssSelector {
if (isPresent(this.attrs)) { if (isPresent(this.attrs)) {
for (var i = 0; i < this.attrs.length;) { for (var i = 0; i < this.attrs.length;) {
var attrName = this.attrs[i++]; var attrName = this.attrs[i++];
var attrValue = this.attrs[i++] var attrValue = this.attrs[i++];
res += '[' + attrName; res += '[' + attrName;
if (attrValue.length > 0) { if (attrValue.length > 0) {
res += '=' + attrValue; res += '=' + attrValue;
@ -130,13 +134,20 @@ export class CssSelector {
* are contained in a given CssSelector. * are contained in a given CssSelector.
*/ */
export class SelectorMatcher { export class SelectorMatcher {
_elementMap:Map; static createNotMatcher(notSelector:CssSelector) {
_elementPartialMap:Map; var notMatcher = new SelectorMatcher();
_classMap:Map; notMatcher._addSelectable(notSelector, null, null);
_classPartialMap:Map; return notMatcher;
_attrValueMap:Map; }
_attrValuePartialMap:Map;
_listContexts:List; private _elementMap: Map<string, string>;
private _elementPartialMap: Map<string, string>;
private _classMap: Map<string, string>;
private _classPartialMap: Map<string, string>;
private _attrValueMap: Map<string, string>;
private _attrValuePartialMap: Map<string, string>;
private _listContexts: List<SelectorListContext>;
constructor() { constructor() {
this._elementMap = MapWrapper.create(); this._elementMap = MapWrapper.create();
this._elementPartialMap = MapWrapper.create(); this._elementPartialMap = MapWrapper.create();
@ -150,14 +161,14 @@ export class SelectorMatcher {
this._listContexts = ListWrapper.create(); this._listContexts = ListWrapper.create();
} }
addSelectables(cssSelectors:List<CssSelector>, callbackCtxt) { addSelectables(cssSelectors: List<CssSelector>, callbackCtxt: any) {
var listContext = null; var listContext = null;
if (cssSelectors.length > 1) { if (cssSelectors.length > 1) {
listContext = new SelectorListContext(cssSelectors); listContext = new SelectorListContext(cssSelectors);
ListWrapper.push(this._listContexts, listContext); ListWrapper.push(this._listContexts, listContext);
} }
for (var i = 0; i < cssSelectors.length; i++) { for (var i = 0; i < cssSelectors.length; i++) {
this.addSelectable(cssSelectors[i], callbackCtxt, listContext); this._addSelectable(cssSelectors[i], callbackCtxt, listContext);
} }
} }
@ -166,7 +177,7 @@ export class SelectorMatcher {
* @param cssSelector A css selector * @param cssSelector A css selector
* @param callbackCtxt An opaque object that will be given to the callback of the `match` function * @param callbackCtxt An opaque object that will be given to the callback of the `match` function
*/ */
addSelectable(cssSelector, callbackCtxt, listContext: SelectorListContext) { private _addSelectable(cssSelector: CssSelector, callbackCtxt: any, listContext: SelectorListContext) {
var matcher = this; var matcher = this;
var element = cssSelector.element; var element = cssSelector.element;
var classNames = cssSelector.classNames; var classNames = cssSelector.classNames;
@ -201,7 +212,7 @@ export class SelectorMatcher {
var attrName = attrs[index++]; var attrName = attrs[index++];
var attrValue = attrs[index++]; var attrValue = attrs[index++];
var map = isTerminal ? matcher._attrValueMap : matcher._attrValuePartialMap; var map = isTerminal ? matcher._attrValueMap : matcher._attrValuePartialMap;
var valuesMap = MapWrapper.get(map, attrName) var valuesMap = MapWrapper.get(map, attrName);
if (isBlank(valuesMap)) { if (isBlank(valuesMap)) {
valuesMap = MapWrapper.create(); valuesMap = MapWrapper.create();
MapWrapper.set(map, attrName, valuesMap); MapWrapper.set(map, attrName, valuesMap);
@ -215,8 +226,8 @@ export class SelectorMatcher {
} }
} }
_addTerminal(map:Map<string,string>, name:string, selectable) { private _addTerminal(map: Map<string, string>, name: string, selectable: SelectorContext) {
var terminalList = MapWrapper.get(map, name) var terminalList = MapWrapper.get(map, name);
if (isBlank(terminalList)) { if (isBlank(terminalList)) {
terminalList = ListWrapper.create(); terminalList = ListWrapper.create();
MapWrapper.set(map, name, terminalList); MapWrapper.set(map, name, terminalList);
@ -224,8 +235,8 @@ export class SelectorMatcher {
ListWrapper.push(terminalList, selectable); ListWrapper.push(terminalList, selectable);
} }
_addPartial(map:Map<string,string>, name:string) { private _addPartial(map: Map<string, string>, name: string) {
var matcher = MapWrapper.get(map, name) var matcher = MapWrapper.get(map, name);
if (isBlank(matcher)) { if (isBlank(matcher)) {
matcher = new SelectorMatcher(); matcher = new SelectorMatcher();
MapWrapper.set(map, name, matcher); MapWrapper.set(map, name, matcher);
@ -240,7 +251,7 @@ export class SelectorMatcher {
* @param matchedCallback This callback will be called with the object handed into `addSelectable` * @param matchedCallback This callback will be called with the object handed into `addSelectable`
* @return boolean true if a match was found * @return boolean true if a match was found
*/ */
match(cssSelector:CssSelector, matchedCallback:Function):boolean { match(cssSelector: CssSelector, matchedCallback /*: (CssSelector, any) => void*/): boolean {
var result = false; var result = false;
var element = cssSelector.element; var element = cssSelector.element;
var classNames = cssSelector.classNames; var classNames = cssSelector.classNames;
@ -251,13 +262,17 @@ export class SelectorMatcher {
} }
result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result; result = this._matchTerminal(this._elementMap, element, cssSelector, matchedCallback) || result;
result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) || result; result = this._matchPartial(this._elementPartialMap, element, cssSelector, matchedCallback) ||
result;
if (isPresent(classNames)) { if (isPresent(classNames)) {
for (var index = 0; index < classNames.length; index++) { for (var index = 0; index < classNames.length; index++) {
var className = classNames[index]; var className = classNames[index];
result = this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result; result =
result = this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) || result; this._matchTerminal(this._classMap, className, cssSelector, matchedCallback) || result;
result =
this._matchPartial(this._classPartialMap, className, cssSelector, matchedCallback) ||
result;
} }
} }
@ -268,18 +283,21 @@ export class SelectorMatcher {
var valuesMap = MapWrapper.get(this._attrValueMap, attrName); var valuesMap = MapWrapper.get(this._attrValueMap, attrName);
if (!StringWrapper.equals(attrValue, _EMPTY_ATTR_VALUE)) { if (!StringWrapper.equals(attrValue, _EMPTY_ATTR_VALUE)) {
result = this._matchTerminal(valuesMap, _EMPTY_ATTR_VALUE, cssSelector, matchedCallback) || result; result =
this._matchTerminal(valuesMap, _EMPTY_ATTR_VALUE, cssSelector, matchedCallback) ||
result;
} }
result = this._matchTerminal(valuesMap, attrValue, cssSelector, matchedCallback) || result; result = this._matchTerminal(valuesMap, attrValue, cssSelector, matchedCallback) || result;
valuesMap = MapWrapper.get(this._attrValuePartialMap, attrName) valuesMap = MapWrapper.get(this._attrValuePartialMap, attrName);
result = this._matchPartial(valuesMap, attrValue, cssSelector, matchedCallback) || result; result = this._matchPartial(valuesMap, attrValue, cssSelector, matchedCallback) || result;
} }
} }
return result; return result;
} }
_matchTerminal(map:Map<string,string> = null, name, cssSelector, matchedCallback):boolean { _matchTerminal(map: Map<string, string>, name, cssSelector: CssSelector,
matchedCallback /*: (CssSelector, any) => void*/): boolean {
if (isBlank(map) || isBlank(name)) { if (isBlank(map) || isBlank(name)) {
return false; return false;
} }
@ -301,11 +319,12 @@ export class SelectorMatcher {
return result; return result;
} }
_matchPartial(map:Map<string,string> = null, name, cssSelector, matchedCallback):boolean { _matchPartial(map: Map<string, string>, name, cssSelector: CssSelector,
matchedCallback /*: (CssSelector, any) => void*/): boolean {
if (isBlank(map) || isBlank(name)) { if (isBlank(map) || isBlank(name)) {
return false; return false;
} }
var nestedSelector = MapWrapper.get(map, name) var nestedSelector = MapWrapper.get(map, name);
if (isBlank(nestedSelector)) { if (isBlank(nestedSelector)) {
return false; return false;
} }
@ -334,21 +353,22 @@ class SelectorContext {
cbContext; // callback context cbContext; // callback context
listContext: SelectorListContext; listContext: SelectorListContext;
constructor(selector:CssSelector, cbContext, listContext: SelectorListContext) { constructor(selector: CssSelector, cbContext: any, listContext: SelectorListContext) {
this.selector = selector; this.selector = selector;
this.notSelector = selector.notSelector; this.notSelector = selector.notSelector;
this.cbContext = cbContext; this.cbContext = cbContext;
this.listContext = listContext; this.listContext = listContext;
} }
finalize(cssSelector: CssSelector, callback) { finalize(cssSelector: CssSelector, callback /*: (CssSelector, any) => void*/) {
var result = true; var result = true;
if (isPresent(this.notSelector) && (isBlank(this.listContext) || !this.listContext.alreadyMatched)) { if (isPresent(this.notSelector) &&
var notMatcher = new SelectorMatcher(); (isBlank(this.listContext) || !this.listContext.alreadyMatched)) {
notMatcher.addSelectable(this.notSelector, null, null); var notMatcher = SelectorMatcher.createNotMatcher(this.notSelector);
result = !notMatcher.match(cssSelector, null); result = !notMatcher.match(cssSelector, null);
} }
if (result && isPresent(callback) && (isBlank(this.listContext) || !this.listContext.alreadyMatched)) { if (result && isPresent(callback) &&
(isBlank(this.listContext) || !this.listContext.alreadyMatched)) {
if (isPresent(this.listContext)) { if (isPresent(this.listContext)) {
this.listContext.alreadyMatched = true; this.listContext.alreadyMatched = true;
} }

View File

@ -1,4 +1,4 @@
import {Injectable} from 'angular2/src/di/annotations_impl'; import {Injectable} from 'angular2/di';
import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang'; import {isBlank, isPresent, BaseException, stringify} from 'angular2/src/facade/lang';
import {Map, MapWrapper, StringMapWrapper, StringMap} from 'angular2/src/facade/collection'; import {Map, MapWrapper, StringMapWrapper, StringMap} from 'angular2/src/facade/collection';
import {PromiseWrapper, Promise} from 'angular2/src/facade/async'; import {PromiseWrapper, Promise} from 'angular2/src/facade/async';
@ -16,14 +16,14 @@ import {UrlResolver} from 'angular2/src/services/url_resolver';
@Injectable() @Injectable()
export class TemplateLoader { export class TemplateLoader {
_xhr: XHR; _xhr: XHR;
_htmlCache: StringMap; _htmlCache: StringMap<string, /*element*/ any>;
constructor(xhr: XHR, urlResolver: UrlResolver) { constructor(xhr: XHR, urlResolver: UrlResolver) {
this._xhr = xhr; this._xhr = xhr;
this._htmlCache = StringMapWrapper.create(); this._htmlCache = StringMapWrapper.create();
} }
load(template: ViewDefinition):Promise { load(template: ViewDefinition): Promise</*element*/ any> {
if (isPresent(template.template)) { if (isPresent(template.template)) {
return PromiseWrapper.resolve(DOM.createTemplate(template.template)); return PromiseWrapper.resolve(DOM.createTemplate(template.template));
} }

View File

@ -10,13 +10,10 @@ import {CompileControl} from './compile_control';
/** /**
* Parses interpolations in direct text child nodes of the current element. * Parses interpolations in direct text child nodes of the current element.
*/ */
export class TextInterpolationParser extends CompileStep { export class TextInterpolationParser implements CompileStep {
_parser: Parser; _parser: Parser;
constructor(parser:Parser) { constructor(parser: Parser) { this._parser = parser; }
super();
this._parser = parser;
}
process(parent: CompileElement, current: CompileElement, control: CompileControl) { process(parent: CompileElement, current: CompileElement, control: CompileControl) {
if (!current.compileChildren) { if (!current.compileChildren) {

View File

@ -25,20 +25,18 @@ import {dashCaseToCamelCase} from '../util';
* as we want to do locate elements with bindings using `getElementsByClassName` later on, * as we want to do locate elements with bindings using `getElementsByClassName` later on,
* which should not descend into the nested view. * which should not descend into the nested view.
*/ */
export class ViewSplitter extends CompileStep { export class ViewSplitter implements CompileStep {
_parser: Parser; _parser: Parser;
constructor(parser:Parser) { constructor(parser: Parser) { this._parser = parser; }
super();
this._parser = parser;
}
process(parent: CompileElement, current: CompileElement, control: CompileControl) { process(parent: CompileElement, current: CompileElement, control: CompileControl) {
var attrs = current.attrs(); var attrs = current.attrs();
var templateBindings = MapWrapper.get(attrs, 'template'); var templateBindings = MapWrapper.get(attrs, 'template');
var hasTemplateBinding = isPresent(templateBindings); var hasTemplateBinding = isPresent(templateBindings);
// look for template shortcuts such as *ng-if="condition" and treat them as template="if condition" // look for template shortcuts such as *ng-if="condition" and treat them as template="if
// condition"
MapWrapper.forEach(attrs, (attrValue, attrName) => { MapWrapper.forEach(attrs, (attrValue, attrName) => {
if (StringWrapper.startsWith(attrName, '*')) { if (StringWrapper.startsWith(attrName, '*')) {
var key = StringWrapper.substring(attrName, 1); // remove the star var key = StringWrapper.substring(attrName, 1); // remove the star
@ -67,7 +65,8 @@ export class ViewSplitter extends CompileStep {
this._moveChildNodes(DOM.content(current.element), DOM.content(viewRoot.element)); this._moveChildNodes(DOM.content(current.element), DOM.content(viewRoot.element));
control.addChild(viewRoot); control.addChild(viewRoot);
} }
} if (hasTemplateBinding) { }
if (hasTemplateBinding) {
var newParent = new CompileElement(DOM.createTemplate('')); var newParent = new CompileElement(DOM.createTemplate(''));
newParent.inheritedProtoView = current.inheritedProtoView; newParent.inheritedProtoView = current.inheritedProtoView;
newParent.inheritedElementBinder = current.inheritedElementBinder; newParent.inheritedElementBinder = current.inheritedElementBinder;
@ -103,18 +102,16 @@ export class ViewSplitter extends CompileStep {
} }
_parseTemplateBindings(templateBindings: string, compileElement: CompileElement) { _parseTemplateBindings(templateBindings: string, compileElement: CompileElement) {
var bindings = this._parser.parseTemplateBindings(templateBindings, compileElement.elementDescription); var bindings =
this._parser.parseTemplateBindings(templateBindings, compileElement.elementDescription);
for (var i = 0; i < bindings.length; i++) { for (var i = 0; i < bindings.length; i++) {
var binding = bindings[i]; var binding = bindings[i];
if (binding.keyIsVar) { if (binding.keyIsVar) {
compileElement.bindElement().bindVariable( compileElement.bindElement().bindVariable(dashCaseToCamelCase(binding.key), binding.name);
dashCaseToCamelCase(binding.key), binding.name
);
MapWrapper.set(compileElement.attrs(), binding.key, binding.name); MapWrapper.set(compileElement.attrs(), binding.key, binding.name);
} else if (isPresent(binding.expression)) { } else if (isPresent(binding.expression)) {
compileElement.bindElement().bindProperty( compileElement.bindElement().bindProperty(dashCaseToCamelCase(binding.key),
dashCaseToCamelCase(binding.key), binding.expression binding.expression);
);
MapWrapper.set(compileElement.attrs(), binding.key, binding.expression.source); MapWrapper.set(compileElement.attrs(), binding.key, binding.expression.source);
} else { } else {
DOM.setAttribute(compileElement.element, binding.key, ''); DOM.setAttribute(compileElement.element, binding.key, '');

View File

@ -6,7 +6,7 @@ import {DirectiveMetadata} from 'angular2/src/render/api';
* Converts a [DirectiveMetadata] to a map representation. This creates a copy, * Converts a [DirectiveMetadata] to a map representation. This creates a copy,
* that is, subsequent changes to `meta` will not be mirrored in the map. * that is, subsequent changes to `meta` will not be mirrored in the map.
*/ */
export function directiveMetadataToMap(meta: DirectiveMetadata): Map { export function directiveMetadataToMap(meta: DirectiveMetadata): Map<string, any> {
return MapWrapper.createFromPairs([ return MapWrapper.createFromPairs([
['id', meta.id], ['id', meta.id],
['selector', meta.selector], ['selector', meta.selector],
@ -27,18 +27,18 @@ export function directiveMetadataToMap(meta: DirectiveMetadata): Map {
* [DirectiveMetadata] object. This creates a copy, that is, subsequent changes * [DirectiveMetadata] object. This creates a copy, that is, subsequent changes
* to `map` will not be mirrored in the [DirectiveMetadata] object. * to `map` will not be mirrored in the [DirectiveMetadata] object.
*/ */
export function directiveMetadataFromMap(map: Map): DirectiveMetadata { export function directiveMetadataFromMap(map: Map<string, any>): DirectiveMetadata {
return new DirectiveMetadata({ return new DirectiveMetadata({
id: MapWrapper.get(map, 'id'), id:<string>MapWrapper.get(map, 'id'),
selector: MapWrapper.get(map, 'selector'), selector:<string>MapWrapper.get(map, 'selector'),
compileChildren: MapWrapper.get(map, 'compileChildren'), compileChildren:<boolean>MapWrapper.get(map, 'compileChildren'),
hostListeners: _cloneIfPresent(MapWrapper.get(map, 'hostListeners')), hostListeners:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostListeners')),
hostProperties: _cloneIfPresent(MapWrapper.get(map, 'hostProperties')), hostProperties:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostProperties')),
hostActions: _cloneIfPresent(MapWrapper.get(map, 'hostActions')), hostActions:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostActions')),
hostAttributes: _cloneIfPresent(MapWrapper.get(map, 'hostAttributes')), hostAttributes:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostAttributes')),
properties: _cloneIfPresent(MapWrapper.get(map, 'properties')), properties:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'properties')),
readAttributes: _cloneIfPresent(MapWrapper.get(map, 'readAttributes')), readAttributes:<List<string>>_cloneIfPresent(MapWrapper.get(map, 'readAttributes')),
type: MapWrapper.get(map, 'type') type:<number>MapWrapper.get(map, 'type')
}); });
} }

View File

@ -1,4 +1,4 @@
import {Inject, Injectable} from 'angular2/src/di/annotations_impl'; import {Inject, Injectable} from 'angular2/di';
import {int, isPresent, isBlank, BaseException, RegExpWrapper} from 'angular2/src/facade/lang'; import {int, isPresent, isBlank, BaseException, RegExpWrapper} from 'angular2/src/facade/lang';
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
@ -25,14 +25,16 @@ export class DomRenderer extends Renderer {
_shadowDomStrategy: ShadowDomStrategy; _shadowDomStrategy: ShadowDomStrategy;
_document; _document;
constructor(eventManager:EventManager, shadowDomStrategy:ShadowDomStrategy, @Inject(DOCUMENT_TOKEN) document) { constructor(eventManager: EventManager, shadowDomStrategy: ShadowDomStrategy,
@Inject(DOCUMENT_TOKEN) document) {
super(); super();
this._eventManager = eventManager; this._eventManager = eventManager;
this._shadowDomStrategy = shadowDomStrategy; this._shadowDomStrategy = shadowDomStrategy;
this._document = document; this._document = document;
} }
createRootHostView(hostProtoViewRef:RenderProtoViewRef, hostElementSelector:string):RenderViewRef { createRootHostView(hostProtoViewRef: RenderProtoViewRef,
hostElementSelector: string): RenderViewRef {
var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef); var hostProtoView = resolveInternalDomProtoView(hostProtoViewRef);
var element = DOM.querySelector(this._document, hostElementSelector); var element = DOM.querySelector(this._document, hostElementSelector);
if (isBlank(element)) { if (isBlank(element)) {
@ -55,7 +57,8 @@ export class DomRenderer extends Renderer {
// noop for now // noop for now
} }
attachComponentView(hostViewRef:RenderViewRef, elementIndex:number, componentViewRef:RenderViewRef) { attachComponentView(hostViewRef: RenderViewRef, elementIndex: number,
componentViewRef: RenderViewRef) {
var hostView = resolveInternalDomView(hostViewRef); var hostView = resolveInternalDomView(hostViewRef);
var componentView = resolveInternalDomView(componentViewRef); var componentView = resolveInternalDomView(componentViewRef);
var element = hostView.boundElements[elementIndex]; var element = hostView.boundElements[elementIndex];
@ -69,7 +72,7 @@ export class DomRenderer extends Renderer {
componentView.shadowRoot = shadowRoot; componentView.shadowRoot = shadowRoot;
} }
setComponentViewRootNodes(componentViewRef:RenderViewRef, rootNodes:List) { setComponentViewRootNodes(componentViewRef: RenderViewRef, rootNodes: List</*node*/ any>) {
var componentView = resolveInternalDomView(componentViewRef); var componentView = resolveInternalDomView(componentViewRef);
this._removeViewNodes(componentView); this._removeViewNodes(componentView);
componentView.rootNodes = rootNodes; componentView.rootNodes = rootNodes;
@ -81,7 +84,8 @@ export class DomRenderer extends Renderer {
return hostView.boundElements[0]; return hostView.boundElements[0];
} }
detachComponentView(hostViewRef:RenderViewRef, boundElementIndex:number, componentViewRef:RenderViewRef) { detachComponentView(hostViewRef: RenderViewRef, boundElementIndex: number,
componentViewRef: RenderViewRef) {
var hostView = resolveInternalDomView(hostViewRef); var hostView = resolveInternalDomView(hostViewRef);
var componentView = resolveInternalDomView(componentViewRef); var componentView = resolveInternalDomView(componentViewRef);
this._removeViewNodes(componentView); this._removeViewNodes(componentView);
@ -93,7 +97,8 @@ export class DomRenderer extends Renderer {
componentView.shadowRoot = null; componentView.shadowRoot = null;
} }
attachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) { attachViewInContainer(parentViewRef: RenderViewRef, boundElementIndex: number, atIndex: number,
viewRef: RenderViewRef) {
var parentView = resolveInternalDomView(parentViewRef); var parentView = resolveInternalDomView(parentViewRef);
var view = resolveInternalDomView(viewRef); var view = resolveInternalDomView(viewRef);
var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex); var viewContainer = this._getOrCreateViewContainer(parentView, boundElementIndex);
@ -118,7 +123,8 @@ export class DomRenderer extends Renderer {
} }
} }
detachViewInContainer(parentViewRef:RenderViewRef, boundElementIndex:number, atIndex:number, viewRef:RenderViewRef) { detachViewInContainer(parentViewRef: RenderViewRef, boundElementIndex: number, atIndex: number,
viewRef: RenderViewRef) {
var parentView = resolveInternalDomView(parentViewRef); var parentView = resolveInternalDomView(parentViewRef);
var view = resolveInternalDomView(viewRef); var view = resolveInternalDomView(viewRef);
var viewContainer = parentView.viewContainers[boundElementIndex]; var viewContainer = parentView.viewContainers[boundElementIndex];
@ -157,7 +163,8 @@ export class DomRenderer extends Renderer {
if (isPresent(binder.globalEvents)) { if (isPresent(binder.globalEvents)) {
for (var i = 0; i < binder.globalEvents.length; i++) { for (var i = 0; i < binder.globalEvents.length; i++) {
var globalEvent = binder.globalEvents[i]; var globalEvent = binder.globalEvents[i];
var remover = this._createGlobalEventListener(view, binderIdx, globalEvent.name, globalEvent.target, globalEvent.fullName); var remover = this._createGlobalEventListener(view, binderIdx, globalEvent.name,
globalEvent.target, globalEvent.fullName);
ListWrapper.push(view.eventHandlerRemovers, remover); ListWrapper.push(view.eventHandlerRemovers, remover);
} }
} }
@ -179,12 +186,14 @@ export class DomRenderer extends Renderer {
view.hydrated = false; view.hydrated = false;
} }
setElementProperty(viewRef:RenderViewRef, elementIndex:number, propertyName:string, propertyValue:any):void { setElementProperty(viewRef: RenderViewRef, elementIndex: number, propertyName: string,
propertyValue: any): void {
var view = resolveInternalDomView(viewRef); var view = resolveInternalDomView(viewRef);
view.setElementProperty(elementIndex, propertyName, propertyValue); view.setElementProperty(elementIndex, propertyName, propertyValue);
} }
callAction(viewRef:RenderViewRef, elementIndex:number, actionExpression:string, actionArgs:any):void { callAction(viewRef: RenderViewRef, elementIndex: number, actionExpression: string,
actionArgs: any): void {
var view = resolveInternalDomView(viewRef); var view = resolveInternalDomView(viewRef);
view.callAction(elementIndex, actionExpression, actionArgs); view.callAction(elementIndex, actionExpression, actionArgs);
} }
@ -200,10 +209,12 @@ export class DomRenderer extends Renderer {
} }
_createView(protoView: DomProtoView, inplaceElement): DomView { _createView(protoView: DomProtoView, inplaceElement): DomView {
var rootElementClone = isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element); var rootElementClone =
isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element);
var elementsWithBindingsDynamic; var elementsWithBindingsDynamic;
if (protoView.isTemplateElement) { if (protoView.isTemplateElement) {
elementsWithBindingsDynamic = DOM.querySelectorAll(DOM.content(rootElementClone), NG_BINDING_CLASS_SELECTOR); elementsWithBindingsDynamic =
DOM.querySelectorAll(DOM.content(rootElementClone), NG_BINDING_CLASS_SELECTOR);
} else { } else {
elementsWithBindingsDynamic = DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS); elementsWithBindingsDynamic = DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS);
} }
@ -216,7 +227,8 @@ export class DomRenderer extends Renderer {
var viewRootNodes; var viewRootNodes;
if (protoView.isTemplateElement) { if (protoView.isTemplateElement) {
var childNode = DOM.firstChild(DOM.content(rootElementClone)); var childNode = DOM.firstChild(DOM.content(rootElementClone));
viewRootNodes = []; // TODO(perf): Should be fixed size, since we could pre-compute in in DomProtoView viewRootNodes =
[]; // TODO(perf): Should be fixed size, since we could pre-compute in in DomProtoView
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array! // Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
while (childNode != null) { while (childNode != null) {
ListWrapper.push(viewRootNodes, childNode); ListWrapper.push(viewRootNodes, childNode);
@ -255,10 +267,7 @@ export class DomRenderer extends Renderer {
contentTags[binderIdx] = contentTag; contentTags[binderIdx] = contentTag;
} }
var view = new DomView( var view = new DomView(protoView, viewRootNodes, boundTextNodes, boundElements, contentTags);
protoView, viewRootNodes,
boundTextNodes, boundElements, contentTags
);
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) { for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
var binder = binders[binderIdx]; var binder = binders[binderIdx];
@ -281,7 +290,8 @@ export class DomRenderer extends Renderer {
// events // events
if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) { if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) {
for (var i = 0; i < binder.localEvents.length; i++) { for (var i = 0; i < binder.localEvents.length; i++) {
this._createEventListener(view, element, binderIdx, binder.localEvents[i].name, binder.eventLocals); this._createEventListener(view, element, binderIdx, binder.localEvents[i].name,
binder.eventLocals);
} }
} }
} }
@ -290,9 +300,8 @@ export class DomRenderer extends Renderer {
} }
_createEventListener(view, element, elementIndex, eventName, eventLocals) { _createEventListener(view, element, elementIndex, eventName, eventLocals) {
this._eventManager.addEventListener(element, eventName, (event) => { this._eventManager.addEventListener(
view.dispatchEvent(elementIndex, eventName, event); element, eventName, (event) => { view.dispatchEvent(elementIndex, eventName, event); });
});
} }
@ -327,9 +336,7 @@ export class DomRenderer extends Renderer {
} }
_createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function { _createGlobalEventListener(view, elementIndex, eventName, eventTarget, fullName): Function {
return this._eventManager.addGlobalEventListener(eventTarget, eventName, (event) => { return this._eventManager.addGlobalEventListener(
view.dispatchEvent(elementIndex, fullName, event); eventTarget, eventName, (event) => { view.dispatchEvent(elementIndex, fullName, event); });
});
} }
} }

View File

@ -20,18 +20,18 @@ export class EventManager {
addEventListener(element, eventName: string, handler: Function) { addEventListener(element, eventName: string, handler: Function) {
var withoutBubbleSymbol = this._removeBubbleSymbol(eventName); var withoutBubbleSymbol = this._removeBubbleSymbol(eventName);
var plugin = this._findPluginFor(withoutBubbleSymbol); var plugin = this._findPluginFor(withoutBubbleSymbol);
plugin.addEventListener(element, withoutBubbleSymbol, handler, withoutBubbleSymbol != eventName); plugin.addEventListener(element, withoutBubbleSymbol, handler,
withoutBubbleSymbol != eventName);
} }
addGlobalEventListener(target: string, eventName: string, handler: Function): Function { addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
var withoutBubbleSymbol = this._removeBubbleSymbol(eventName); var withoutBubbleSymbol = this._removeBubbleSymbol(eventName);
var plugin = this._findPluginFor(withoutBubbleSymbol); var plugin = this._findPluginFor(withoutBubbleSymbol);
return plugin.addGlobalEventListener(target, withoutBubbleSymbol, handler, withoutBubbleSymbol != eventName); return plugin.addGlobalEventListener(target, withoutBubbleSymbol, handler,
withoutBubbleSymbol != eventName);
} }
getZone(): NgZone { getZone(): NgZone { return this._zone; }
return this._zone;
}
_findPluginFor(eventName: string): EventManagerPlugin { _findPluginFor(eventName: string): EventManagerPlugin {
var plugins = this._plugins; var plugins = this._plugins;
@ -56,15 +56,14 @@ export class EventManagerPlugin {
// That is equivalent to having supporting $event.target // That is equivalent to having supporting $event.target
// The bubbling flag (currently ^) is stripped before calling the supports and // The bubbling flag (currently ^) is stripped before calling the supports and
// addEventListener methods. // addEventListener methods.
supports(eventName: string): boolean { supports(eventName: string): boolean { return false; }
return false;
}
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) { addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
throw "not implemented"; throw "not implemented";
} }
addGlobalEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean): Function { addGlobalEventListener(element, eventName: string, handler: Function,
shouldSupportBubble: boolean): Function {
throw "not implemented"; throw "not implemented";
} }
} }
@ -74,37 +73,30 @@ export class DomEventsPlugin extends EventManagerPlugin {
// This plugin should come last in the list of plugins, because it accepts all // This plugin should come last in the list of plugins, because it accepts all
// events. // events.
supports(eventName: string): boolean { supports(eventName: string): boolean { return true; }
return true;
}
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) { addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
var outsideHandler = this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone); var outsideHandler =
this.manager._zone.runOutsideAngular(() => { this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone);
DOM.on(element, eventName, outsideHandler); this.manager._zone.runOutsideAngular(() => { DOM.on(element, eventName, outsideHandler); });
});
} }
addGlobalEventListener(target:string, eventName: string, handler: Function, shouldSupportBubble: boolean): Function { addGlobalEventListener(target: string, eventName: string, handler: Function,
shouldSupportBubble: boolean): Function {
var element = DOM.getGlobalEventTarget(target); var element = DOM.getGlobalEventTarget(target);
var outsideHandler = this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone); var outsideHandler =
return this.manager._zone.runOutsideAngular(() => { this._getOutsideHandler(shouldSupportBubble, element, handler, this.manager._zone);
return DOM.onAndCancel(element, eventName, outsideHandler); return this.manager._zone.runOutsideAngular(
}); () => { return DOM.onAndCancel(element, eventName, outsideHandler); });
} }
_getOutsideHandler(shouldSupportBubble: boolean, element, handler: Function, zone: NgZone) { _getOutsideHandler(shouldSupportBubble: boolean, element, handler: Function, zone: NgZone) {
return shouldSupportBubble ? return shouldSupportBubble ? DomEventsPlugin.bubbleCallback(element, handler, zone) :
DomEventsPlugin.bubbleCallback(element, handler, zone) :
DomEventsPlugin.sameElementCallback(element, handler, zone); DomEventsPlugin.sameElementCallback(element, handler, zone);
} }
static sameElementCallback(element, handler, zone) { static sameElementCallback(element, handler, zone) {
return (event) => { return (event) => { if (event.target === element) { zone.run(() => handler(event)); } };
if (event.target === element) {
zone.run(() => handler(event));
}
};
} }
static bubbleCallback(element, handler, zone) { static bubbleCallback(element, handler, zone) {

View File

@ -41,9 +41,7 @@ var _eventNames = {
export class HammerGesturesPluginCommon extends EventManagerPlugin { export class HammerGesturesPluginCommon extends EventManagerPlugin {
constructor() { constructor() { super(); }
super();
}
supports(eventName: string): boolean { supports(eventName: string): boolean {
eventName = eventName.toLowerCase(); eventName = eventName.toLowerCase();

View File

@ -2,9 +2,7 @@ import {HammerGesturesPluginCommon} from './hammer_common';
import {isPresent, BaseException} from 'angular2/src/facade/lang'; import {isPresent, BaseException} from 'angular2/src/facade/lang';
export class HammerGesturesPlugin extends HammerGesturesPluginCommon { export class HammerGesturesPlugin extends HammerGesturesPluginCommon {
constructor() { constructor() { super(); }
super();
}
supports(eventName: string): boolean { supports(eventName: string): boolean {
if (!super.supports(eventName)) return false; if (!super.supports(eventName)) return false;
@ -17,7 +15,8 @@ export class HammerGesturesPlugin extends HammerGesturesPluginCommon {
} }
addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) { addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
if (shouldSupportBubble) throw new BaseException('Hammer.js plugin does not support bubbling gestures.'); if (shouldSupportBubble)
throw new BaseException('Hammer.js plugin does not support bubbling gestures.');
var zone = this.manager.getZone(); var zone = this.manager.getZone();
eventName = eventName.toLowerCase(); eventName = eventName.toLowerCase();
@ -27,11 +26,7 @@ export class HammerGesturesPlugin extends HammerGesturesPluginCommon {
mc.get('pinch').set({enable: true}); mc.get('pinch').set({enable: true});
mc.get('rotate').set({enable: true}); mc.get('rotate').set({enable: true});
mc.on(eventName, function (eventObj) { mc.on(eventName, function(eventObj) { zone.run(function() { handler(eventObj); }); });
zone.run(function () {
handler(eventObj);
});
});
}); });
} }
} }

View File

@ -1,10 +1,18 @@
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {isPresent, isBlank, StringWrapper, RegExpWrapper, BaseException, NumberWrapper} from 'angular2/src/facade/lang'; import {
isPresent,
isBlank,
StringWrapper,
RegExpWrapper,
BaseException,
NumberWrapper
} from 'angular2/src/facade/lang';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {EventManagerPlugin} from './event_manager'; import {EventManagerPlugin} from './event_manager';
var modifierKeys = ['alt', 'control', 'meta', 'shift']; var modifierKeys = ['alt', 'control', 'meta', 'shift'];
var modifierKeyGetters = { var modifierKeyGetters =
{
'alt': (event) => event.altKey, 'alt': (event) => event.altKey,
'control': (event) => event.ctrlKey, 'control': (event) => event.ctrlKey,
'meta': (event) => event.metaKey, 'meta': (event) => event.metaKey,
@ -12,20 +20,18 @@ var modifierKeyGetters = {
} }
export class KeyEventsPlugin extends EventManagerPlugin { export class KeyEventsPlugin extends EventManagerPlugin {
constructor() { constructor() { super(); }
super();
}
supports(eventName: string): boolean { supports(eventName: string): boolean {
return isPresent(KeyEventsPlugin.parseEventName(eventName)); return isPresent(KeyEventsPlugin.parseEventName(eventName));
} }
addEventListener(element, eventName: string, handler: Function, addEventListener(element, eventName: string, handler: Function, shouldSupportBubble: boolean) {
shouldSupportBubble: boolean) {
var parsedEvent = KeyEventsPlugin.parseEventName(eventName); var parsedEvent = KeyEventsPlugin.parseEventName(eventName);
var outsideHandler = KeyEventsPlugin.eventCallback(element, shouldSupportBubble, var outsideHandler = KeyEventsPlugin.eventCallback(element, shouldSupportBubble,
StringMapWrapper.get(parsedEvent, 'fullKey'), handler, this.manager.getZone()); StringMapWrapper.get(parsedEvent, 'fullKey'),
handler, this.manager.getZone());
this.manager.getZone().runOutsideAngular(() => { this.manager.getZone().runOutsideAngular(() => {
DOM.on(element, StringMapWrapper.get(parsedEvent, 'domEventName'), outsideHandler); DOM.on(element, StringMapWrapper.get(parsedEvent, 'domEventName'), outsideHandler);
@ -36,7 +42,9 @@ export class KeyEventsPlugin extends EventManagerPlugin {
eventName = eventName.toLowerCase(); eventName = eventName.toLowerCase();
var parts = eventName.split('.'); var parts = eventName.split('.');
var domEventName = ListWrapper.removeAt(parts, 0); var domEventName = ListWrapper.removeAt(parts, 0);
if ((parts.length === 0) || !(StringWrapper.equals(domEventName, 'keydown') || StringWrapper.equals(domEventName, 'keyup'))) { if ((parts.length === 0) ||
!(StringWrapper.equals(domEventName, 'keydown') ||
StringWrapper.equals(domEventName, 'keyup'))) {
return null; return null;
} }
var key = ListWrapper.removeLast(parts); var key = ListWrapper.removeLast(parts);
@ -55,10 +63,7 @@ export class KeyEventsPlugin extends EventManagerPlugin {
return null; return null;
} }
return { return {'domEventName': domEventName, 'fullKey': fullKey};
'domEventName': domEventName,
'fullKey': fullKey
};
} }
static getEventFullKey(event): string { static getEventFullKey(event): string {
@ -83,8 +88,7 @@ export class KeyEventsPlugin extends EventManagerPlugin {
} }
static eventCallback(element, shouldSupportBubble, fullKey, handler, zone) { static eventCallback(element, shouldSupportBubble, fullKey, handler, zone) {
return (event) => { return (event) => { var correctElement = shouldSupportBubble || event.target === element;
var correctElement = shouldSupportBubble || event.target === element;
if (correctElement && KeyEventsPlugin.getEventFullKey(event) === fullKey) { if (correctElement && KeyEventsPlugin.getEventFullKey(event) === fullKey) {
zone.run(() => handler(event)); zone.run(() => handler(event));
} }

View File

@ -4,8 +4,8 @@ import {isPresent} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
class ContentStrategy { class ContentStrategy {
nodes:List; nodes: List</*node*/ any>;
insert(nodes:List){} insert(nodes: List</*node*/ any>) {}
} }
/** /**
@ -26,7 +26,7 @@ class RenderedContent extends ContentStrategy {
// Inserts the nodes in between the start and end scripts. // Inserts the nodes in between the start and end scripts.
// Previous content is removed. // Previous content is removed.
insert(nodes:List) { insert(nodes: List</*node*/ any>) {
this.nodes = nodes; this.nodes = nodes;
DOM.insertAllBefore(this.endScript, nodes); DOM.insertAllBefore(this.endScript, nodes);
this._removeNodesUntil(ListWrapper.isEmpty(nodes) ? this.endScript : nodes[0]); this._removeNodesUntil(ListWrapper.isEmpty(nodes) ? this.endScript : nodes[0]);
@ -34,8 +34,7 @@ class RenderedContent extends ContentStrategy {
_removeNodesUntil(node) { _removeNodesUntil(node) {
var p = DOM.parentElement(this.beginScript); var p = DOM.parentElement(this.beginScript);
for (var next = DOM.nextSibling(this.beginScript); for (var next = DOM.nextSibling(this.beginScript); next !== node;
next !== node;
next = DOM.nextSibling(this.beginScript)) { next = DOM.nextSibling(this.beginScript)) {
DOM.removeChild(p, next); DOM.removeChild(p, next);
} }
@ -56,7 +55,7 @@ class IntermediateContent extends ContentStrategy {
this.destinationLightDom = destinationLightDom; this.destinationLightDom = destinationLightDom;
} }
insert(nodes:List) { insert(nodes: List</*node*/ any>) {
this.nodes = nodes; this.nodes = nodes;
this.destinationLightDom.redistribute(); this.destinationLightDom.redistribute();
} }
@ -65,7 +64,7 @@ class IntermediateContent extends ContentStrategy {
export class Content { export class Content {
select: string; select: string;
_strategy:ContentStrategy; private _strategy: ContentStrategy;
contentStartElement; contentStartElement;
constructor(contentStartEl, selector: string) { constructor(contentStartEl, selector: string) {
@ -75,16 +74,11 @@ export class Content {
} }
init(destinationLightDom: ldModule.LightDom) { init(destinationLightDom: ldModule.LightDom) {
this._strategy = isPresent(destinationLightDom) ? this._strategy = isPresent(destinationLightDom) ? new IntermediateContent(destinationLightDom) :
new IntermediateContent(destinationLightDom) :
new RenderedContent(this.contentStartElement); new RenderedContent(this.contentStartElement);
} }
nodes():List { nodes(): List</*node*/ any> { return this._strategy.nodes; }
return this._strategy.nodes;
}
insert(nodes:List) { insert(nodes: List</*node*/ any>) { this._strategy.insert(nodes); }
this._strategy.insert(nodes);
}
} }

View File

@ -7,7 +7,11 @@ import {StyleInliner} from 'angular2/src/render/dom/shadow_dom/style_inliner';
import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver'; import {StyleUrlResolver} from 'angular2/src/render/dom/shadow_dom/style_url_resolver';
import {EmulatedUnscopedShadowDomStrategy} from './emulated_unscoped_shadow_dom_strategy'; import {EmulatedUnscopedShadowDomStrategy} from './emulated_unscoped_shadow_dom_strategy';
import { import {
getContentAttribute, getHostAttribute, getComponentId, shimCssForComponent, insertStyleElement getContentAttribute,
getHostAttribute,
getComponentId,
shimCssForComponent,
insertStyleElement
} from './util'; } from './util';
/** /**
@ -30,27 +34,26 @@ export class EmulatedScopedShadowDomStrategy extends EmulatedUnscopedShadowDomSt
this.styleInliner = styleInliner; this.styleInliner = styleInliner;
} }
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise { processStyleElement(hostComponentId: string, templateUrl: string, styleEl): Promise<any> {
var cssText = DOM.getText(styleEl); var cssText = DOM.getText(styleEl);
cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl); cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl);
var css = this.styleInliner.inlineImports(cssText, templateUrl); var inlinedCss = this.styleInliner.inlineImports(cssText, templateUrl);
if (PromiseWrapper.isPromise(css)) { if (isPresent(inlinedCss.asyncResult)) {
DOM.setText(styleEl, ''); DOM.setText(styleEl, '');
return css.then((css) => { return inlinedCss.asyncResult.then((css) => {
css = shimCssForComponent(css, hostComponentId); css = shimCssForComponent(css, hostComponentId);
DOM.setText(styleEl, css); DOM.setText(styleEl, css);
}); });
} else { } else {
css = shimCssForComponent(css, hostComponentId); var css = shimCssForComponent(inlinedCss.syncResult, hostComponentId);
DOM.setText(styleEl, css); DOM.setText(styleEl, css);
}
DOM.remove(styleEl); DOM.remove(styleEl);
insertStyleElement(this.styleHost, styleEl); insertStyleElement(this.styleHost, styleEl);
return null; return null;
} }
}
processElement(hostComponentId: string, elementComponentId: string, element) { processElement(hostComponentId: string, elementComponentId: string, element) {
// Shim the element as a child of the compiled component // Shim the element as a child of the compiled component

View File

@ -28,19 +28,15 @@ export class EmulatedUnscopedShadowDomStrategy extends ShadowDomStrategy {
this.styleHost = styleHost; this.styleHost = styleHost;
} }
hasNativeContentElement():boolean { hasNativeContentElement(): boolean { return false; }
return false;
}
prepareShadowRoot(el) { prepareShadowRoot(el) { return el; }
return el;
}
constructLightDom(lightDomView: viewModule.DomView, el): LightDom { constructLightDom(lightDomView: viewModule.DomView, el): LightDom {
return new LightDom(lightDomView, el); return new LightDom(lightDomView, el);
} }
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise { processStyleElement(hostComponentId: string, templateUrl: string, styleEl): Promise<any> {
var cssText = DOM.getText(styleEl); var cssText = DOM.getText(styleEl);
cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl); cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl);
DOM.setText(styleEl, cssText); DOM.setText(styleEl, cssText);

View File

@ -25,28 +25,22 @@ export class LightDom {
// The shadow DOM // The shadow DOM
shadowDomView: viewModule.DomView; shadowDomView: viewModule.DomView;
// The nodes of the light DOM // The nodes of the light DOM
nodes:List; nodes: List</*node*/ any>;
roots:List<_Root>; private _roots: List<_Root>;
constructor(lightDomView: viewModule.DomView, element) { constructor(lightDomView: viewModule.DomView, element) {
this.lightDomView = lightDomView; this.lightDomView = lightDomView;
this.nodes = DOM.childNodesAsList(element); this.nodes = DOM.childNodesAsList(element);
this.roots = null; this._roots = null;
this.shadowDomView = null; this.shadowDomView = null;
} }
attachShadowDomView(shadowDomView:viewModule.DomView) { attachShadowDomView(shadowDomView: viewModule.DomView) { this.shadowDomView = shadowDomView; }
this.shadowDomView = shadowDomView;
}
detachShadowDomView() { detachShadowDomView() { this.shadowDomView = null; }
this.shadowDomView = null;
}
redistribute() { redistribute() { redistributeNodes(this.contentTags(), this.expandedDomNodes()); }
redistributeNodes(this.contentTags(), this.expandedDomNodes());
}
contentTags(): List<Content> { contentTags(): List<Content> {
if (isPresent(this.shadowDomView)) { if (isPresent(this.shadowDomView)) {
@ -57,7 +51,7 @@ export class LightDom {
} }
// Collects the Content directives from the view and all its child views // Collects the Content directives from the view and all its child views
_collectAllContentTags(view: viewModule.DomView, acc:List<Content>):List<Content> { private _collectAllContentTags(view: viewModule.DomView, acc: List<Content>): List<Content> {
var contentTags = view.contentTags; var contentTags = view.contentTags;
var vcs = view.viewContainers; var vcs = view.viewContainers;
for (var i = 0; i < vcs.length; i++) { for (var i = 0; i < vcs.length; i++) {
@ -67,9 +61,8 @@ export class LightDom {
ListWrapper.push(acc, contentTag); ListWrapper.push(acc, contentTag);
} }
if (isPresent(vc)) { if (isPresent(vc)) {
ListWrapper.forEach(vc.contentTagContainers(), (view) => { ListWrapper.forEach(vc.contentTagContainers(),
this._collectAllContentTags(view, acc); (view) => { this._collectAllContentTags(view, acc); });
});
} }
} }
return acc; return acc;
@ -79,12 +72,11 @@ export class LightDom {
// - nodes from enclosed ViewContainers, // - nodes from enclosed ViewContainers,
// - nodes from enclosed content tags, // - nodes from enclosed content tags,
// - plain DOM nodes // - plain DOM nodes
expandedDomNodes():List { expandedDomNodes(): List</*node*/ any> {
var res = []; var res = [];
var roots = this._roots(); var roots = this._findRoots();
for (var i = 0; i < roots.length; ++i) { for (var i = 0; i < roots.length; ++i) {
var root = roots[i]; var root = roots[i];
if (isPresent(root.boundElementIndex)) { if (isPresent(root.boundElementIndex)) {
var vc = this.lightDomView.viewContainers[root.boundElementIndex]; var vc = this.lightDomView.viewContainers[root.boundElementIndex];
@ -105,12 +97,12 @@ export class LightDom {
// Returns a list of Roots for all the nodes of the light DOM. // Returns a list of Roots for all the nodes of the light DOM.
// The Root object contains the DOM node and its corresponding boundElementIndex // The Root object contains the DOM node and its corresponding boundElementIndex
_roots() { private _findRoots() {
if (isPresent(this.roots)) return this.roots; if (isPresent(this._roots)) return this._roots;
var boundElements = this.lightDomView.boundElements; var boundElements = this.lightDomView.boundElements;
this.roots = ListWrapper.map(this.nodes, (n) => { this._roots = ListWrapper.map(this.nodes, (n) => {
var boundElementIndex = null; var boundElementIndex = null;
for (var i = 0; i < boundElements.length; i++) { for (var i = 0; i < boundElements.length; i++) {
var boundEl = boundElements[i]; var boundEl = boundElements[i];
@ -122,12 +114,12 @@ export class LightDom {
return new _Root(n, boundElementIndex); return new _Root(n, boundElementIndex);
}); });
return this.roots; return this._roots;
} }
} }
// Projects the light DOM into the shadow DOM // Projects the light DOM into the shadow DOM
function redistributeNodes(contents:List<Content>, nodes:List) { function redistributeNodes(contents: List<Content>, nodes: List</*node*/ any>) {
for (var i = 0; i < contents.length; ++i) { for (var i = 0; i < contents.length; ++i) {
var content = contents[i]; var content = contents[i];
var select = content.select; var select = content.select;

View File

@ -19,11 +19,9 @@ export class NativeShadowDomStrategy extends ShadowDomStrategy {
this.styleUrlResolver = styleUrlResolver; this.styleUrlResolver = styleUrlResolver;
} }
prepareShadowRoot(el) { prepareShadowRoot(el) { return DOM.createShadowRoot(el); }
return DOM.createShadowRoot(el);
}
processStyleElement(hostComponentId:string, templateUrl:string, styleEl):Promise { processStyleElement(hostComponentId: string, templateUrl: string, styleEl): Promise<any> {
var cssText = DOM.getText(styleEl); var cssText = DOM.getText(styleEl);
cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl); cssText = this.styleUrlResolver.resolveUrls(cssText, templateUrl);
DOM.setText(styleEl, cssText); DOM.setText(styleEl, cssText);

View File

@ -16,7 +16,8 @@ import {
* *
* Please make sure to keep to edits in sync with the source file. * Please make sure to keep to edits in sync with the source file.
* *
* Source: https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js * Source:
* https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
* *
* The original file level comment is reproduced below * The original file level comment is reproduced below
*/ */
@ -139,9 +140,7 @@ import {
export class ShadowCss { export class ShadowCss {
strictStyling: boolean; strictStyling: boolean;
constructor() { constructor() { this.strictStyling = true; }
this.strictStyling = true;
}
/* /*
* Shim a style element with the given selector. Returns cssText that can * Shim a style element with the given selector. Returns cssText that can
@ -186,9 +185,8 @@ export class ShadowCss {
**/ **/
_insertPolyfillDirectivesInCssText(cssText: string): string { _insertPolyfillDirectivesInCssText(cssText: string): string {
// Difference with webcomponents.js: does not handle comments // Difference with webcomponents.js: does not handle comments
return StringWrapper.replaceAllMapped(cssText, _cssContentNextSelectorRe, function(m) { return StringWrapper.replaceAllMapped(cssText, _cssContentNextSelectorRe,
return m[1] + '{'; function(m) { return m[1] + '{'; });
});
} }
/* /*
@ -225,16 +223,14 @@ export class ShadowCss {
* scopeName .foo { ... } * scopeName .foo { ... }
*/ */
_scopeCssText(cssText: string, scopeSelector: string, hostSelector: string): string { _scopeCssText(cssText: string, scopeSelector: string, hostSelector: string): string {
var unscoped = this._extractUnscopedRulesFromCssText(cssText); var unscoped = this._extractUnscopedRulesFromCssText(cssText);
cssText = this._insertPolyfillHostInCssText(cssText); cssText = this._insertPolyfillHostInCssText(cssText);
cssText = this._convertColonHost(cssText); cssText = this._convertColonHost(cssText);
cssText = this._convertColonHostContext(cssText); cssText = this._convertColonHostContext(cssText);
cssText = this._convertShadowDOMSelectors(cssText); cssText = this._convertShadowDOMSelectors(cssText);
if (isPresent(scopeSelector)) { if (isPresent(scopeSelector)) {
_withCssRules(cssText, (rules) => { _withCssRules(cssText,
cssText = this._scopeRules(rules, scopeSelector, hostSelector); (rules) => { cssText = this._scopeRules(rules, scopeSelector, hostSelector); });
});
} }
cssText = cssText + '\n' + unscoped; cssText = cssText + '\n' + unscoped;
return cssText.trim(); return cssText.trim();
@ -276,8 +272,7 @@ export class ShadowCss {
* scopeName.foo > .bar * scopeName.foo > .bar
*/ */
_convertColonHost(cssText: string): string { _convertColonHost(cssText: string): string {
return this._convertColonRule(cssText, _cssColonHostRe, return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer);
this._colonHostPartReplacer);
} }
/* /*
@ -349,7 +344,8 @@ export class ShadowCss {
var rule = cssRules[i]; var rule = cssRules[i];
if (DOM.isStyleRule(rule) || DOM.isPageRule(rule)) { if (DOM.isStyleRule(rule) || DOM.isPageRule(rule)) {
cssText += this._scopeSelector(rule.selectorText, scopeSelector, hostSelector, cssText += this._scopeSelector(rule.selectorText, scopeSelector, hostSelector,
this.strictStyling) + ' {\n'; this.strictStyling) +
' {\n';
cssText += this._propertiesFromRule(rule) + '\n}\n\n'; cssText += this._propertiesFromRule(rule) + '\n}\n\n';
} else if (DOM.isMediaRule(rule)) { } else if (DOM.isMediaRule(rule)) {
cssText += '@media ' + rule.media.mediaText + ' {\n'; cssText += '@media ' + rule.media.mediaText + ' {\n';
@ -436,17 +432,14 @@ export class ShadowCss {
_applyStrictSelectorScope(selector: string, scopeSelector: string): string { _applyStrictSelectorScope(selector: string, scopeSelector: string): string {
var isRe = RegExpWrapper.create('\\[is=([^\\]]*)\\]'); var isRe = RegExpWrapper.create('\\[is=([^\\]]*)\\]');
scopeSelector = StringWrapper.replaceAllMapped(scopeSelector, isRe, (m) => m[1]); scopeSelector = StringWrapper.replaceAllMapped(scopeSelector, isRe, (m) => m[1]);
var splits = [' ', '>', '+', '~'], var splits = [' ', '>', '+', '~'], scoped = selector, attrName = '[' + scopeSelector + ']';
scoped = selector,
attrName = '[' + scopeSelector + ']';
for (var i = 0; i < splits.length; i++) { for (var i = 0; i < splits.length; i++) {
var sep = splits[i]; var sep = splits[i];
var parts = scoped.split(sep); var parts = scoped.split(sep);
scoped = ListWrapper.map(parts, function(p) { scoped = ListWrapper.map(parts, function(p) {
// remove :host since it should be unnecessary // remove :host since it should be unnecessary
var t = StringWrapper.replaceAll(p.trim(), _polyfillHostRe, ''); var t = StringWrapper.replaceAll(p.trim(), _polyfillHostRe, '');
if (t.length > 0 && if (t.length > 0 && !ListWrapper.contains(splits, t) &&
!ListWrapper.contains(splits, t) &&
!StringWrapper.contains(t, attrName)) { !StringWrapper.contains(t, attrName)) {
var re = RegExpWrapper.create('([^:]*)(:*)(.*)'); var re = RegExpWrapper.create('([^:]*)(:*)(.*)');
var m = RegExpWrapper.firstMatch(re, t); var m = RegExpWrapper.firstMatch(re, t);
@ -475,8 +468,8 @@ export class ShadowCss {
if (rule.style.content.length > 0 && if (rule.style.content.length > 0 &&
!isPresent(RegExpWrapper.firstMatch(attrRe, rule.style.content))) { !isPresent(RegExpWrapper.firstMatch(attrRe, rule.style.content))) {
var contentRe = RegExpWrapper.create('content:[^;]*;'); var contentRe = RegExpWrapper.create('content:[^;]*;');
cssText = StringWrapper.replaceAll(cssText, contentRe, 'content: \'' + cssText =
rule.style.content + '\';'); StringWrapper.replaceAll(cssText, contentRe, 'content: \'' + rule.style.content + '\';');
} }
// TODO(sorvell): we can workaround this issue here, but we need a list // TODO(sorvell): we can workaround this issue here, but we need a list
// of troublesome properties to fix https://github.com/Polymer/platform/issues/53 // of troublesome properties to fix https://github.com/Polymer/platform/issues/53
@ -498,8 +491,8 @@ export class ShadowCss {
var _cssContentNextSelectorRe = RegExpWrapper.create( var _cssContentNextSelectorRe = RegExpWrapper.create(
'polyfill-next-selector[^}]*content:[\\s]*?[\'"](.*?)[\'"][;\\s]*}([^{]*?){', 'im'); 'polyfill-next-selector[^}]*content:[\\s]*?[\'"](.*?)[\'"][;\\s]*}([^{]*?){', 'im');
var _cssContentRuleRe = RegExpWrapper.create( var _cssContentRuleRe =
'(polyfill-rule)[^}]*(content:[\\s]*[\'"](.*?)[\'"])[;\\s]*[^}]*}', 'im'); RegExpWrapper.create('(polyfill-rule)[^}]*(content:[\\s]*[\'"](.*?)[\'"])[;\\s]*[^}]*}', 'im');
var _cssContentUnscopedRuleRe = RegExpWrapper.create( var _cssContentUnscopedRuleRe = RegExpWrapper.create(
'(polyfill-unscoped-rule)[^}]*(content:[\\s]*[\'"](.*?)[\'"])[;\\s]*[^}]*}', 'im'); '(polyfill-unscoped-rule)[^}]*(content:[\\s]*[\'"](.*?)[\'"])[;\\s]*[^}]*}', 'im');
var _polyfillHost = '-shadowcsshost'; var _polyfillHost = '-shadowcsshost';

View File

@ -10,13 +10,13 @@ import {CompileControl} from '../compiler/compile_control';
import {ViewDefinition} from '../../api'; import {ViewDefinition} from '../../api';
import {ShadowDomStrategy} from './shadow_dom_strategy'; import {ShadowDomStrategy} from './shadow_dom_strategy';
export class ShadowDomCompileStep extends CompileStep { export class ShadowDomCompileStep implements CompileStep {
_shadowDomStrategy: ShadowDomStrategy; _shadowDomStrategy: ShadowDomStrategy;
_template: ViewDefinition; _template: ViewDefinition;
_subTaskPromises: List<Promise>; _subTaskPromises: List<Promise<any>>;
constructor(shadowDomStrategy: ShadowDomStrategy, template: ViewDefinition, subTaskPromises:List<Promise>) { constructor(shadowDomStrategy: ShadowDomStrategy, template: ViewDefinition,
super(); subTaskPromises: List<Promise<any>>) {
this._shadowDomStrategy = shadowDomStrategy; this._shadowDomStrategy = shadowDomStrategy;
this._template = template; this._template = template;
this._subTaskPromises = subTaskPromises; this._subTaskPromises = subTaskPromises;
@ -30,16 +30,14 @@ export class ShadowDomCompileStep extends CompileStep {
this._processContentElement(current); this._processContentElement(current);
} else { } else {
var componentId = current.isBound() ? current.inheritedElementBinder.componentId : null; var componentId = current.isBound() ? current.inheritedElementBinder.componentId : null;
this._shadowDomStrategy.processElement( this._shadowDomStrategy.processElement(this._template.componentId, componentId,
this._template.componentId, componentId, current.element current.element);
);
} }
} }
_processStyleElement(current: CompileElement, control: CompileControl) { _processStyleElement(current: CompileElement, control: CompileControl) {
var stylePromise = this._shadowDomStrategy.processStyleElement( var stylePromise = this._shadowDomStrategy.processStyleElement(
this._template.componentId, this._template.absUrl, current.element this._template.componentId, this._template.absUrl, current.element);
);
if (isPresent(stylePromise) && PromiseWrapper.isPromise(stylePromise)) { if (isPresent(stylePromise) && PromiseWrapper.isPromise(stylePromise)) {
ListWrapper.push(this._subTaskPromises, stylePromise); ListWrapper.push(this._subTaskPromises, stylePromise);
} }

View File

@ -5,25 +5,19 @@ import * as viewModule from '../view/view';
import {LightDom} from './light_dom'; import {LightDom} from './light_dom';
export class ShadowDomStrategy { export class ShadowDomStrategy {
hasNativeContentElement():boolean { hasNativeContentElement(): boolean { return true; }
return true;
}
/** /**
* Prepares and returns the shadow root for the given element. * Prepares and returns the shadow root for the given element.
*/ */
prepareShadowRoot(el):any { prepareShadowRoot(el): any { return null; }
return null;
}
constructLightDom(lightDomView:viewModule.DomView, el): LightDom { constructLightDom(lightDomView: viewModule.DomView, el): LightDom { return null; }
return null;
}
/** /**
* An optional step that can modify the template style elements. * An optional step that can modify the template style elements.
*/ */
processStyleElement(hostComponentId:string, templateUrl:string, styleElement):Promise { processStyleElement(hostComponentId: string, templateUrl: string, styleElement): Promise<any> {
return null; return null;
}; };

View File

@ -1,4 +1,4 @@
import {Injectable} from 'angular2/src/di/annotations_impl'; import {Injectable} from 'angular2/di';
import {XHR} from 'angular2/src/services/xhr'; import {XHR} from 'angular2/src/services/xhr';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
@ -18,6 +18,10 @@ import {
PromiseWrapper, PromiseWrapper,
} from 'angular2/src/facade/async'; } from 'angular2/src/facade/async';
export class SyncAsyncResult<T> {
constructor(public syncResult: T, public asyncResult: Promise<T>) {}
}
/** /**
* Inline @import rules in the given CSS. * Inline @import rules in the given CSS.
* *
@ -44,19 +48,18 @@ export class StyleInliner {
* @param {string} baseUrl * @param {string} baseUrl
* @returns {*} a Promise<string> when @import rules are present, a string otherwise * @returns {*} a Promise<string> when @import rules are present, a string otherwise
*/ */
// TODO(vicb): Union types: returns either a Promise<string> or a string inlineImports(cssText: string, baseUrl: string): SyncAsyncResult<string> {
// TODO(vicb): commented out @import rules should not be inlined
inlineImports(cssText: string, baseUrl: string) {
return this._inlineImports(cssText, baseUrl, []); return this._inlineImports(cssText, baseUrl, []);
} }
_inlineImports(cssText: string, baseUrl: string, inlinedUrls: List<string>) { _inlineImports(cssText: string, baseUrl: string,
inlinedUrls: List<string>): SyncAsyncResult<string> {
var partIndex = 0; var partIndex = 0;
var parts = StringWrapper.split(cssText, _importRe); var parts = StringWrapper.split(cssText, _importRe);
if (parts.length === 1) { if (parts.length === 1) {
// no @import rule found, return the original css // no @import rule found, return the original css
return cssText; return new SyncAsyncResult(cssText, null);
} }
var promises = []; var promises = [];
@ -81,36 +84,32 @@ export class StyleInliner {
promise = PromiseWrapper.resolve(prefix); promise = PromiseWrapper.resolve(prefix);
} else { } else {
ListWrapper.push(inlinedUrls, url); ListWrapper.push(inlinedUrls, url);
promise = PromiseWrapper.then( promise = PromiseWrapper.then(this._xhr.get(url), (rawCss) => {
this._xhr.get(url),
(css) => {
// resolve nested @import rules // resolve nested @import rules
css = this._inlineImports(css, url, inlinedUrls); var inlinedCss = this._inlineImports(rawCss, url, inlinedUrls);
if (PromiseWrapper.isPromise(css)) { if (isPresent(inlinedCss.asyncResult)) {
// wait until nested @import are inlined // wait until nested @import are inlined
return css.then((css) => { return inlinedCss.asyncResult.then(
return prefix + this._transformImportedCss(css, mediaQuery, url) + '\n' (css) => {return prefix + this._transformImportedCss(css, mediaQuery, url) + '\n'});
}) ;
} else { } else {
// there are no nested @import, return the css // there are no nested @import, return the css
return prefix + this._transformImportedCss(css, mediaQuery, url) + '\n'; return prefix + this._transformImportedCss(inlinedCss.syncResult, mediaQuery, url) +
'\n';
} }
}, }, (error) => `/* failed to import ${url} */\n`);
(error) => `/* failed to import ${url} */\n`
);
} }
ListWrapper.push(promises, promise); ListWrapper.push(promises, promise);
partIndex += 2; partIndex += 2;
} }
return PromiseWrapper.all(promises).then(function (cssParts) { return new SyncAsyncResult(null, PromiseWrapper.all(promises).then(function(cssParts) {
var cssText = cssParts.join(''); var cssText = cssParts.join('');
if (partIndex < parts.length) { if (partIndex < parts.length) {
// append then content located after the last @import rule // append then content located after the last @import rule
cssText += parts[partIndex]; cssText += parts[partIndex];
} }
return cssText; return cssText;
}); }));
} }
_transformImportedCss(css: string, mediaQuery: string, url: string): string { _transformImportedCss(css: string, mediaQuery: string, url: string): string {

View File

@ -1,7 +1,7 @@
// Some of the code comes from WebComponents.JS // Some of the code comes from WebComponents.JS
// https://github.com/webcomponents/webcomponentsjs/blob/master/src/HTMLImports/path.js // https://github.com/webcomponents/webcomponentsjs/blob/master/src/HTMLImports/path.js
import {Injectable} from 'angular2/src/di/annotations_impl'; import {Injectable} from 'angular2/di';
import {RegExp, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang'; import {RegExp, RegExpWrapper, StringWrapper} from 'angular2/src/facade/lang';
import {UrlResolver} from 'angular2/src/services/url_resolver'; import {UrlResolver} from 'angular2/src/services/url_resolver';
@ -12,9 +12,7 @@ import {UrlResolver} from 'angular2/src/services/url_resolver';
export class StyleUrlResolver { export class StyleUrlResolver {
_resolver: UrlResolver; _resolver: UrlResolver;
constructor(resolver: UrlResolver) { constructor(resolver: UrlResolver) { this._resolver = resolver; }
this._resolver = resolver;
}
resolveUrls(cssText: string, baseUrl: string) { resolveUrls(cssText: string, baseUrl: string) {
cssText = this._replaceUrls(cssText, _cssUrlRe, baseUrl); cssText = this._replaceUrls(cssText, _cssUrlRe, baseUrl);

View File

@ -9,13 +9,11 @@ var CAMEL_CASE_REGEXP = RegExpWrapper.create('([A-Z])');
var DASH_CASE_REGEXP = RegExpWrapper.create('-([a-z])'); var DASH_CASE_REGEXP = RegExpWrapper.create('-([a-z])');
export function camelCaseToDashCase(input: string) { export function camelCaseToDashCase(input: string) {
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP, (m) => { return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
return '-' + m[1].toLowerCase(); (m) => { return '-' + m[1].toLowerCase(); });
});
} }
export function dashCaseToCamelCase(input: string) { export function dashCaseToCamelCase(input: string) {
return StringWrapper.replaceAllMapped(input, DASH_CASE_REGEXP, (m) => { return StringWrapper.replaceAllMapped(input, DASH_CASE_REGEXP,
return m[1].toUpperCase(); (m) => { return m[1].toUpperCase(); });
});
} }

View File

@ -28,6 +28,18 @@ export class ElementBinder {
parentIndex, parentIndex,
distanceToParent, distanceToParent,
propertySetters propertySetters
}:{
contentTagSelector?: string,
textNodeIndices?: List<number>,
nestedProtoView?: protoViewModule.DomProtoView,
eventLocals?: AST,
localEvents?: List<Event>,
globalEvents?: List<Event>,
componentId?: string,
parentIndex?:number,
distanceToParent?:number,
propertySetters?: Map<string, SetterFn>,
hostActions?: Map<string, AST>
} = {}) { } = {}) {
this.textNodeIndices = textNodeIndices; this.textNodeIndices = textNodeIndices;
this.contentTagSelector = contentTagSelector; this.contentTagSelector = contentTagSelector;

View File

@ -1,4 +1,12 @@
import {StringWrapper, RegExpWrapper, BaseException, isPresent, isBlank, isString, stringify} from 'angular2/src/facade/lang'; import {
StringWrapper,
RegExpWrapper,
BaseException,
isPresent,
isBlank,
isString,
stringify
} from 'angular2/src/facade/lang';
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {camelCaseToDashCase, dashCaseToCamelCase} from '../util'; import {camelCaseToDashCase, dashCaseToCamelCase} from '../util';
@ -7,6 +15,12 @@ import {reflector} from 'angular2/src/reflection/reflection';
const STYLE_SEPARATOR = '.'; const STYLE_SEPARATOR = '.';
var propertySettersCache = StringMapWrapper.create(); var propertySettersCache = StringMapWrapper.create();
var innerHTMLSetterCache; var innerHTMLSetterCache;
const ATTRIBUTE_PREFIX = 'attr.';
var attributeSettersCache = StringMapWrapper.create();
const CLASS_PREFIX = 'class.';
var classSettersCache = StringMapWrapper.create();
const STYLE_PREFIX = 'style.';
var styleSettersCache = StringMapWrapper.create();
export function setterFactory(property: string): Function { export function setterFactory(property: string): Function {
var setterFn, styleParts, styleSuffix; var setterFn, styleParts, styleSuffix;
@ -39,9 +53,6 @@ export function setterFactory(property: string): Function {
return setterFn; return setterFn;
} }
const ATTRIBUTE_PREFIX = 'attr.';
var attributeSettersCache = StringMapWrapper.create();
function _isValidAttributeValue(attrName: string, value: any): boolean { function _isValidAttributeValue(attrName: string, value: any): boolean {
if (attrName == "role") { if (attrName == "role") {
return isString(value); return isString(value);
@ -62,7 +73,8 @@ function attributeSetterFactory(attrName:string): Function {
} else { } else {
if (isPresent(value)) { if (isPresent(value)) {
throw new BaseException("Invalid " + dashCasedAttributeName + throw new BaseException("Invalid " + dashCasedAttributeName +
" attribute, only string values are allowed, got '" + stringify(value) + "'"); " attribute, only string values are allowed, got '" +
stringify(value) + "'");
} }
DOM.removeAttribute(element, dashCasedAttributeName); DOM.removeAttribute(element, dashCasedAttributeName);
} }
@ -73,9 +85,6 @@ function attributeSetterFactory(attrName:string): Function {
return setterFn; return setterFn;
} }
const CLASS_PREFIX = 'class.';
var classSettersCache = StringMapWrapper.create();
function classSetterFactory(className: string): Function { function classSetterFactory(className: string): Function {
var setterFn = StringMapWrapper.get(classSettersCache, className); var setterFn = StringMapWrapper.get(classSettersCache, className);
var dashCasedClassName; var dashCasedClassName;
@ -94,9 +103,6 @@ function classSetterFactory(className:string): Function {
return setterFn; return setterFn;
} }
const STYLE_PREFIX = 'style.';
var styleSettersCache = StringMapWrapper.create();
function styleSetterFactory(styleName: string, styleSuffix: string): Function { function styleSetterFactory(styleName: string, styleSuffix: string): Function {
var cacheKey = styleName + styleSuffix; var cacheKey = styleName + styleSuffix;
var setterFn = StringMapWrapper.get(styleSettersCache, cacheKey); var setterFn = StringMapWrapper.get(styleSettersCache, cacheKey);

View File

@ -9,8 +9,7 @@ import {NG_BINDING_CLASS} from '../util';
import {RenderProtoViewRef} from '../../api'; import {RenderProtoViewRef} from '../../api';
export function resolveInternalDomProtoView(protoViewRef: RenderProtoViewRef) { export function resolveInternalDomProtoView(protoViewRef: RenderProtoViewRef) {
var domProtoViewRef:DomProtoViewRef = protoViewRef; return (<DomProtoViewRef>protoViewRef)._protoView;
return domProtoViewRef._protoView;
} }
export class DomProtoViewRef extends RenderProtoViewRef { export class DomProtoViewRef extends RenderProtoViewRef {
@ -25,15 +24,13 @@ export class DomProtoView {
element; element;
elementBinders: List<ElementBinder>; elementBinders: List<ElementBinder>;
isTemplateElement: boolean; isTemplateElement: boolean;
rootBindingOffset:int; rootBindingOffset: number;
constructor({ constructor({elementBinders, element}) {
elementBinders,
element
}) {
this.element = element; this.element = element;
this.elementBinders = elementBinders; this.elementBinders = elementBinders;
this.isTemplateElement = DOM.isTemplateElement(this.element); this.isTemplateElement = DOM.isTemplateElement(this.element);
this.rootBindingOffset = (isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0; this.rootBindingOffset =
(isPresent(this.element) && DOM.hasClass(this.element, NG_BINDING_CLASS)) ? 1 : 0;
} }
} }

View File

@ -3,7 +3,12 @@ import {ListWrapper, MapWrapper, Set, SetWrapper, List} from 'angular2/src/facad
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import { import {
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver ASTWithSource,
AST,
AstTransformer,
AccessMember,
LiteralArray,
ImplicitReceiver
} from 'angular2/change_detection'; } from 'angular2/change_detection';
import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './proto_view'; import {DomProtoView, DomProtoViewRef, resolveInternalDomProtoView} from './proto_view';
@ -37,7 +42,8 @@ export class ProtoViewBuilder {
bindVariable(name, value) { bindVariable(name, value) {
// Store the variable map from value to variable, reflecting how it will be used later by // Store the variable map from value to variable, reflecting how it will be used later by
// DomView. When a local is set to the view, a lookup for the variable name will take place keyed // DomView. When a local is set to the view, a lookup for the variable name will take place
// keyed
// by the "value", or exported identifier. For example, ng-for sets a view local of "index". // by the "value", or exported identifier. For example, ng-for sets a view local of "index".
// When this occurs, a lookup keyed by "index" must occur to find if there is a var referencing // When this occurs, a lookup keyed by "index" must occur to find if there is a var referencing
// it. // it.
@ -75,14 +81,16 @@ export class ProtoViewBuilder {
MapWrapper.set(propertySetters, propertyName, setterFactory(propertyName)); MapWrapper.set(propertySetters, propertyName, setterFactory(propertyName));
}); });
var nestedProtoView = var nestedProtoView = isPresent(ebb.nestedProtoView) ? ebb.nestedProtoView.build() : null;
isPresent(ebb.nestedProtoView) ? ebb.nestedProtoView.build() : null;
var parentIndex = isPresent(ebb.parent) ? ebb.parent.index : -1; var parentIndex = isPresent(ebb.parent) ? ebb.parent.index : -1;
ListWrapper.push(apiElementBinders, new api.ElementBinder({ ListWrapper.push(apiElementBinders, new api.ElementBinder({
index: ebb.index, parentIndex:parentIndex, distanceToParent:ebb.distanceToParent, index: ebb.index,
parentIndex: parentIndex,
distanceToParent: ebb.distanceToParent,
directives: apiDirectiveBinders, directives: apiDirectiveBinders,
nestedProtoView: nestedProtoView, nestedProtoView: nestedProtoView,
propertyBindings: ebb.propertyBindings, variableBindings: ebb.variableBindings, propertyBindings: ebb.propertyBindings,
variableBindings: ebb.variableBindings,
eventBindings: ebb.eventBindings, eventBindings: ebb.eventBindings,
textBindings: ebb.textBindings, textBindings: ebb.textBindings,
readAttributes: ebb.readAttributes readAttributes: ebb.readAttributes
@ -92,7 +100,9 @@ export class ProtoViewBuilder {
contentTagSelector: ebb.contentTagSelector, contentTagSelector: ebb.contentTagSelector,
parentIndex: parentIndex, parentIndex: parentIndex,
distanceToParent: ebb.distanceToParent, distanceToParent: ebb.distanceToParent,
nestedProtoView: isPresent(nestedProtoView) ? resolveInternalDomProtoView(nestedProtoView.render) : null, nestedProtoView: isPresent(nestedProtoView) ?
resolveInternalDomProtoView(nestedProtoView.render) :
null,
componentId: ebb.componentId, componentId: ebb.componentId,
eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()), eventLocals: new LiteralArray(ebb.eventBuilder.buildEventLocals()),
localEvents: ebb.eventBuilder.buildLocalEvents(), localEvents: ebb.eventBuilder.buildLocalEvents(),
@ -102,10 +112,8 @@ export class ProtoViewBuilder {
})); }));
}); });
return new api.ProtoViewDto({ return new api.ProtoViewDto({
render: new DomProtoViewRef(new DomProtoView({ render: new DomProtoViewRef(
element: this.rootElement, new DomProtoView({element: this.rootElement, elementBinders: renderElementBinders})),
elementBinders: renderElementBinders
})),
type: this.type, type: this.type,
elementBinders: apiElementBinders, elementBinders: apiElementBinders,
variableBindings: this.variableBindings variableBindings: this.variableBindings
@ -192,9 +200,11 @@ export class ElementBinderBuilder {
this.nestedProtoView.bindVariable(name, value); this.nestedProtoView.bindVariable(name, value);
} else { } else {
// Store the variable map from value to variable, reflecting how it will be used later by // Store the variable map from value to variable, reflecting how it will be used later by
// DomView. When a local is set to the view, a lookup for the variable name will take place keyed // DomView. When a local is set to the view, a lookup for the variable name will take place
// keyed
// by the "value", or exported identifier. For example, ng-for sets a view local of "index". // by the "value", or exported identifier. For example, ng-for sets a view local of "index".
// When this occurs, a lookup keyed by "index" must occur to find if there is a var referencing // When this occurs, a lookup keyed by "index" must occur to find if there is a var
// referencing
// it. // it.
MapWrapper.set(this.variableBindings, value, name); MapWrapper.set(this.variableBindings, value, name);
} }
@ -209,13 +219,9 @@ export class ElementBinderBuilder {
ListWrapper.push(this.textBindings, expression); ListWrapper.push(this.textBindings, expression);
} }
setContentTagSelector(value:string) { setContentTagSelector(value: string) { this.contentTagSelector = value; }
this.contentTagSelector = value;
}
setComponentId(componentId:string) { setComponentId(componentId: string) { this.componentId = componentId; }
this.componentId = componentId;
}
} }
export class DirectiveBuilder { export class DirectiveBuilder {
@ -235,9 +241,7 @@ export class DirectiveBuilder {
this.eventBuilder = new EventBuilder(); this.eventBuilder = new EventBuilder();
} }
bindProperty(name, expression) { bindProperty(name, expression) { MapWrapper.set(this.propertyBindings, name, expression); }
MapWrapper.set(this.propertyBindings, name, expression);
}
bindHostProperty(name, expression) { bindHostProperty(name, expression) {
MapWrapper.set(this.hostPropertyBindings, name, expression); MapWrapper.set(this.hostPropertyBindings, name, expression);
@ -272,7 +276,8 @@ export class EventBuilder extends AstTransformer {
// var adjustedAst = astWithSource.ast.visit(this); // var adjustedAst = astWithSource.ast.visit(this);
var adjustedAst = source.ast; var adjustedAst = source.ast;
var fullName = isPresent(target) ? target + EVENT_TARGET_SEPARATOR + name : name; var fullName = isPresent(target) ? target + EVENT_TARGET_SEPARATOR + name : name;
var result = new api.EventBinding(fullName, new ASTWithSource(adjustedAst, source.source, source.location)); var result = new api.EventBinding(
fullName, new ASTWithSource(adjustedAst, source.source, source.location));
var event = new Event(name, target, fullName); var event = new Event(name, target, fullName);
if (isBlank(target)) { if (isBlank(target)) {
ListWrapper.push(this.localEvents, event); ListWrapper.push(this.localEvents, event);
@ -284,12 +289,13 @@ export class EventBuilder extends AstTransformer {
visitAccessMember(ast: AccessMember) { visitAccessMember(ast: AccessMember) {
var isEventAccess = false; var isEventAccess = false;
var current = ast; var current: AST = ast;
while (!isEventAccess && (current instanceof AccessMember)) { while (!isEventAccess && (current instanceof AccessMember)) {
if (current.name == '$event') { var am = <AccessMember>current;
if (am.name == '$event') {
isEventAccess = true; isEventAccess = true;
} }
current = current.receiver; current = am.receiver;
} }
if (isEventAccess) { if (isEventAccess) {
@ -301,17 +307,11 @@ export class EventBuilder extends AstTransformer {
} }
} }
buildEventLocals() { buildEventLocals() { return this.locals; }
return this.locals;
}
buildLocalEvents() { buildLocalEvents() { return this.localEvents; }
return this.localEvents;
}
buildGlobalEvents() { buildGlobalEvents() { return this.globalEvents; }
return this.globalEvents;
}
merge(eventBuilder: EventBuilder) { merge(eventBuilder: EventBuilder) {
this._merge(this.localEvents, eventBuilder.localEvents); this._merge(this.localEvents, eventBuilder.localEvents);

View File

@ -8,14 +8,10 @@ import {DomProtoView} from './proto_view';
import {LightDom} from '../shadow_dom/light_dom'; import {LightDom} from '../shadow_dom/light_dom';
import {Content} from '../shadow_dom/content_tag'; import {Content} from '../shadow_dom/content_tag';
import {RenderViewRef} from '../../api'; import {RenderViewRef, EventDispatcher} from '../../api';
// TODO(tbosch): enable this again!
// import {EventDispatcher} from '../../api';
export function resolveInternalDomView(viewRef: RenderViewRef) { export function resolveInternalDomView(viewRef: RenderViewRef) {
var domViewRef:DomViewRef = viewRef; return (<DomViewRef>viewRef)._view;
return domViewRef._view;
} }
export class DomViewRef extends RenderViewRef { export class DomViewRef extends RenderViewRef {
@ -33,32 +29,20 @@ const NG_BINDING_CLASS = 'ng-binding';
* Const of making objects: http://jsperf.com/instantiate-size-of-object * Const of making objects: http://jsperf.com/instantiate-size-of-object
*/ */
export class DomView { export class DomView {
boundElements:List;
boundTextNodes:List;
/// When the view is part of render tree, the DocumentFragment is empty, which is why we need
/// to keep track of the nodes.
rootNodes:List;
// TODO(tbosch): move componentChildViews, viewContainers, contentTags, lightDoms into // TODO(tbosch): move componentChildViews, viewContainers, contentTags, lightDoms into
// a single array with records inside // a single array with records inside
viewContainers: List<DomViewContainer>; viewContainers: List<DomViewContainer>;
contentTags: List<Content>;
lightDoms: List<LightDom>; lightDoms: List<LightDom>;
hostLightDom: LightDom; hostLightDom: LightDom;
shadowRoot; shadowRoot;
proto: DomProtoView;
hydrated: boolean; hydrated: boolean;
eventDispatcher: any/*EventDispatcher*/; eventDispatcher: EventDispatcher;
eventHandlerRemovers: List<Function>; eventHandlerRemovers: List<Function>;
constructor( constructor(public proto: DomProtoView, public rootNodes: List</*node*/ any>,
proto:DomProtoView, rootNodes:List, public boundTextNodes: List</*node*/ any>,
boundTextNodes: List, boundElements:List, contentTags:List) { public boundElements: List</*element*/ any>, public contentTags: List<Content>) {
this.proto = proto;
this.rootNodes = rootNodes;
this.boundTextNodes = boundTextNodes;
this.boundElements = boundElements;
this.viewContainers = ListWrapper.createFixedSize(boundElements.length); this.viewContainers = ListWrapper.createFixedSize(boundElements.length);
this.contentTags = contentTags;
this.lightDoms = ListWrapper.createFixedSize(boundElements.length); this.lightDoms = ListWrapper.createFixedSize(boundElements.length);
this.hostLightDom = null; this.hostLightDom = null;
this.hydrated = false; this.hydrated = false;
@ -77,7 +61,8 @@ export class DomView {
} }
setElementProperty(elementIndex: number, propertyName: string, value: any) { setElementProperty(elementIndex: number, propertyName: string, value: any) {
var setter = MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName); var setter =
MapWrapper.get(this.proto.elementBinders[elementIndex].propertySetters, propertyName);
setter(this.boundElements[elementIndex], value); setter(this.boundElements[elementIndex], value);
} }
@ -93,9 +78,7 @@ export class DomView {
return new Locals(null, map); return new Locals(null, map);
} }
setText(textIndex:number, value:string) { setText(textIndex: number, value: string) { DOM.setText(this.boundTextNodes[textIndex], value); }
DOM.setText(this.boundTextNodes[textIndex], value);
}
dispatchEvent(elementIndex, eventName, event): boolean { dispatchEvent(elementIndex, eventName, event): boolean {
var allowDefaultBehavior = true; var allowDefaultBehavior = true;
@ -104,9 +87,11 @@ export class DomView {
MapWrapper.set(evalLocals, '$event', event); MapWrapper.set(evalLocals, '$event', event);
// TODO(tbosch): reenable this when we are parsing element properties // TODO(tbosch): reenable this when we are parsing element properties
// out of action expressions // out of action expressions
// var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals)); // var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new
// Locals(null, evalLocals));
// this.eventDispatcher.dispatchEvent(elementIndex, eventName, localValues); // this.eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
allowDefaultBehavior = this.eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals); allowDefaultBehavior =
this.eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals);
if (!allowDefaultBehavior) { if (!allowDefaultBehavior) {
event.preventDefault(); event.preventDefault();
} }

View File

@ -10,16 +10,13 @@ export class DomViewContainer {
this.views = []; this.views = [];
} }
contentTagContainers() { contentTagContainers() { return this.views; }
return this.views;
}
nodes():List { nodes(): List</*node*/ any> {
var r = []; var r = [];
for (var i = 0; i < this.views.length; ++i) { for (var i = 0; i < this.views.length; ++i) {
r = ListWrapper.concat(r, this.views[i].rootNodes); r = ListWrapper.concat(r, this.views[i].rootNodes);
} }
return r; return r;
} }
} }

View File

@ -1,12 +0,0 @@
import {DOM} from 'angular2/src/dom/dom_adapter';
export class Title {
getTitle():string {
return DOM.getTitle();
}
setTitle(newTitle:string) {
DOM.setTitle(newTitle);
}
}

View File

@ -0,0 +1,7 @@
import {DOM} from 'angular2/src/dom/dom_adapter';
export class Title {
getTitle(): string { return DOM.getTitle(); }
setTitle(newTitle: string) { DOM.setTitle(newTitle); }
}

View File

@ -1,4 +1,4 @@
import {Injectable} from 'angular2/src/di/annotations_impl'; import {Injectable} from 'angular2/di';
import {isPresent, isBlank, RegExpWrapper, BaseException} from 'angular2/src/facade/lang'; import {isPresent, isBlank, RegExpWrapper, BaseException} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
@ -18,15 +18,19 @@ export class UrlResolver {
* ## When the `baseUrl` is null * ## When the `baseUrl` is null
* *
* `url` is resolved in the context of the current document. * `url` is resolved in the context of the current document.
* If the document location is 'http://www.foo.com/base' and the `url` is 'path/to/here', the resolved url will be * If the document location is 'http://www.foo.com/base' and the `url` is 'path/to/here', the
* resolved url will be
* 'http://www.foo.com/base/path/to/here' * 'http://www.foo.com/base/path/to/here'
* *
* ## When the `baseUrl` is not null * ## When the `baseUrl` is not null
* *
* - when the `url` is null, the `baseUrl` is returned, * - when the `url` is null, the `baseUrl` is returned,
* - due to a limitation in the process used to resolve urls (a HTMLLinkElement), `url` must not start with a `/`, * - due to a limitation in the process used to resolve urls (a HTMLLinkElement), `url` must not
* - if `url` is relative ('path/to/here', './path/to/here'), the resolved url is a combination of `baseUrl` and `url`, * start with a `/`,
* - if `url` is absolute (it has a scheme: 'http://', 'https://'), the `url` is returned (ignoring the `baseUrl`) * - if `url` is relative ('path/to/here', './path/to/here'), the resolved url is a combination of
* `baseUrl` and `url`,
* - if `url` is absolute (it has a scheme: 'http://', 'https://'), the `url` is returned
* (ignoring the `baseUrl`)
* *
* @param {string} baseUrl * @param {string} baseUrl
* @param {string} url * @param {string} url
@ -41,10 +45,12 @@ export class UrlResolver {
if (isBlank(url) || url == '') return baseUrl; if (isBlank(url) || url == '') return baseUrl;
if (url[0] == '/') { if (url[0] == '/') {
// The `HTMLLinkElement` does not allow resolving this case (the `url` would be interpreted as relative): // The `HTMLLinkElement` does not allow resolving this case (the `url` would be interpreted as
// relative):
// - `baseUrl` = 'http://www.foo.com/base' // - `baseUrl` = 'http://www.foo.com/base'
// - `url` = '/absolute/path/to/here' // - `url` = '/absolute/path/to/here'
// - the result would be 'http://www.foo.com/base/absolute/path/to/here' while 'http://www.foo.com/absolute/path/to/here' // - the result would be 'http://www.foo.com/base/absolute/path/to/here' while
// 'http://www.foo.com/absolute/path/to/here'
// is expected (without the 'base' segment). // is expected (without the 'base' segment).
throw new BaseException(`Could not resolve the url ${url} from ${baseUrl}`); throw new BaseException(`Could not resolve the url ${url} from ${baseUrl}`);
} }

View File

@ -1,7 +1,5 @@
import {Promise} from 'angular2/src/facade/async'; import {Promise} from 'angular2/src/facade/async';
export class XHR { export class XHR {
get(url: string): Promise<string> { get(url: string): Promise<string> { return null; }
return null;
}
} }

View File

@ -1,4 +1,4 @@
import {Injectable} from 'angular2/src/di/annotations_impl'; import {Injectable} from 'angular2/di';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {XHR} from './xhr'; import {XHR} from './xhr';
@ -19,9 +19,7 @@ export class XHRImpl extends XHR {
} }
}; };
xhr.onerror = function() { xhr.onerror = function() { completer.reject(`Failed to load ${url}`); };
completer.reject(`Failed to load ${url}`);
};
xhr.send(); xhr.send();
return completer.promise; return completer.promise;

View File

@ -22,8 +22,7 @@ export function makeDecorator(annotationCls) {
} }
export function makeParamDecorator(annotationCls) { export function makeParamDecorator(annotationCls) {
return function() { return function(... args) {
var args = arguments;
var Reflect = global.Reflect; var Reflect = global.Reflect;
if (!(Reflect && Reflect.getMetadata)) { if (!(Reflect && Reflect.getMetadata)) {
throw 'reflect-metadata shim is required when using parameter decorators'; throw 'reflect-metadata shim is required when using parameter decorators';

View File

@ -183,10 +183,9 @@ class MockStepFactory extends CompileStepFactory {
} }
} }
class MockStep extends CompileStep { class MockStep /*implements CompileStep*/ {
processClosure:Function; processClosure:Function;
constructor(process) { constructor(process) {
super();
this.processClosure = process; this.processClosure = process;
} }
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {

View File

@ -1,5 +1,5 @@
import {describe, beforeEach, it, xit, expect, iit, ddescribe, el} from 'angular2/test_lib'; import {describe, beforeEach, it, xit, expect, iit, ddescribe, el} from 'angular2/test_lib';
import {isPresent, isBlank, assertionsEnabled} from 'angular2/src/facade/lang'; import {isPresent, isBlank, assertionsEnabled, IMPLEMENTS} from 'angular2/src/facade/lang';
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {DirectiveParser} from 'angular2/src/render/dom/compiler/directive_parser'; import {DirectiveParser} from 'angular2/src/render/dom/compiler/directive_parser';
@ -225,10 +225,10 @@ export function main() {
}); });
} }
class MockStep extends CompileStep { @IMPLEMENTS(CompileStep)
class MockStep {
processClosure:Function; processClosure:Function;
constructor(process) { constructor(process) {
super();
this.processClosure = process; this.processClosure = process;
} }
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {

View File

@ -1,7 +1,7 @@
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'angular2/test_lib'; import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'angular2/test_lib';
import {ListWrapper, List, MapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, List, MapWrapper} from 'angular2/src/facade/collection';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {isPresent, NumberWrapper, StringWrapper} from 'angular2/src/facade/lang'; import {isPresent, NumberWrapper, StringWrapper, IMPLEMENTS} from 'angular2/src/facade/lang';
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline'; import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element'; import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
@ -182,10 +182,10 @@ export function main() {
}); });
} }
class MockStep extends CompileStep { @IMPLEMENTS(CompileStep)
class MockStep {
processClosure:Function; processClosure:Function;
constructor(process) { constructor(process) {
super();
this.processClosure = process; this.processClosure = process;
} }
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {
@ -193,7 +193,8 @@ class MockStep extends CompileStep {
} }
} }
export class IgnoreChildrenStep extends CompileStep { @IMPLEMENTS(CompileStep)
export class IgnoreChildrenStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {
var attributeMap = DOM.attributeMap(current.element); var attributeMap = DOM.attributeMap(current.element);
if (MapWrapper.contains(attributeMap, 'ignore-children')) { if (MapWrapper.contains(attributeMap, 'ignore-children')) {
@ -202,7 +203,8 @@ export class IgnoreChildrenStep extends CompileStep {
} }
} }
class IgnoreCurrentElementStep extends CompileStep { @IMPLEMENTS(CompileStep)
class IgnoreCurrentElementStep {
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {
var attributeMap = DOM.attributeMap(current.element); var attributeMap = DOM.attributeMap(current.element);
if (MapWrapper.contains(attributeMap, 'ignore-current')) { if (MapWrapper.contains(attributeMap, 'ignore-current')) {

View File

@ -1,9 +1,10 @@
import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'angular2/test_lib'; import {describe, beforeEach, it, expect, iit, ddescribe, el} from 'angular2/test_lib';
import {IMPLEMENTS} from 'angular2/src/facade/lang';
import {PropertyBindingParser} from 'angular2/src/render/dom/compiler/property_binding_parser'; import {PropertyBindingParser} from 'angular2/src/render/dom/compiler/property_binding_parser';
import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline'; import {CompilePipeline} from 'angular2/src/render/dom/compiler/compile_pipeline';
import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element'; import {CompileElement} from 'angular2/src/render/dom/compiler/compile_element';
import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step' import {CompileStep} from 'angular2/src/render/dom/compiler/compile_step';
import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control'; import {CompileControl} from 'angular2/src/render/dom/compiler/compile_control';
import {Lexer, Parser} from 'angular2/change_detection'; import {Lexer, Parser} from 'angular2/change_detection';
@ -164,10 +165,10 @@ export function main() {
}); });
} }
class MockStep extends CompileStep { @IMPLEMENTS(CompileStep)
class MockStep {
processClosure:Function; processClosure:Function;
constructor(process) { constructor(process) {
super();
this.processClosure = process; this.processClosure = process;
} }
process(parent:CompileElement, current:CompileElement, control:CompileControl) { process(parent:CompileElement, current:CompileElement, control:CompileControl) {

View File

@ -10,13 +10,12 @@ import {RenderViewRef, ProtoViewDto, ViewDefinition, EventDispatcher, DirectiveM
import {resolveInternalDomView} from 'angular2/src/render/dom/view/view'; import {resolveInternalDomView} from 'angular2/src/render/dom/view/view';
import {el, dispatchEvent} from 'angular2/test_lib'; import {el, dispatchEvent} from 'angular2/test_lib';
export class TestView extends EventDispatcher { export class TestView {
rawView:DomView; rawView:DomView;
viewRef:RenderViewRef; viewRef:RenderViewRef;
events:List; events:List;
constructor(viewRef:RenderViewRef) { constructor(viewRef:RenderViewRef) {
super();
this.viewRef = viewRef; this.viewRef = viewRef;
this.rawView = resolveInternalDomView(viewRef); this.rawView = resolveInternalDomView(viewRef);
this.events = []; this.events = [];
@ -24,11 +23,11 @@ export class TestView extends EventDispatcher {
} }
class LoggingEventDispatcher extends EventDispatcher { @IMPLEMENTS(EventDispatcher)
class LoggingEventDispatcher {
log:List; log:List;
constructor(log:List) { constructor(log:List) {
super();
this.log = log; this.log = log;
} }

View File

@ -32,8 +32,7 @@ export function main() {
it('should return a string when there is no import statement', inject([StyleInliner], (inliner) => { it('should return a string when there is no import statement', inject([StyleInliner], (inliner) => {
var css = '.main {}'; var css = '.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base'); var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).not.toBePromise(); expect(loadedCss.syncResult).toEqual(css);
expect(loadedCss).toEqual(css);
})); }));
it('should inline @import rules', it('should inline @import rules',
@ -41,9 +40,9 @@ export function main() {
xhr.reply('http://base/one.css', '.one {}'); xhr.reply('http://base/one.css', '.one {}');
var css = '@import url("one.css");.main {}'; var css = '@import url("one.css");.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base'); var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('.one {}\n.main {}'); expect(css).toEqual('.one {}\n.main {}');
async.done(); async.done();
@ -59,9 +58,9 @@ export function main() {
xhr.reply('http://base/one.css', '.one {}'); xhr.reply('http://base/one.css', '.one {}');
var css = '@import url(one.css);.main {}'; var css = '@import url(one.css);.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base'); var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('.one {}\n.main {}'); expect(css).toEqual('.one {}\n.main {}');
async.done(); async.done();
@ -76,9 +75,9 @@ export function main() {
inject([StyleInliner, AsyncTestCompleter], (inliner, async) => { inject([StyleInliner, AsyncTestCompleter], (inliner, async) => {
var css = '@import "one.css";.main {}'; var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base'); var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}'); expect(css).toEqual('/* failed to import http://base/one.css */\n.main {}');
async.done(); async.done();
@ -95,9 +94,9 @@ export function main() {
xhr.reply('http://base/two.css', '.two {}'); xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";@import "two.css";.main {}'; var css = '@import "one.css";@import "two.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base'); var loadedCss = inliner.inlineImports(css, 'http://base');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('.one {}\n.two {}\n.main {}'); expect(css).toEqual('.one {}\n.two {}\n.main {}');
async.done(); async.done();
@ -114,9 +113,9 @@ export function main() {
xhr.reply('http://base/two.css', '.two {}'); xhr.reply('http://base/two.css', '.two {}');
var css = '@import "one.css";.main {}'; var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/'); var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}'); expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done(); async.done();
@ -133,9 +132,9 @@ export function main() {
xhr.reply('http://base/two.css', '@import "one.css";.two {}'); xhr.reply('http://base/two.css', '@import "one.css";.two {}');
var css = '@import "one.css";.main {}'; var css = '@import "one.css";.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/'); var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('.two {}\n.one {}\n.main {}'); expect(css).toEqual('.two {}\n.one {}\n.main {}');
async.done(); async.done();
@ -151,9 +150,9 @@ export function main() {
// Invalid rule: the url is not quoted // Invalid rule: the url is not quoted
var css = '@import one.css;.main {}'; var css = '@import one.css;.main {}';
var loadedCss = inliner.inlineImports(css, 'http://base/'); var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}'); expect(css).toEqual('/* Invalid import rule: "@import one.css;" */.main {}');
async.done(); async.done();
@ -171,9 +170,9 @@ export function main() {
xhr.reply('http://base/one.css', '.one {}'); xhr.reply('http://base/one.css', '.one {}');
var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);'; var css = '@import "one.css" (min-width: 700px) and (orientation: landscape);';
var loadedCss = inliner.inlineImports(css, 'http://base/'); var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual('@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n'); expect(css).toEqual('@media (min-width: 700px) and (orientation: landscape) {\n.one {}\n}\n');
async.done(); async.done();
@ -193,9 +192,9 @@ export function main() {
xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}'); xhr.reply('http://base/nested/two.css', '.two {background-image: url("../img/two.jpg");}');
var css = '@import "one.css";' var css = '@import "one.css";'
var loadedCss = inliner.inlineImports(css, 'http://base/'); var loadedCss = inliner.inlineImports(css, 'http://base/');
expect(loadedCss).toBePromise(); expect(loadedCss.asyncResult).toBePromise();
PromiseWrapper.then( PromiseWrapper.then(
loadedCss, loadedCss.asyncResult,
function(css) { function(css) {
expect(css).toEqual( expect(css).toEqual(
".two {background-image: url('http://base/img/two.jpg');}\n" + ".two {background-image: url('http://base/img/two.jpg');}\n" +

View File

@ -21,7 +21,6 @@ module.exports = function makeNodeTree(destinationPath) {
include: ['angular2/**', 'benchpress/**', 'rtts_assert/**', '**/e2e_test/**'], include: ['angular2/**', 'benchpress/**', 'rtts_assert/**', '**/e2e_test/**'],
exclude: [ exclude: [
// the following code and tests are not compatible with CJS/node environment // the following code and tests are not compatible with CJS/node environment
'angular2/src/core/zone/ng_zone.es6',
'angular2/test/core/zone/**', 'angular2/test/core/zone/**',
'angular2/test/test_lib/fake_async_spec.js' 'angular2/test/test_lib/fake_async_spec.js'
] ]