feat(web-workers) Add WebWorker Renderer
Allows angular apps to be rendered from the webworker! Closes #3052, #3053, and #3097
This commit is contained in:
		
							parent
							
								
									21b988f554
								
							
						
					
					
						commit
						771c0170d9
					
				| @ -106,7 +106,7 @@ export class Parser { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class _ParseAST { | ||||
| export class _ParseAST { | ||||
|   index: int = 0; | ||||
|   constructor(public input: string, public location: any, public tokens: List<any>, | ||||
|               public reflector: Reflector, public parseAction: boolean) {} | ||||
|  | ||||
| @ -45,6 +45,7 @@ import {HammerGesturesPlugin} from 'angular2/src/render/dom/events/hammer_gestur | ||||
| import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; | ||||
| import {UrlResolver} from 'angular2/src/services/url_resolver'; | ||||
| import {AppRootUrl} from 'angular2/src/services/app_root_url'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| import { | ||||
|   ComponentRef, | ||||
|   DynamicComponentLoader | ||||
| @ -136,14 +137,14 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> { | ||||
|     StyleInliner, | ||||
|     DynamicComponentLoader, | ||||
|     Testability, | ||||
|     AppRootUrl | ||||
|     AnchorBasedAppRootUrl, | ||||
|     bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl) | ||||
|   ]; | ||||
| } | ||||
| 
 | ||||
| function _createNgZone(): NgZone { | ||||
| export function createNgZone(handler: ExceptionHandler): NgZone { | ||||
|   // bootstrapErrorReporter is needed because we cannot use custom exception handler
 | ||||
|   // configured via DI until the root Injector has been created.
 | ||||
|   var handler = new ExceptionHandler(); | ||||
|   var bootstrapErrorReporter = (exception, stackTrace) => handler.call(exception, stackTrace); | ||||
|   var zone = new NgZone({enableLongStackTrace: assertionsEnabled()}); | ||||
|   zone.overrideOnErrorHandler(bootstrapErrorReporter); | ||||
| @ -282,7 +283,7 @@ export function commonBootstrap( | ||||
|   BrowserDomAdapter.makeCurrent(); | ||||
|   var bootstrapProcess = PromiseWrapper.completer(); | ||||
| 
 | ||||
|   var zone = _createNgZone(); | ||||
|   var zone = createNgZone(new ExceptionHandler()); | ||||
|   zone.run(() => { | ||||
|     // TODO(rado): prepopulate template cache, so applications with only
 | ||||
|     // index.html and main.js are possible.
 | ||||
|  | ||||
| @ -39,6 +39,19 @@ bool isDate(obj) => obj is DateTime; | ||||
| 
 | ||||
| String stringify(obj) => obj.toString(); | ||||
| 
 | ||||
| int serializeEnum(val) { | ||||
|   return val.index; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Deserializes an enum | ||||
|  * val should be the indexed value of the enum (sa returned from @Link{serializeEnum}) | ||||
|  * values should be a map from indexes to values for the enum that you want to deserialize. | ||||
|  */ | ||||
| dynamic deserializeEnum(int val, Map<int, dynamic> values) { | ||||
|   return values[val]; | ||||
| } | ||||
| 
 | ||||
| class StringWrapper { | ||||
|   static String fromCharCode(int code) { | ||||
|     return new String.fromCharCode(code); | ||||
|  | ||||
| @ -130,6 +130,17 @@ export function stringify(token): string { | ||||
|   return (newLineIndex === -1) ? res : res.substring(0, newLineIndex); | ||||
| } | ||||
| 
 | ||||
| // serialize / deserialize enum exist only for consistency with dart API
 | ||||
| // enums in typescript don't need to be serialized
 | ||||
| 
 | ||||
| export function serializeEnum(val): int { | ||||
|   return val; | ||||
| } | ||||
| 
 | ||||
| export function deserializeEnum(val, values: Map<int, any>): any { | ||||
|   return val; | ||||
| } | ||||
| 
 | ||||
| export class StringWrapper { | ||||
|   static fromCharCode(code: int): string { return String.fromCharCode(code); } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										21
									
								
								modules/angular2/src/services/anchor_based_app_root_url.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								modules/angular2/src/services/anchor_based_app_root_url.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| import {AppRootUrl} from "angular2/src/services/app_root_url"; | ||||
| import {DOM} from "angular2/src/dom/dom_adapter"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| 
 | ||||
| /** | ||||
|  * Extension of {@link AppRootUrl} that uses a DOM anchor tag to set the root url to | ||||
|  * the current page's url. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AnchorBasedAppRootUrl extends AppRootUrl { | ||||
|   constructor() { | ||||
|     super(""); | ||||
|     // compute the root url to pass to AppRootUrl
 | ||||
|     var rootUrl: string; | ||||
|     var a = DOM.createElement('a'); | ||||
|     DOM.resolveAndSetHref(a, './', null); | ||||
|     rootUrl = DOM.getHref(a); | ||||
| 
 | ||||
|     this.value = rootUrl; | ||||
|   } | ||||
| } | ||||
| @ -1,6 +1,5 @@ | ||||
| import {Injectable} from 'angular2/di'; | ||||
| import {isBlank} from 'angular2/src/facade/lang'; | ||||
| import {DOM} from 'angular2/src/dom/dom_adapter'; | ||||
| 
 | ||||
| /** | ||||
|  * Specifies app root url for the application. | ||||
| @ -15,16 +14,12 @@ import {DOM} from 'angular2/src/dom/dom_adapter'; | ||||
| export class AppRootUrl { | ||||
|   private _value: string; | ||||
| 
 | ||||
|   constructor(value: string) { this._value = value; } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the base URL of the currently running application. | ||||
|    */ | ||||
|   get value() { | ||||
|     if (isBlank(this._value)) { | ||||
|       var a = DOM.createElement('a'); | ||||
|       DOM.resolveAndSetHref(a, './', null); | ||||
|       this._value = DOM.getHref(a); | ||||
|     } | ||||
|   get value() { return this._value; } | ||||
| 
 | ||||
|     return this._value; | ||||
|   } | ||||
|   set value(value: string) { this._value = value; } | ||||
| } | ||||
|  | ||||
| @ -23,6 +23,7 @@ import {XHR} from 'angular2/src/render/xhr'; | ||||
| import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; | ||||
| import {UrlResolver} from 'angular2/src/services/url_resolver'; | ||||
| import {AppRootUrl} from 'angular2/src/services/app_root_url'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; | ||||
| import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner'; | ||||
| import {NgZone} from 'angular2/src/core/zone/ng_zone'; | ||||
| @ -56,6 +57,7 @@ import { | ||||
|   DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES | ||||
| } from 'angular2/src/render/dom/dom_renderer'; | ||||
| import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler'; | ||||
| import {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| import {Log} from './utils'; | ||||
| 
 | ||||
| /** | ||||
| @ -88,6 +90,7 @@ function _getAppBindings() { | ||||
|   } catch (e) { | ||||
|     appDoc = null; | ||||
|   } | ||||
| 
 | ||||
|   return [ | ||||
|     bind(DOCUMENT_TOKEN) | ||||
|         .toValue(appDoc), | ||||
| @ -102,6 +105,7 @@ function _getAppBindings() { | ||||
|     AppViewPool, | ||||
|     AppViewManager, | ||||
|     AppViewManagerUtils, | ||||
|     Serializer, | ||||
|     ELEMENT_PROBE_CONFIG, | ||||
|     bind(APP_VIEW_POOL_CAPACITY).toValue(500), | ||||
|     Compiler, | ||||
| @ -120,7 +124,8 @@ function _getAppBindings() { | ||||
|     bind(XHR).toClass(MockXHR), | ||||
|     ComponentUrlMapper, | ||||
|     UrlResolver, | ||||
|     AppRootUrl, | ||||
|     AnchorBasedAppRootUrl, | ||||
|     bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl), | ||||
|     StyleUrlResolver, | ||||
|     StyleInliner, | ||||
|     TestComponentBuilder, | ||||
|  | ||||
							
								
								
									
										9
									
								
								modules/angular2/src/web-workers/shared/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								modules/angular2/src/web-workers/shared/api.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| import {CONST_EXPR} from "angular2/src/facade/lang"; | ||||
| import {OpaqueToken} from "angular2/di"; | ||||
| import {RenderElementRef, RenderViewRef} from "angular2/src/render/api"; | ||||
| 
 | ||||
| export const ON_WEBWORKER = CONST_EXPR(new OpaqueToken('WebWorker.onWebWorker')); | ||||
| 
 | ||||
| export class WorkerElementRef implements RenderElementRef { | ||||
|   constructor(public renderView: RenderViewRef, public renderBoundElementIndex: number) {} | ||||
| } | ||||
| @ -13,6 +13,14 @@ export interface SourceListener { | ||||
|   (data: any): void;  // TODO: Replace this any type with the type of a real messaging protocol
 | ||||
| } | ||||
| 
 | ||||
| export interface MessageBusSource { listen(fn: SourceListener): void; } | ||||
| export interface MessageBusSource { | ||||
|   /** | ||||
|    * Attaches the SourceListener to this source. | ||||
|    * The SourceListener will get called whenever the bus receives a message | ||||
|    * Returns a listener id that can be passed to {@link removeListener} | ||||
|    */ | ||||
|   addListener(fn: SourceListener): number; | ||||
|   removeListener(index: number); | ||||
| } | ||||
| 
 | ||||
| export interface MessageBusSink { send(message: Object): void; } | ||||
|  | ||||
| @ -0,0 +1,56 @@ | ||||
| import {Injectable, Inject} from "angular2/di"; | ||||
| import {RenderProtoViewRef} from "angular2/src/render/api"; | ||||
| import {ON_WEBWORKER} from "angular2/src/web-workers/shared/api"; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class RenderProtoViewRefStore { | ||||
|   private _lookupByIndex: Map<number, RenderProtoViewRef> = new Map<number, RenderProtoViewRef>(); | ||||
|   private _lookupByProtoView: Map<RenderProtoViewRef, number> = | ||||
|       new Map<RenderProtoViewRef, number>(); | ||||
|   private _nextIndex: number = 0; | ||||
|   private _onWebworker: boolean; | ||||
| 
 | ||||
|   constructor(@Inject(ON_WEBWORKER) onWebworker) { this._onWebworker = onWebworker; } | ||||
| 
 | ||||
|   storeRenderProtoViewRef(ref: RenderProtoViewRef): number { | ||||
|     if (this._lookupByProtoView.has(ref)) { | ||||
|       return this._lookupByProtoView.get(ref); | ||||
|     } else { | ||||
|       this._lookupByIndex.set(this._nextIndex, ref); | ||||
|       this._lookupByProtoView.set(ref, this._nextIndex); | ||||
|       return this._nextIndex++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   retreiveRenderProtoViewRef(index: number): RenderProtoViewRef { | ||||
|     return this._lookupByIndex.get(index); | ||||
|   } | ||||
| 
 | ||||
|   deserialize(index: number): RenderProtoViewRef { | ||||
|     if (index == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (this._onWebworker) { | ||||
|       return new WebworkerRenderProtoViewRef(index); | ||||
|     } else { | ||||
|       return this.retreiveRenderProtoViewRef(index); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   serialize(ref: RenderProtoViewRef): number { | ||||
|     if (ref == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (this._onWebworker) { | ||||
|       return (<WebworkerRenderProtoViewRef>ref).refNumber; | ||||
|     } else { | ||||
|       return this.storeRenderProtoViewRef(ref); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class WebworkerRenderProtoViewRef extends RenderProtoViewRef { | ||||
|   constructor(public refNumber: number) { super(); } | ||||
| } | ||||
| @ -0,0 +1,149 @@ | ||||
| import {Injectable, Inject} from "angular2/di"; | ||||
| import {RenderViewRef, RenderFragmentRef, RenderViewWithFragments} from "angular2/src/render/api"; | ||||
| import {ON_WEBWORKER} from "angular2/src/web-workers/shared/api"; | ||||
| import {List, ListWrapper} from "angular2/src/facade/collection"; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class RenderViewWithFragmentsStore { | ||||
|   private _nextIndex: number = 0; | ||||
|   private _onWebWorker: boolean; | ||||
|   private _lookupByIndex: Map<number, RenderViewRef | RenderFragmentRef>; | ||||
|   private _lookupByView: Map<RenderViewRef | RenderFragmentRef, number>; | ||||
| 
 | ||||
|   constructor(@Inject(ON_WEBWORKER) onWebWorker) { | ||||
|     this._onWebWorker = onWebWorker; | ||||
|     if (!onWebWorker) { | ||||
|       this._lookupByIndex = new Map<number, RenderViewRef | RenderFragmentRef>(); | ||||
|       this._lookupByView = new Map<RenderViewRef | RenderFragmentRef, number>(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   allocate(fragmentCount: number): RenderViewWithFragments { | ||||
|     var viewRef = new WorkerRenderViewRef(this._nextIndex++); | ||||
|     var fragmentRefs = ListWrapper.createGrowableSize(fragmentCount); | ||||
| 
 | ||||
|     for (var i = 0; i < fragmentCount; i++) { | ||||
|       fragmentRefs[i] = new WorkerRenderFragmentRef(this._nextIndex++); | ||||
|     } | ||||
|     return new RenderViewWithFragments(viewRef, fragmentRefs); | ||||
|   } | ||||
| 
 | ||||
|   store(view: RenderViewWithFragments, startIndex: number) { | ||||
|     this._lookupByIndex.set(startIndex, view.viewRef); | ||||
|     this._lookupByView.set(view.viewRef, startIndex); | ||||
|     startIndex++; | ||||
| 
 | ||||
|     ListWrapper.forEach(view.fragmentRefs, (ref) => { | ||||
|       this._lookupByIndex.set(startIndex, ref); | ||||
|       this._lookupByView.set(ref, startIndex); | ||||
|       startIndex++; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   retreive(ref: number): RenderViewRef | RenderFragmentRef { | ||||
|     if (ref == null) { | ||||
|       return null; | ||||
|     } | ||||
|     return this._lookupByIndex.get(ref); | ||||
|   } | ||||
| 
 | ||||
|   serializeRenderViewRef(viewRef: RenderViewRef): number { | ||||
|     return this._serializeRenderFragmentOrViewRef(viewRef); | ||||
|   } | ||||
| 
 | ||||
|   serializeRenderFragmentRef(fragmentRef: RenderFragmentRef): number { | ||||
|     return this._serializeRenderFragmentOrViewRef(fragmentRef); | ||||
|   } | ||||
| 
 | ||||
|   deserializeRenderViewRef(ref: number): RenderViewRef { | ||||
|     if (ref == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (this._onWebWorker) { | ||||
|       return WorkerRenderViewRef.deserialize(ref); | ||||
|     } else { | ||||
|       return this.retreive(ref); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   deserializeRenderFragmentRef(ref: number): RenderFragmentRef { | ||||
|     if (ref == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (this._onWebWorker) { | ||||
|       return WorkerRenderFragmentRef.deserialize(ref); | ||||
|     } else { | ||||
|       return this.retreive(ref); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private _serializeRenderFragmentOrViewRef(ref: RenderViewRef | RenderFragmentRef): number { | ||||
|     if (ref == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (this._onWebWorker) { | ||||
|       return (<WorkerRenderFragmentRef | WorkerRenderViewRef>ref).serialize(); | ||||
|     } else { | ||||
|       return this._lookupByView.get(ref); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   serializeViewWithFragments(view: RenderViewWithFragments): StringMap<string, any> { | ||||
|     if (view == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     if (this._onWebWorker) { | ||||
|       return { | ||||
|         'viewRef': (<WorkerRenderViewRef>view.viewRef).serialize(), | ||||
|         'fragmentRefs': ListWrapper.map(view.fragmentRefs, (val) => val.serialize()) | ||||
|       }; | ||||
|     } else { | ||||
|       return { | ||||
|         'viewRef': this._lookupByView.get(view.viewRef), | ||||
|         'fragmentRefs': ListWrapper.map(view.fragmentRefs, (val) => this._lookupByView.get(val)) | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   deserializeViewWithFragments(obj: StringMap<string, any>): RenderViewWithFragments { | ||||
|     if (obj == null) { | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     var viewRef: RenderViewRef | RenderFragmentRef; | ||||
|     var fragments: List<RenderViewRef | RenderFragmentRef>; | ||||
|     if (this._onWebWorker) { | ||||
|       viewRef = WorkerRenderViewRef.deserialize(obj['viewRef']); | ||||
|       fragments = | ||||
|           ListWrapper.map(obj['fragmentRefs'], (val) => WorkerRenderFragmentRef.deserialize(val)); | ||||
| 
 | ||||
|       return new RenderViewWithFragments(viewRef, fragments); | ||||
|     } else { | ||||
|       viewRef = this.retreive(obj['viewRef']); | ||||
|       fragments = ListWrapper.map(obj['fragmentRefs'], (val) => this.retreive(val)); | ||||
| 
 | ||||
|       return new RenderViewWithFragments(viewRef, fragments); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class WorkerRenderViewRef extends RenderViewRef { | ||||
|   constructor(public refNumber: number) { super(); } | ||||
|   serialize(): number { return this.refNumber; } | ||||
| 
 | ||||
|   static deserialize(ref: number): WorkerRenderViewRef { return new WorkerRenderViewRef(ref); } | ||||
| } | ||||
| 
 | ||||
| export class WorkerRenderFragmentRef extends RenderFragmentRef { | ||||
|   constructor(public refNumber: number) { super(); } | ||||
| 
 | ||||
|   serialize(): number { return this.refNumber; } | ||||
| 
 | ||||
|   static deserialize(ref: number): WorkerRenderFragmentRef { | ||||
|     return new WorkerRenderFragmentRef(ref); | ||||
|   } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| import {Type, isArray, isPresent} from "angular2/src/facade/lang"; | ||||
| import {Type, isArray, isPresent, serializeEnum, deserializeEnum} from "angular2/src/facade/lang"; | ||||
| import {List, ListWrapper, Map, StringMapWrapper, MapWrapper} from "angular2/src/facade/collection"; | ||||
| import { | ||||
|   ProtoViewDto, | ||||
| @ -7,75 +7,122 @@ import { | ||||
|   DirectiveBinder, | ||||
|   ElementPropertyBinding, | ||||
|   EventBinding, | ||||
|   ViewDefinition | ||||
|   ViewDefinition, | ||||
|   RenderProtoViewRef, | ||||
|   RenderProtoViewMergeMapping, | ||||
|   RenderViewRef, | ||||
|   RenderFragmentRef, | ||||
|   RenderElementRef, | ||||
|   ViewType | ||||
| } from "angular2/src/render/api"; | ||||
| import {WorkerElementRef} from 'angular2/src/web-workers/shared/api'; | ||||
| import {AST, ASTWithSource} from "angular2/change_detection"; | ||||
| import {Parser} from "angular2/src/change_detection/parser/parser"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store'; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class Serializer { | ||||
|   static parser: Parser = null; | ||||
|   private _enumRegistry: Map<any, Map<int, any>>; | ||||
|   constructor(private _parser: Parser, private _protoViewStore: RenderProtoViewRefStore, | ||||
|               private _renderViewStore: RenderViewWithFragmentsStore) { | ||||
|     this._enumRegistry = new Map<any, Map<int, any>>(); | ||||
|     var viewTypeMap = new Map<int, any>(); | ||||
|     viewTypeMap[0] = ViewType.HOST; | ||||
|     viewTypeMap[1] = ViewType.COMPONENT; | ||||
|     viewTypeMap[2] = ViewType.EMBEDDED; | ||||
|     this._enumRegistry.set(ViewType, viewTypeMap); | ||||
|   } | ||||
| 
 | ||||
|   static serialize(obj: any, type: Type): Object { | ||||
|   serialize(obj: any, type: Type): Object { | ||||
|     if (!isPresent(obj)) { | ||||
|       return null; | ||||
|     } | ||||
|     if (isArray(obj)) { | ||||
|       var serializedObj = []; | ||||
|       ListWrapper.forEach(obj, (val) => { serializedObj.push(Serializer.serialize(val, type)); }); | ||||
|       ListWrapper.forEach(obj, (val) => { serializedObj.push(this.serialize(val, type)); }); | ||||
|       return serializedObj; | ||||
|     } | ||||
|     if (type == String) { | ||||
|       return obj; | ||||
|     } | ||||
|     if (type == ViewDefinition) { | ||||
|       return ViewDefinitionSerializer.serialize(obj); | ||||
|       return this._serializeViewDefinition(obj); | ||||
|     } else if (type == DirectiveBinder) { | ||||
|       return DirectiveBinderSerializer.serialize(obj); | ||||
|       return this._serializeDirectiveBinder(obj); | ||||
|     } else if (type == ProtoViewDto) { | ||||
|       return ProtoViewDtoSerializer.serialize(obj); | ||||
|       return this._serializeProtoViewDto(obj); | ||||
|     } else if (type == ElementBinder) { | ||||
|       return ElementBinderSerializer.serialize(obj); | ||||
|       return this._serializeElementBinder(obj); | ||||
|     } else if (type == DirectiveMetadata) { | ||||
|       return DirectiveMetadataSerializer.serialize(obj); | ||||
|       return this._serializeDirectiveMetadata(obj); | ||||
|     } else if (type == ASTWithSource) { | ||||
|       return ASTWithSourceSerializer.serialize(obj); | ||||
|       return this._serializeASTWithSource(obj); | ||||
|     } else if (type == RenderProtoViewRef) { | ||||
|       return this._protoViewStore.serialize(obj); | ||||
|     } else if (type == RenderProtoViewMergeMapping) { | ||||
|       return this._serializeRenderProtoViewMergeMapping(obj); | ||||
|     } else if (type == RenderViewRef) { | ||||
|       return this._renderViewStore.serializeRenderViewRef(obj); | ||||
|     } else if (type == RenderFragmentRef) { | ||||
|       return this._renderViewStore.serializeRenderFragmentRef(obj); | ||||
|     } else if (type == WorkerElementRef) { | ||||
|       return this._serializeWorkerElementRef(obj); | ||||
|     } else { | ||||
|       throw "No serializer for " + type.toString(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // TODO: template this to return the type that is passed if possible
 | ||||
|   static deserialize(map: List<any>, type: Type, data?: any): any { | ||||
|   deserialize(map: any, type: Type, data?: any): any { | ||||
|     if (!isPresent(map)) { | ||||
|       return null; | ||||
|     } | ||||
|     if (isArray(map)) { | ||||
|       var obj: List<any> = new List<any>(); | ||||
|       ListWrapper.forEach(map, (val) => { obj.push(Serializer.deserialize(val, type, data)); }); | ||||
|       ListWrapper.forEach(map, (val) => { obj.push(this.deserialize(val, type, data)); }); | ||||
|       return obj; | ||||
|     } | ||||
|     if (type == String) { | ||||
|       return map; | ||||
|     } | ||||
| 
 | ||||
|     if (type == ViewDefinition) { | ||||
|       return ViewDefinitionSerializer.deserialize(map); | ||||
|       return this._deserializeViewDefinition(map); | ||||
|     } else if (type == DirectiveBinder) { | ||||
|       return DirectiveBinderSerializer.deserialize(map); | ||||
|       return this._deserializeDirectiveBinder(map); | ||||
|     } else if (type == ProtoViewDto) { | ||||
|       return ProtoViewDtoSerializer.deserialize(map); | ||||
|       return this._deserializeProtoViewDto(map); | ||||
|     } else if (type == DirectiveMetadata) { | ||||
|       return DirectiveMetadataSerializer.deserialize(map); | ||||
|       return this._deserializeDirectiveMetadata(map); | ||||
|     } else if (type == ElementBinder) { | ||||
|       return ElementBinderSerializer.deserialize(map); | ||||
|       return this._deserializeElementBinder(map); | ||||
|     } else if (type == ASTWithSource) { | ||||
|       return ASTWithSourceSerializer.deserialize(map, data); | ||||
|       return this._deserializeASTWithSource(map, data); | ||||
|     } else if (type == RenderProtoViewRef) { | ||||
|       return this._protoViewStore.deserialize(map); | ||||
|     } else if (type == RenderProtoViewMergeMapping) { | ||||
|       return this._deserializeRenderProtoViewMergeMapping(map); | ||||
|     } else if (type == RenderViewRef) { | ||||
|       return this._renderViewStore.deserializeRenderViewRef(map); | ||||
|     } else if (type == RenderFragmentRef) { | ||||
|       return this._renderViewStore.deserializeRenderFragmentRef(map); | ||||
|     } else if (type == WorkerElementRef) { | ||||
|       return this._deserializeWorkerElementRef(map); | ||||
|     } else { | ||||
|       throw "No deserializer for " + type.toString(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static mapToObject(map: Map<any, any>, type?: Type): Object { | ||||
|   mapToObject(map: Map<string, any>, type?: Type): Object { | ||||
|     var object = {}; | ||||
|     var serialize = isPresent(type); | ||||
| 
 | ||||
|     MapWrapper.forEach(map, (value, key) => { | ||||
|       if (serialize) { | ||||
|         object[key] = Serializer.serialize(value, type); | ||||
|         object[key] = this.serialize(value, type); | ||||
|       } else { | ||||
|         object[key] = value; | ||||
|       } | ||||
| @ -84,191 +131,213 @@ export class Serializer { | ||||
|   } | ||||
| 
 | ||||
|   /* | ||||
|    * Transforms a Javascript object into a Map<string, V> | ||||
|    * Transforms a Javascript object (StringMap) into a Map<string, V> | ||||
|    * If the values need to be deserialized pass in their type | ||||
|    * and they will be deserialized before being placed in the map | ||||
|    */ | ||||
|   static objectToMap(obj: Object, type?: Type, data?: any): Map<string, any> { | ||||
|   objectToMap(obj: StringMap<string, any>, type?: Type, data?: any): Map<string, any> { | ||||
|     if (isPresent(type)) { | ||||
|       var map: Map<string, any> = new Map(); | ||||
|       StringMapWrapper.forEach( | ||||
|           obj, (key, val) => { map.set(key, Serializer.deserialize(val, type, data)); }); | ||||
|       StringMapWrapper.forEach(obj, | ||||
|                                (key, val) => { map.set(key, this.deserialize(val, type, data)); }); | ||||
|       return map; | ||||
|     } else { | ||||
|       return MapWrapper.createFromStringMap(obj); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ASTWithSourceSerializer { | ||||
|   static serialize(tree: ASTWithSource): Object { | ||||
|   allocateRenderViews(fragmentCount: number) { this._renderViewStore.allocate(fragmentCount); } | ||||
| 
 | ||||
|   private _serializeWorkerElementRef(elementRef: RenderElementRef): StringMap<string, any> { | ||||
|     return { | ||||
|       'renderView': this.serialize(elementRef.renderView, RenderViewRef), | ||||
|       'renderBoundElementIndex': elementRef.renderBoundElementIndex | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   private _deserializeWorkerElementRef(map: StringMap<string, any>): RenderElementRef { | ||||
|     return new WorkerElementRef(this.deserialize(map['renderView'], RenderViewRef), | ||||
|                                 map['renderBoundElementIndex']); | ||||
|   } | ||||
| 
 | ||||
|   private _serializeRenderProtoViewMergeMapping(mapping: RenderProtoViewMergeMapping): Object { | ||||
|     return { | ||||
|       'mergedProtoViewRef': this._protoViewStore.serialize(mapping.mergedProtoViewRef), | ||||
|       'fragmentCount': mapping.fragmentCount, | ||||
|       'mappedElementIndices': mapping.mappedElementIndices, | ||||
|       'mappedElementCount': mapping.mappedElementCount, | ||||
|       'mappedTextIndices': mapping.mappedTextIndices, | ||||
|       'hostElementIndicesByViewIndex': mapping.hostElementIndicesByViewIndex, | ||||
|       'nestedViewCountByViewIndex': mapping.nestedViewCountByViewIndex | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   private _deserializeRenderProtoViewMergeMapping(obj: StringMap<string, any>): | ||||
|       RenderProtoViewMergeMapping { | ||||
|     return new RenderProtoViewMergeMapping( | ||||
|         this._protoViewStore.deserialize(obj['mergedProtoViewRef']), obj['fragmentCount'], | ||||
|         obj['mappedElementIndices'], obj['mappedElementCount'], obj['mappedTextIndices'], | ||||
|         obj['hostElementIndicesByViewIndex'], obj['nestedViewCountByViewIndex']); | ||||
|   } | ||||
| 
 | ||||
|   private _serializeASTWithSource(tree: ASTWithSource): Object { | ||||
|     return {'input': tree.source, 'location': tree.location}; | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj: any, data: string): AST { | ||||
|   private _deserializeASTWithSource(obj: StringMap<string, any>, data: string): AST { | ||||
|     // TODO: make ASTs serializable
 | ||||
|     var ast: AST; | ||||
|     switch (data) { | ||||
|       case "interpolation": | ||||
|         ast = Serializer.parser.parseInterpolation(obj.input, obj.location); | ||||
|         ast = this._parser.parseInterpolation(obj['input'], obj['location']); | ||||
|         break; | ||||
|       case "binding": | ||||
|         ast = Serializer.parser.parseBinding(obj.input, obj.location); | ||||
|         ast = this._parser.parseBinding(obj['input'], obj['location']); | ||||
|         break; | ||||
|       case "simpleBinding": | ||||
|         ast = Serializer.parser.parseSimpleBinding(obj.input, obj.location); | ||||
|         ast = this._parser.parseSimpleBinding(obj['input'], obj['location']); | ||||
|         break; | ||||
|       /*case "templateBindings": | ||||
|         ast = Serializer.parser.parseTemplateBindings(obj.input, obj.location); | ||||
|         break;*/ | ||||
|       case "interpolation": | ||||
|         ast = Serializer.parser.parseInterpolation(obj.input, obj.location); | ||||
|         ast = this._parser.parseInterpolation(obj['input'], obj['location']); | ||||
|         break; | ||||
|       default: | ||||
|         throw "No AST deserializer for " + data; | ||||
|     } | ||||
|     return ast; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ViewDefinitionSerializer { | ||||
|   static serialize(view: ViewDefinition): Object { | ||||
|   private _serializeViewDefinition(view: ViewDefinition): Object { | ||||
|     return { | ||||
|       'componentId': view.componentId, | ||||
|       'templateAbsUrl': view.templateAbsUrl, | ||||
|       'template': view.template, | ||||
|       'directives': Serializer.serialize(view.directives, DirectiveMetadata), | ||||
|       'directives': this.serialize(view.directives, DirectiveMetadata), | ||||
|       'styleAbsUrls': view.styleAbsUrls, | ||||
|       'styles': view.styles | ||||
|     }; | ||||
|   } | ||||
|   static deserialize(obj: any): ViewDefinition { | ||||
| 
 | ||||
|   private _deserializeViewDefinition(obj: StringMap<string, any>): ViewDefinition { | ||||
|     return new ViewDefinition({ | ||||
|       componentId: obj.componentId, | ||||
|       templateAbsUrl: obj.templateAbsUrl, template: obj.template, | ||||
|       directives: Serializer.deserialize(obj.directives, DirectiveMetadata), | ||||
|       styleAbsUrls: obj.styleAbsUrls, | ||||
|       styles: obj.styles | ||||
|       componentId: obj['componentId'], | ||||
|       templateAbsUrl: obj['templateAbsUrl'], template: obj['template'], | ||||
|       directives: this.deserialize(obj['directives'], DirectiveMetadata), | ||||
|       styleAbsUrls: obj['styleAbsUrls'], | ||||
|       styles: obj['styles'] | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DirectiveBinderSerializer { | ||||
|   static serialize(binder: DirectiveBinder): Object { | ||||
|   private _serializeDirectiveBinder(binder: DirectiveBinder): Object { | ||||
|     return { | ||||
|       'directiveIndex': binder.directiveIndex, | ||||
|       'propertyBindings': Serializer.mapToObject(binder.propertyBindings, ASTWithSource), | ||||
|       'eventBindings': Serializer.serialize(binder.eventBindings, EventBinding), | ||||
|       'hostPropertyBindings': | ||||
|           Serializer.serialize(binder.hostPropertyBindings, ElementPropertyBinding) | ||||
|       'propertyBindings': this.mapToObject(binder.propertyBindings, ASTWithSource), | ||||
|       'eventBindings': this.serialize(binder.eventBindings, EventBinding), | ||||
|       'hostPropertyBindings': this.serialize(binder.hostPropertyBindings, ElementPropertyBinding) | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj: any): DirectiveBinder { | ||||
|   private _deserializeDirectiveBinder(obj: StringMap<string, any>): DirectiveBinder { | ||||
|     return new DirectiveBinder({ | ||||
|       directiveIndex: obj.directiveIndex, | ||||
|       propertyBindings: Serializer.objectToMap(obj.propertyBindings, ASTWithSource, "binding"), | ||||
|       eventBindings: Serializer.deserialize(obj.eventBindings, EventBinding), | ||||
|       hostPropertyBindings: Serializer.deserialize(obj.hostPropertyBindings, ElementPropertyBinding) | ||||
|       directiveIndex: obj['directiveIndex'], | ||||
|       propertyBindings: this.objectToMap(obj['propertyBindings'], ASTWithSource, "binding"), | ||||
|       eventBindings: this.deserialize(obj['eventBindings'], EventBinding), | ||||
|       hostPropertyBindings: this.deserialize(obj['hostPropertyBindings'], ElementPropertyBinding) | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ElementBinderSerializer { | ||||
|   static serialize(binder: ElementBinder): Object { | ||||
|   private _serializeElementBinder(binder: ElementBinder): Object { | ||||
|     return { | ||||
|       'index': binder.index, | ||||
|       'parentIndex': binder.parentIndex, | ||||
|       'distanceToParent': binder.distanceToParent, | ||||
|       'directives': Serializer.serialize(binder.directives, DirectiveBinder), | ||||
|       'nestedProtoView': Serializer.serialize(binder.nestedProtoView, ProtoViewDto), | ||||
|       'propertyBindings': Serializer.serialize(binder.propertyBindings, ElementPropertyBinding), | ||||
|       'variableBindings': Serializer.mapToObject(binder.variableBindings), | ||||
|       'eventBindings': Serializer.serialize(binder.eventBindings, EventBinding), | ||||
|       'readAttributes': Serializer.mapToObject(binder.readAttributes) | ||||
|       'directives': this.serialize(binder.directives, DirectiveBinder), | ||||
|       'nestedProtoView': this.serialize(binder.nestedProtoView, ProtoViewDto), | ||||
|       'propertyBindings': this.serialize(binder.propertyBindings, ElementPropertyBinding), | ||||
|       'variableBindings': this.mapToObject(binder.variableBindings), | ||||
|       'eventBindings': this.serialize(binder.eventBindings, EventBinding), | ||||
|       'readAttributes': this.mapToObject(binder.readAttributes) | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj: any): ElementBinder { | ||||
|   private _deserializeElementBinder(obj: StringMap<string, any>): ElementBinder { | ||||
|     return new ElementBinder({ | ||||
|       index: obj.index, | ||||
|       parentIndex: obj.parentIndex, | ||||
|       distanceToParent: obj.distanceToParent, | ||||
|       directives: Serializer.deserialize(obj.directives, DirectiveBinder), | ||||
|       nestedProtoView: Serializer.deserialize(obj.nestedProtoView, ProtoViewDto), | ||||
|       propertyBindings: Serializer.deserialize(obj.propertyBindings, ElementPropertyBinding), | ||||
|       variableBindings: Serializer.objectToMap(obj.variableBindings), | ||||
|       eventBindings: Serializer.deserialize(obj.eventBindings, EventBinding), | ||||
|       readAttributes: Serializer.objectToMap(obj.readAttributes) | ||||
|       index: obj['index'], | ||||
|       parentIndex: obj['parentIndex'], | ||||
|       distanceToParent: obj['distanceToParent'], | ||||
|       directives: this.deserialize(obj['directives'], DirectiveBinder), | ||||
|       nestedProtoView: this.deserialize(obj['nestedProtoView'], ProtoViewDto), | ||||
|       propertyBindings: this.deserialize(obj['propertyBindings'], ElementPropertyBinding), | ||||
|       variableBindings: this.objectToMap(obj['variableBindings']), | ||||
|       eventBindings: this.deserialize(obj['eventBindings'], EventBinding), | ||||
|       readAttributes: this.objectToMap(obj['readAttributes']) | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ProtoViewDtoSerializer { | ||||
|   static serialize(view: ProtoViewDto): Object { | ||||
|     // TODO: fix render refs and write a serializer for them
 | ||||
|   private _serializeProtoViewDto(view: ProtoViewDto): Object { | ||||
|     return { | ||||
|       'render': null, | ||||
|       'elementBinders': Serializer.serialize(view.elementBinders, ElementBinder), | ||||
|       'variableBindings': Serializer.mapToObject(view.variableBindings), | ||||
|       'textBindings': Serializer.serialize(view.textBindings, ASTWithSource), | ||||
|       'type': view.type | ||||
|       'render': this._protoViewStore.serialize(view.render), | ||||
|       'elementBinders': this.serialize(view.elementBinders, ElementBinder), | ||||
|       'variableBindings': this.mapToObject(view.variableBindings), | ||||
|       'type': serializeEnum(view.type), | ||||
|       'textBindings': this.serialize(view.textBindings, ASTWithSource), | ||||
|       'transitiveNgContentCount': view.transitiveNgContentCount | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj: any): ProtoViewDto { | ||||
|   private _deserializeProtoViewDto(obj: StringMap<string, any>): ProtoViewDto { | ||||
|     return new ProtoViewDto({ | ||||
|       render: null,  // TODO: fix render refs and write a serializer for them
 | ||||
|       elementBinders: Serializer.deserialize(obj.elementBinders, ElementBinder), | ||||
|       variableBindings: Serializer.objectToMap(obj.variableBindings), | ||||
|       textBindings: Serializer.deserialize(obj.textBindings, ASTWithSource, "interpolation"), | ||||
|       type: obj.type | ||||
|       render: this._protoViewStore.deserialize(obj["render"]), | ||||
|       elementBinders: this.deserialize(obj['elementBinders'], ElementBinder), | ||||
|       variableBindings: this.objectToMap(obj['variableBindings']), | ||||
|       textBindings: this.deserialize(obj['textBindings'], ASTWithSource, "interpolation"), | ||||
|       type: deserializeEnum(obj['type'], this._enumRegistry.get(ViewType)), | ||||
|       transitiveNgContentCount: obj['transitivengContentCount'] | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DirectiveMetadataSerializer { | ||||
|   static serialize(meta: DirectiveMetadata): Object { | ||||
|   private _serializeDirectiveMetadata(meta: DirectiveMetadata): Object { | ||||
|     var obj = { | ||||
|       'id': meta.id, | ||||
|       'selector': meta.selector, | ||||
|       'compileChildren': meta.compileChildren, | ||||
|       'hostProperties': Serializer.mapToObject(meta.hostProperties), | ||||
|       'hostListeners': Serializer.mapToObject(meta.hostListeners), | ||||
|       'hostActions': Serializer.mapToObject(meta.hostActions), | ||||
|       'hostAttributes': Serializer.mapToObject(meta.hostAttributes), | ||||
|       'events': meta.events, | ||||
|       'properties': meta.properties, | ||||
|       'readAttributes': meta.readAttributes, | ||||
|       'type': meta.type, | ||||
|       'exportAs': meta.exportAs, | ||||
|       'callOnDestroy': meta.callOnDestroy, | ||||
|       'callOnChange': meta.callOnChange, | ||||
|       'callOnCheck': meta.callOnCheck, | ||||
|       'callOnInit': meta.callOnInit, | ||||
|       'callOnAllChangesDone': meta.callOnAllChangesDone, | ||||
|       'changeDetection': meta.changeDetection, | ||||
|       'events': meta.events | ||||
|       'exportAs': meta.exportAs, | ||||
|       'hostProperties': this.mapToObject(meta.hostProperties), | ||||
|       'hostListeners': this.mapToObject(meta.hostListeners), | ||||
|       'hostActions': this.mapToObject(meta.hostActions), | ||||
|       'hostAttributes': this.mapToObject(meta.hostAttributes) | ||||
|     }; | ||||
|     return obj; | ||||
|   } | ||||
|   static deserialize(obj: any): DirectiveMetadata { | ||||
|   private _deserializeDirectiveMetadata(obj: StringMap<string, any>): DirectiveMetadata { | ||||
|     return new DirectiveMetadata({ | ||||
|       id: obj.id, | ||||
|       selector: obj.selector, | ||||
|       compileChildren: obj.compileChildren, | ||||
|       hostProperties: Serializer.objectToMap(obj.hostProperties), | ||||
|       hostListeners: Serializer.objectToMap(obj.hostListeners), | ||||
|       hostActions: Serializer.objectToMap(obj.hostActions), | ||||
|       hostAttributes: Serializer.objectToMap(obj.hostAttributes), | ||||
|       properties: obj.properties, | ||||
|       readAttributes: obj.readAttributes, | ||||
|       type: obj.type, | ||||
|       exportAs: obj.exportAs, | ||||
|       callOnDestroy: obj.callOnDestroy, | ||||
|       callOnCheck: obj.callOnCheck, | ||||
|       callOnInit: obj.callOnInit, | ||||
|       callOnAllChangesDone: obj.callOnAllChangesDone, | ||||
|       changeDetection: obj.changeDetection, | ||||
|       events: obj.events | ||||
|       id: obj['id'], | ||||
|       selector: obj['selector'], | ||||
|       compileChildren: obj['compileChildren'], | ||||
|       hostProperties: this.objectToMap(obj['hostProperties']), | ||||
|       hostListeners: this.objectToMap(obj['hostListeners']), | ||||
|       hostActions: this.objectToMap(obj['hostActions']), | ||||
|       hostAttributes: this.objectToMap(obj['hostAttributes']), | ||||
|       properties: obj['properties'], | ||||
|       readAttributes: obj['readAttributes'], | ||||
|       type: obj['type'], | ||||
|       exportAs: obj['exportAs'], | ||||
|       callOnDestroy: obj['callOnDestroy'], | ||||
|       callOnChange: obj['callOnChange'], | ||||
|       callOnCheck: obj['callOnCheck'], | ||||
|       callOnInit: obj['callOnInit'], | ||||
|       callOnAllChangesDone: obj['callOnAllChangesDone'], | ||||
|       changeDetection: obj['changeDetection'], | ||||
|       events: obj['events'] | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,275 +0,0 @@ | ||||
| import {Type, isArray, isPresent} from "angular2/src/facade/lang"; | ||||
| import {List, ListWrapper, Map, StringMapWrapper, MapWrapper} from "angular2/src/facade/collection"; | ||||
| import { | ||||
|   ProtoViewDto, | ||||
|   DirectiveMetadata, | ||||
|   ElementBinder, | ||||
|   DirectiveBinder, | ||||
|   ElementPropertyBinding, | ||||
|   EventBinding, | ||||
|   ViewDefinition | ||||
| } from "angular2/src/render/api"; | ||||
| import {AST, ASTWithSource} from "angular2/change_detection"; | ||||
| import {Parser} from "angular2/src/change_detection/parser/parser"; | ||||
| 
 | ||||
| export class Serializer { | ||||
|   static parser: Parser = null; | ||||
| 
 | ||||
|   static serialize(obj: any, type: Type): Object { | ||||
|     if (!isPresent(obj)) { | ||||
|       return null; | ||||
|     } | ||||
|     if (isArray(obj)) { | ||||
|       var serializedObj = []; | ||||
|       ListWrapper.forEach(obj, (val) => { serializedObj.push(Serializer.serialize(val, type)); }); | ||||
|       return serializedObj; | ||||
|     } | ||||
|     if (type == ViewDefinition) { | ||||
|       return ViewDefinitionSerializer.serialize(obj); | ||||
|     } else if (type == DirectiveBinder) { | ||||
|       return DirectiveBinderSerializer.serialize(obj); | ||||
|     } else if (type == ProtoViewDto) { | ||||
|       return ProtoViewDtoSerializer.serialize(obj); | ||||
|     } else if (type == ElementBinder) { | ||||
|       return ElementBinderSerializer.serialize(obj); | ||||
|     } else if (type == DirectiveMetadata) { | ||||
|       return DirectiveMetadataSerializer.serialize(obj); | ||||
|     } else if (type == ASTWithSource) { | ||||
|       return ASTWithSourceSerializer.serialize(obj); | ||||
|     } else { | ||||
|       throw "No serializer for " + type.toString(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // TODO: template this to return the type that is passed if possible | ||||
|   static deserialize(map, type: Type, data?): any { | ||||
|     if (!isPresent(map)) { | ||||
|       return null; | ||||
|     } | ||||
|     if (isArray(map)) { | ||||
|       var obj: List<any> = new List<any>(); | ||||
|       ListWrapper.forEach(map, (val) => { obj.push(Serializer.deserialize(val, type, data)); }); | ||||
|       return obj; | ||||
|     } | ||||
| 
 | ||||
|     if (type == ViewDefinition) { | ||||
|       return ViewDefinitionSerializer.deserialize(map); | ||||
|     } else if (type == DirectiveBinder) { | ||||
|       return DirectiveBinderSerializer.deserialize(map); | ||||
|     } else if (type == ProtoViewDto) { | ||||
|       return ProtoViewDtoSerializer.deserialize(map); | ||||
|     } else if (type == DirectiveMetadata) { | ||||
|       return DirectiveMetadataSerializer.deserialize(map); | ||||
|     } else if (type == ElementBinder) { | ||||
|       return ElementBinderSerializer.deserialize(map); | ||||
|     } else if (type == ASTWithSource) { | ||||
|       return ASTWithSourceSerializer.deserialize(map, data); | ||||
|     } else { | ||||
|       throw "No deserializer for " + type.toString(); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static mapToObject(map, type?: Type): Object { | ||||
|     var object = {}; | ||||
|     var serialize = isPresent(type); | ||||
| 
 | ||||
|     MapWrapper.forEach(map, (value, key) => { | ||||
|       if (serialize) { | ||||
|         object[key] = Serializer.serialize(value, type); | ||||
|       } else { | ||||
|         object[key] = value; | ||||
|       } | ||||
|     }); | ||||
|     return object; | ||||
|   } | ||||
| 
 | ||||
|   /* | ||||
|    * Transforms a Javascript object into a Map<string, V> | ||||
|    * If the values need to be deserialized pass in their type | ||||
|    * and they will be deserialized before being placed in the map | ||||
|    */ | ||||
|   static objectToMap(obj, type?: Type, data?): Map<string, any> { | ||||
|     if (isPresent(type)) { | ||||
|       var map: Map<string, any> = new Map(); | ||||
|       StringMapWrapper.forEach( | ||||
|           obj, (key, val) => { map.set(key, Serializer.deserialize(val, type, data)); }); | ||||
|       return map; | ||||
|     } else { | ||||
|       return MapWrapper.createFromStringMap(obj); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ASTWithSourceSerializer { | ||||
|   static serialize(tree: ASTWithSource): Object { | ||||
|     return { 'input': tree.source, 'location': tree.location } | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj: any, data: string): AST { | ||||
|     // TODO: make ASTs serializable | ||||
|     var ast: AST; | ||||
|     switch (data) { | ||||
|       case "interpolation": | ||||
|         ast = Serializer.parser.parseInterpolation(obj.input, obj.location); | ||||
|         break; | ||||
|       case "binding": | ||||
|         ast = Serializer.parser.parseBinding(obj.input, obj.location); | ||||
|         break; | ||||
|       case "simpleBinding": | ||||
|         ast = Serializer.parser.parseSimpleBinding(obj.input, obj.location); | ||||
|         break; | ||||
|       /*case "templateBindings": | ||||
|         ast = Serializer.parser.parseTemplateBindings(obj.input, obj.location); | ||||
|         break;*/ | ||||
|       case "interpolation": | ||||
|         ast = Serializer.parser.parseInterpolation(obj.input, obj.location); | ||||
|         break; | ||||
|       default: | ||||
|         throw "No AST deserializer for " + data; | ||||
|     } | ||||
|     return ast; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ViewDefinitionSerializer { | ||||
|   static serialize(view: ViewDefinition): Object{ | ||||
|     return { | ||||
|       'componentId': view.componentId, | ||||
|       'templateAbsUrl': view.templateAbsUrl, | ||||
|       'template': view.template, | ||||
|       'directives': Serializer.serialize(view.directives, DirectiveMetadata), | ||||
|       'styleAbsUrls': view.styleAbsUrls, | ||||
|       'styles': view.styles | ||||
|     }; | ||||
|   } | ||||
|   static deserialize(obj): ViewDefinition { | ||||
|     return new ViewDefinition({ | ||||
|       'componentId': obj.componentId, | ||||
|       'templateAbsUrl': obj.templateAbsUrl, | ||||
|       'template': obj.template, | ||||
|       'directives': Serializer.deserialize(obj.directives, DirectiveMetadata), | ||||
|       'styleAbsUrls': obj.styleAbsUrls, | ||||
|       'styles': obj.styles | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DirectiveBinderSerializer { | ||||
|   static serialize(binder: DirectiveBinder): Object { | ||||
|     return { | ||||
|       'directiveIndex': binder.directiveIndex, | ||||
|       'propertyBindings': Serializer.mapToObject(binder.propertyBindings, ASTWithSource), | ||||
|       'eventBindings': Serializer.serialize(binder.eventBindings, EventBinding), | ||||
|       'hostPropertyBindings': | ||||
|           Serializer.serialize(binder.hostPropertyBindings, ElementPropertyBinding) | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj): DirectiveBinder { | ||||
|     return new DirectiveBinder({ | ||||
|       'directiveIndex': obj.directiveIndex, | ||||
|       'propertyBindings': Serializer.objectToMap(obj.propertyBindings, ASTWithSource, "binding"), | ||||
|       'eventBindings': Serializer.deserialize(obj.eventBindings, EventBinding), | ||||
|       'hostPropertyBindings': | ||||
|           Serializer.deserialize(obj.hostPropertyBindings, ElementPropertyBinding) | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ElementBinderSerializer { | ||||
|   static serialize(binder: ElementBinder): Object { | ||||
|     return { | ||||
|       'index': binder.index,  | ||||
|       'parentIndex': binder.parentIndex, | ||||
|       'distanceToParent': binder.distanceToParent, | ||||
|       'directives': Serializer.serialize(binder.directives, DirectiveBinder), | ||||
|       'nestedProtoView': Serializer.serialize(binder.nestedProtoView, ProtoViewDto), | ||||
|       'propertyBindings': Serializer.serialize(binder.propertyBindings, ElementPropertyBinding), | ||||
|       'variableBindings': Serializer.mapToObject(binder.variableBindings), | ||||
|       'eventBindings': Serializer.serialize(binder.eventBindings, EventBinding), | ||||
|       'textBindings': Serializer.serialize(binder.textBindings, ASTWithSource), | ||||
|       'readAttributes': Serializer.mapToObject(binder.readAttributes) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj): ElementBinder { | ||||
|     return new ElementBinder({ | ||||
|       'index': obj.index, | ||||
|       'parentIndex': obj.parentIndex, | ||||
|       'distanceToParent': obj.distanceToParent, | ||||
|       'directives': Serializer.deserialize(obj.directives, DirectiveBinder), | ||||
|       'nestedProtoView': Serializer.deserialize(obj.nestedProtoView, ProtoViewDto), | ||||
|       'propertyBindings': Serializer.deserialize(obj.propertyBindings, ElementPropertyBinding), | ||||
|       'variableBindings': Serializer.objectToMap(obj.variableBindings), | ||||
|       'eventBindings': Serializer.deserialize(obj.eventBindings, EventBinding), | ||||
|       'textBindings': Serializer.deserialize(obj.textBindings, ASTWithSource, "interpolation"), | ||||
|       'readAttributes': Serializer.objectToMap(obj.readAttributes) | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ProtoViewDtoSerializer { | ||||
|   static serialize(view: ProtoViewDto): Object { | ||||
|     return { | ||||
|       'render': null,  // TODO: fix render refs and write a serializer for them | ||||
|       'elementBinders': Serializer.serialize(view.elementBinders, ElementBinder), | ||||
|       'variableBindings': Serializer.mapToObject(view.variableBindings), | ||||
|       'type': view.type | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static deserialize(obj): ProtoViewDto { | ||||
|     return new ProtoViewDto({ | ||||
|       'render': null,  // TODO: fix render refs and write a serializer for them | ||||
|       'elementBinders': Serializer.deserialize(obj.elementBinders, ElementBinder), | ||||
|       'variableBindings': Serializer.objectToMap(obj.variableBindings), | ||||
|       'type': obj.type | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class DirectiveMetadataSerializer { | ||||
|   static serialize(meta: DirectiveMetadata): Object { | ||||
|     var obj = { | ||||
|       'id': meta.id, | ||||
|       'selector': meta.selector, | ||||
|       'compileChildren': meta.compileChildren, | ||||
|       'hostProperties': Serializer.mapToObject(meta.hostProperties), | ||||
|       'hostListeners': Serializer.mapToObject(meta.hostListeners), | ||||
|       'hostActions': Serializer.mapToObject(meta.hostActions), | ||||
|       'hostAttributes': Serializer.mapToObject(meta.hostAttributes), | ||||
|       'properties': meta.properties, | ||||
|       'readAttributes': meta.readAttributes, | ||||
|       'type': meta.type, | ||||
|       'exportAs': meta.exportAs, | ||||
|       'callOnDestroy': meta.callOnDestroy, | ||||
|       'callOnCheck': meta.callOnCheck, | ||||
|       'callOnInit': meta.callOnInit, | ||||
|       'callOnAllChangesDone': meta.callOnAllChangesDone, | ||||
|       'changeDetection': meta.changeDetection, | ||||
|       'events': meta.events | ||||
|     }; | ||||
|     return obj; | ||||
|   } | ||||
|   static deserialize(obj): DirectiveMetadata { | ||||
|     return new DirectiveMetadata({ | ||||
|       'id': obj.id, | ||||
|       'selector': obj.selector, | ||||
|       'compileChildren': obj.compileChildren, | ||||
|       'hostProperties': Serializer.objectToMap(obj.hostProperties), | ||||
|       'hostListeners': Serializer.objectToMap(obj.hostListeners), | ||||
|       'hostActions': Serializer.objectToMap(obj.hostActions), | ||||
|       'hostAttributes': Serializer.objectToMap(obj.hostAttributes), | ||||
|       'properties': obj.properties, | ||||
|       'readAttributes': obj.readAttributes, | ||||
|       'type': obj.type, | ||||
|       'exportAs': obj.exportAs, | ||||
|       'callOnDestroy': obj.callOnDestroy, | ||||
|       'callOnCheck': obj.callOnCheck, | ||||
|       'callOnInit': obj.callOnInit, | ||||
|       'callOnAllChangesDone': obj.callOnAllChangesDone, | ||||
|       'changeDetection': obj.changeDetection, | ||||
|       'events': obj.events | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| @ -2,23 +2,28 @@ library angular2.src.web_workers.ui; | ||||
| 
 | ||||
| import 'dart:isolate'; | ||||
| import 'dart:async'; | ||||
| import "package:angular2/src/web-workers/shared/message_bus.dart" | ||||
| import 'dart:core'; | ||||
| import 'package:angular2/src/web-workers/shared/message_bus.dart' | ||||
|     show MessageBus, MessageBusSink, MessageBusSource; | ||||
| import 'package:angular2/src/web-workers/ui/impl.dart' | ||||
|     show bootstrapUICommon; | ||||
| 
 | ||||
| /** | ||||
|  * Bootstrapping a WebWorker | ||||
|  *  | ||||
|  * | ||||
|  * You instantiate a WebWorker application by calling bootstrap with the URI of your worker's index script | ||||
|  * Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process  | ||||
|  * Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process | ||||
|  */ | ||||
| void bootstrap(String uri) { | ||||
|   throw "Not Implemented"; | ||||
|   spawnWorker(Uri.parse(uri)).then((bus) { | ||||
|     bootstrapUICommon(bus); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * To be called from the main thread to spawn and communicate with the worker thread | ||||
|  */ | ||||
| Future<UIMessageBus> spawnWorker(Uri uri) { | ||||
| Future<UIMessageBus> spawnWorker(Uri uri){ | ||||
|   var receivePort = new ReceivePort(); | ||||
|   var isolateEndSendPort = receivePort.sendPort; | ||||
|   return Isolate.spawnUri(uri, const [], isolateEndSendPort).then((_) { | ||||
| @ -52,6 +57,8 @@ class UIMessageBusSink extends MessageBusSink { | ||||
| class UIMessageBusSource extends MessageBusSource { | ||||
|   final ReceivePort _port; | ||||
|   final Stream rawDataStream; | ||||
|   Map<int, StreamSubscription> _listenerStore = new Map<int, StreamSubscription>(); | ||||
|   int _numListeners = 0; | ||||
| 
 | ||||
|   UIMessageBusSource(ReceivePort port) | ||||
|       : _port = port, | ||||
| @ -61,9 +68,17 @@ class UIMessageBusSource extends MessageBusSource { | ||||
|     return message is SendPort; | ||||
|   }); | ||||
| 
 | ||||
|   void listen(Function fn) { | ||||
|     rawDataStream.listen((message) { | ||||
|   int addListener(Function fn){ | ||||
|     var subscription = rawDataStream.listen((message){ | ||||
|       fn({"data": message}); | ||||
|     }); | ||||
| 
 | ||||
|     _listenerStore[++_numListeners] = subscription; | ||||
|     return _numListeners; | ||||
|   } | ||||
| 
 | ||||
|   void removeListener(int index){ | ||||
|     _listenerStore[index].cancel(); | ||||
|     _listenerStore.remove(index); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -5,6 +5,7 @@ import { | ||||
|   SourceListener | ||||
| } from "angular2/src/web-workers/shared/message_bus"; | ||||
| import {BaseException} from "angular2/src/facade/lang"; | ||||
| import {bootstrapUICommon} from "angular2/src/web-workers/ui/impl"; | ||||
| 
 | ||||
| /** | ||||
|  * Bootstrapping a WebWorker | ||||
| @ -15,7 +16,8 @@ import {BaseException} from "angular2/src/facade/lang"; | ||||
|  * bootstrapping process | ||||
|  */ | ||||
| export function bootstrap(uri: string): void { | ||||
|   throw new BaseException("Not Implemented"); | ||||
|   var messageBus = spawnWorker(uri); | ||||
|   bootstrapUICommon(messageBus); | ||||
| } | ||||
| 
 | ||||
| export function spawnWorker(uri: string): MessageBus { | ||||
| @ -34,7 +36,19 @@ export class UIMessageBusSink implements MessageBusSink { | ||||
| } | ||||
| 
 | ||||
| export class UIMessageBusSource implements MessageBusSource { | ||||
|   private _listenerStore: Map<int, SourceListener> = new Map<int, SourceListener>(); | ||||
|   private _numListeners: int = 0; | ||||
| 
 | ||||
|   constructor(private _worker: Worker) {} | ||||
| 
 | ||||
|   listen(fn: SourceListener): void { this._worker.addEventListener("message", fn); } | ||||
|   public addListener(fn: SourceListener): int { | ||||
|     this._worker.addEventListener("message", fn); | ||||
|     this._listenerStore[++this._numListeners] = fn; | ||||
|     return this._numListeners; | ||||
|   } | ||||
| 
 | ||||
|   public removeListener(index: int): void { | ||||
|     removeEventListener("message", this._listenerStore[index]); | ||||
|     this._listenerStore.delete(index); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										136
									
								
								modules/angular2/src/web-workers/ui/di_bindings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								modules/angular2/src/web-workers/ui/di_bindings.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | ||||
| // TODO: This whole file is nearly identical to core/application.ts.
 | ||||
| // There should be a way to refactor application so that this file is unnecessary
 | ||||
| import {Injector, bind, Binding} from "angular2/di"; | ||||
| import {Type, isBlank, isPresent} from "angular2/src/facade/lang"; | ||||
| import {Reflector, reflector} from 'angular2/src/reflection/reflection'; | ||||
| import {List, ListWrapper} from 'angular2/src/facade/collection'; | ||||
| import { | ||||
|   Parser, | ||||
|   Lexer, | ||||
|   ChangeDetection, | ||||
|   DynamicChangeDetection, | ||||
|   JitChangeDetection, | ||||
|   PreGeneratedChangeDetection, | ||||
|   Pipes, | ||||
|   defaultPipes | ||||
| } from 'angular2/change_detection'; | ||||
| import {EventManager, DomEventsPlugin} from 'angular2/src/render/dom/events/event_manager'; | ||||
| import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; | ||||
| import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter'; | ||||
| import {KeyEventsPlugin} from 'angular2/src/render/dom/events/key_events'; | ||||
| import {HammerGesturesPlugin} from 'angular2/src/render/dom/events/hammer_gestures'; | ||||
| import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool'; | ||||
| import {Renderer, RenderCompiler} from 'angular2/src/render/api'; | ||||
| import { | ||||
|   DomRenderer, | ||||
|   DOCUMENT_TOKEN, | ||||
|   DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES | ||||
| } from 'angular2/src/render/dom/dom_renderer'; | ||||
| import {DefaultDomCompiler} from 'angular2/src/render/dom/compiler/compiler'; | ||||
| import {DOM} from 'angular2/src/dom/dom_adapter'; | ||||
| import {NgZone} from 'angular2/src/core/zone/ng_zone'; | ||||
| import {ShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/shadow_dom_strategy'; | ||||
| import { | ||||
|   EmulatedUnscopedShadowDomStrategy | ||||
| } from 'angular2/src/render/dom/shadow_dom/emulated_unscoped_shadow_dom_strategy'; | ||||
| import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; | ||||
| import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils'; | ||||
| import {AppViewListener} from 'angular2/src/core/compiler/view_listener'; | ||||
| import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory'; | ||||
| import {ViewResolver} from 'angular2/src/core/compiler/view_resolver'; | ||||
| import {ViewLoader} from 'angular2/src/render/dom/compiler/view_loader'; | ||||
| import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver'; | ||||
| import {ExceptionHandler} from 'angular2/src/core/exception_handler'; | ||||
| import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; | ||||
| import {StyleInliner} from 'angular2/src/render/dom/compiler/style_inliner'; | ||||
| import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; | ||||
| import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; | ||||
| import {UrlResolver} from 'angular2/src/services/url_resolver'; | ||||
| import {Testability} from 'angular2/src/core/testability/testability'; | ||||
| import {XHR} from 'angular2/src/render/xhr'; | ||||
| import {XHRImpl} from 'angular2/src/render/xhr_impl'; | ||||
| import {Serializer} from 'angular2/src/web-workers/shared/serializer'; | ||||
| import {ON_WEBWORKER} from 'angular2/src/web-workers/shared/api'; | ||||
| import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store'; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl'; | ||||
| 
 | ||||
| var _rootInjector: Injector; | ||||
| 
 | ||||
| // Contains everything that is safe to share between applications.
 | ||||
| var _rootBindings = [bind(Reflector).toValue(reflector)]; | ||||
| 
 | ||||
| // TODO: This code is nearly identitcal to core/application. There should be a way to only write it
 | ||||
| // once
 | ||||
| function _injectorBindings(): List<Type | Binding | List<any>> { | ||||
|   var bestChangeDetection: Type = DynamicChangeDetection; | ||||
|   if (PreGeneratedChangeDetection.isSupported()) { | ||||
|     bestChangeDetection = PreGeneratedChangeDetection; | ||||
|   } else if (JitChangeDetection.isSupported()) { | ||||
|     bestChangeDetection = JitChangeDetection; | ||||
|   } | ||||
|   // compute the root url to pass to AppRootUrl
 | ||||
|   /*var rootUrl: string; | ||||
|   var a = DOM.createElement('a'); | ||||
|   DOM.resolveAndSetHref(a, './', null); | ||||
|   rootUrl = DOM.getHref(a);*/ | ||||
| 
 | ||||
|   return [ | ||||
|     bind(DOCUMENT_TOKEN) | ||||
|         .toValue(DOM.defaultDoc()), | ||||
|     bind(EventManager) | ||||
|         .toFactory( | ||||
|             (ngZone) => { | ||||
|               var plugins = | ||||
|                   [new HammerGesturesPlugin(), new KeyEventsPlugin(), new DomEventsPlugin()]; | ||||
|               return new EventManager(plugins, ngZone); | ||||
|             }, | ||||
|             [NgZone]), | ||||
|     bind(ShadowDomStrategy) | ||||
|         .toFactory((doc) => new EmulatedUnscopedShadowDomStrategy(doc.head), [DOCUMENT_TOKEN]), | ||||
|     bind(DOM_REFLECT_PROPERTIES_AS_ATTRIBUTES).toValue(false), | ||||
|     DomRenderer, | ||||
|     DefaultDomCompiler, | ||||
|     Serializer, | ||||
|     bind(Renderer).toAlias(DomRenderer), | ||||
|     bind(RenderCompiler).toAlias(DefaultDomCompiler), | ||||
|     bind(ON_WEBWORKER).toValue(false), | ||||
|     RenderViewWithFragmentsStore, | ||||
|     RenderProtoViewRefStore, | ||||
|     ProtoViewFactory, | ||||
|     AppViewPool, | ||||
|     bind(APP_VIEW_POOL_CAPACITY).toValue(10000), | ||||
|     AppViewManager, | ||||
|     AppViewManagerUtils, | ||||
|     AppViewListener, | ||||
|     Compiler, | ||||
|     CompilerCache, | ||||
|     ViewResolver, | ||||
|     bind(Pipes).toValue(defaultPipes), | ||||
|     bind(ChangeDetection).toClass(bestChangeDetection), | ||||
|     ViewLoader, | ||||
|     DirectiveResolver, | ||||
|     Parser, | ||||
|     Lexer, | ||||
|     ExceptionHandler, | ||||
|     bind(XHR).toValue(new XHRImpl()), | ||||
|     ComponentUrlMapper, | ||||
|     UrlResolver, | ||||
|     StyleUrlResolver, | ||||
|     StyleInliner, | ||||
|     DynamicComponentLoader, | ||||
|     Testability, | ||||
|     AnchorBasedAppRootUrl, | ||||
|     WebWorkerMain | ||||
|   ]; | ||||
| } | ||||
| 
 | ||||
| export function createInjector(zone: NgZone): Injector { | ||||
|   BrowserDomAdapter.makeCurrent(); | ||||
|   _rootBindings.push(bind(NgZone).toValue(zone)); | ||||
|   var injector: Injector = Injector.resolveAndCreate(_rootBindings); | ||||
|   return injector.resolveAndCreateChild(_injectorBindings()); | ||||
| } | ||||
							
								
								
									
										234
									
								
								modules/angular2/src/web-workers/ui/impl.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								modules/angular2/src/web-workers/ui/impl.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,234 @@ | ||||
| /* | ||||
|  * This file is the entry point for the main thread | ||||
|  * It takes care of spawning the worker and sending it the initial init message | ||||
|  * It also acts and the messenger between the worker thread and the renderer running on the UI | ||||
|  * thread | ||||
|  * TODO: This class might need to be refactored to match application.ts... | ||||
| */ | ||||
| 
 | ||||
| import {createInjector} from "./di_bindings"; | ||||
| import { | ||||
|   Renderer, | ||||
|   RenderCompiler, | ||||
|   DirectiveMetadata, | ||||
|   ProtoViewDto, | ||||
|   ViewDefinition, | ||||
|   RenderProtoViewRef, | ||||
|   RenderProtoViewMergeMapping, | ||||
|   RenderViewRef, | ||||
|   RenderFragmentRef | ||||
| } from "angular2/src/render/api"; | ||||
| import {Type, print, BaseException} from "angular2/src/facade/lang"; | ||||
| import {Promise, PromiseWrapper} from "angular2/src/facade/async"; | ||||
| import {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| import {MessageBus} from "angular2/src/web-workers/shared/message_bus"; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| import {createNgZone} from 'angular2/src/core/application_common'; | ||||
| import {WorkerElementRef} from 'angular2/src/web-workers/shared/api'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| import {ExceptionHandler} from 'angular2/src/core/exception_handler'; | ||||
| import {Injectable} from 'angular2/di'; | ||||
| import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter'; | ||||
| 
 | ||||
| /** | ||||
|  * Creates a zone, sets up the DI bindings | ||||
|  * And then creates a new WebWorkerMain object to handle messages from the worker | ||||
|  */ | ||||
| export function bootstrapUICommon(bus: MessageBus) { | ||||
|   BrowserDomAdapter.makeCurrent(); | ||||
|   var zone = createNgZone(new ExceptionHandler()); | ||||
|   zone.run(() => { | ||||
|     var injector = createInjector(zone); | ||||
|     var webWorkerMain = injector.get(WebWorkerMain); | ||||
|     webWorkerMain.attachToWorker(bus); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WebWorkerMain { | ||||
|   private _rootUrl: string; | ||||
|   private _bus: MessageBus; | ||||
| 
 | ||||
|   constructor(private _renderCompiler: RenderCompiler, private _renderer: Renderer, | ||||
|               private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore, | ||||
|               private _serializer: Serializer, rootUrl: AnchorBasedAppRootUrl) { | ||||
|     this._rootUrl = rootUrl.value; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Attach's this WebWorkerMain instance to the given MessageBus | ||||
|    * This instance will now listen for all messages from the worker and handle them appropriately | ||||
|    * Note: Don't attach more than one WebWorkerMain instance to the same MessageBus. | ||||
|    */ | ||||
|   attachToWorker(bus: MessageBus) { | ||||
|     this._bus = bus; | ||||
|     this._bus.source.addListener((message) => { this._handleWorkerMessage(message); }); | ||||
|   } | ||||
| 
 | ||||
|   private _sendInitMessage() { this._sendWorkerMessage("init", {"rootUrl": this._rootUrl}); } | ||||
| 
 | ||||
|   /* | ||||
|    * Sends an error back to the worker thread in response to an opeartion on the UI thread | ||||
|    */ | ||||
|   private _sendWorkerError(id: string, error: any) { | ||||
|     this._sendWorkerMessage("error", {"id": id, "error": error}); | ||||
|   } | ||||
| 
 | ||||
|   private _sendWorkerMessage(type: string, data: StringMap<string, any>) { | ||||
|     this._bus.sink.send({'type': type, 'value': data}); | ||||
|   } | ||||
| 
 | ||||
|   // TODO: Transfer the types with the serialized data so this can be automated?
 | ||||
|   private _handleCompilerMessage(data: ReceivedMessage) { | ||||
|     var promise: Promise<any>; | ||||
|     switch (data.method) { | ||||
|       case "compileHost": | ||||
|         var directiveMetadata = this._serializer.deserialize(data.args[0], DirectiveMetadata); | ||||
|         promise = this._renderCompiler.compileHost(directiveMetadata); | ||||
|         this._wrapWorkerPromise(data.id, promise, ProtoViewDto); | ||||
|         break; | ||||
|       case "compile": | ||||
|         var view = this._serializer.deserialize(data.args[0], ViewDefinition); | ||||
|         promise = this._renderCompiler.compile(view); | ||||
|         this._wrapWorkerPromise(data.id, promise, ProtoViewDto); | ||||
|         break; | ||||
|       case "mergeProtoViewsRecursively": | ||||
|         var views = this._serializer.deserialize(data.args[0], RenderProtoViewRef); | ||||
|         promise = this._renderCompiler.mergeProtoViewsRecursively(views); | ||||
|         this._wrapWorkerPromise(data.id, promise, RenderProtoViewMergeMapping); | ||||
|         break; | ||||
|       default: | ||||
|         throw new BaseException("not implemented"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private _createViewHelper(args: List<any>, method) { | ||||
|     var hostProtoView = this._serializer.deserialize(args[0], RenderProtoViewRef); | ||||
|     var fragmentCount = args[1]; | ||||
|     var startIndex, renderViewWithFragments; | ||||
|     if (method == "createView") { | ||||
|       startIndex = args[2]; | ||||
|       renderViewWithFragments = this._renderer.createView(hostProtoView, fragmentCount); | ||||
|     } else { | ||||
|       var selector = args[2]; | ||||
|       startIndex = args[3]; | ||||
|       renderViewWithFragments = | ||||
|           this._renderer.createRootHostView(hostProtoView, fragmentCount, selector); | ||||
|     } | ||||
|     this._renderViewWithFragmentsStore.store(renderViewWithFragments, startIndex); | ||||
|   } | ||||
| 
 | ||||
|   private _handleRendererMessage(data: ReceivedMessage) { | ||||
|     var args = data.args; | ||||
|     switch (data.method) { | ||||
|       case "createRootHostView": | ||||
|       case "createView": | ||||
|         this._createViewHelper(args, data.method); | ||||
|         break; | ||||
|       case "destroyView": | ||||
|         var viewRef = this._serializer.deserialize(args[0], RenderViewRef); | ||||
|         this._renderer.destroyView(viewRef); | ||||
|         break; | ||||
|       case "attachFragmentAfterFragment": | ||||
|         var previousFragment = this._serializer.deserialize(args[0], RenderFragmentRef); | ||||
|         var fragment = this._serializer.deserialize(args[1], RenderFragmentRef); | ||||
|         this._renderer.attachFragmentAfterFragment(previousFragment, fragment); | ||||
|         break; | ||||
|       case "attachFragmentAfterElement": | ||||
|         var element = this._serializer.deserialize(args[0], WorkerElementRef); | ||||
|         var fragment = this._serializer.deserialize(args[1], RenderFragmentRef); | ||||
|         this._renderer.attachFragmentAfterElement(element, fragment); | ||||
|         break; | ||||
|       case "detachFragment": | ||||
|         var fragment = this._serializer.deserialize(args[0], RenderFragmentRef); | ||||
|         this._renderer.detachFragment(fragment); | ||||
|         break; | ||||
|       case "hydrateView": | ||||
|         var viewRef = this._serializer.deserialize(args[0], RenderViewRef); | ||||
|         this._renderer.hydrateView(viewRef); | ||||
|         break; | ||||
|       case "dehydrateView": | ||||
|         var viewRef = this._serializer.deserialize(args[0], RenderViewRef); | ||||
|         this._renderer.dehydrateView(viewRef); | ||||
|         break; | ||||
|       case "setText": | ||||
|         var viewRef = this._serializer.deserialize(args[0], RenderViewRef); | ||||
|         var textNodeIndex = args[1]; | ||||
|         var text = args[2]; | ||||
|         this._renderer.setText(viewRef, textNodeIndex, text); | ||||
|         break; | ||||
|       case "setElementProperty": | ||||
|         var elementRef = this._serializer.deserialize(args[0], WorkerElementRef); | ||||
|         var propName = args[1]; | ||||
|         var propValue = args[2]; | ||||
|         this._renderer.setElementProperty(elementRef, propName, propValue); | ||||
|         break; | ||||
|       case "setElementAttribute": | ||||
|         var elementRef = this._serializer.deserialize(args[0], WorkerElementRef); | ||||
|         var attributeName = args[1]; | ||||
|         var attributeValue = args[2]; | ||||
|         this._renderer.setElementAttribute(elementRef, attributeName, attributeValue); | ||||
|         break; | ||||
|       case "setElementClass": | ||||
|         var elementRef = this._serializer.deserialize(args[0], WorkerElementRef); | ||||
|         var className = args[1]; | ||||
|         var isAdd = args[2]; | ||||
|         this._renderer.setElementClass(elementRef, className, isAdd); | ||||
|         break; | ||||
|       case "setElementStyle": | ||||
|         var elementRef = this._serializer.deserialize(args[0], WorkerElementRef); | ||||
|         var styleName = args[1]; | ||||
|         var styleValue = args[2]; | ||||
|         this._renderer.setElementStyle(elementRef, styleName, styleValue); | ||||
|         break; | ||||
|       case "invokeElementMethod": | ||||
|         var elementRef = this._serializer.deserialize(args[0], WorkerElementRef); | ||||
|         var methodName = args[1]; | ||||
|         var methodArgs = args[2]; | ||||
|         this._renderer.invokeElementMethod(elementRef, methodName, methodArgs); | ||||
|         break; | ||||
|       default: | ||||
|         throw new BaseException("Not Implemented"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // TODO: Create message type
 | ||||
|   private _handleWorkerMessage(message: StringMap<string, any>) { | ||||
|     var data: ReceivedMessage = new ReceivedMessage(message['data']); | ||||
|     switch (data.type) { | ||||
|       case "ready": | ||||
|         return this._sendInitMessage(); | ||||
|       case "compiler": | ||||
|         return this._handleCompilerMessage(data); | ||||
|       case "renderer": | ||||
|         return this._handleRendererMessage(data); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private _wrapWorkerPromise(id: string, promise: Promise<any>, type: Type): void { | ||||
|     PromiseWrapper.then(promise, (result: any) => { | ||||
|       try { | ||||
|         this._sendWorkerMessage("result", | ||||
|                                 {"id": id, "value": this._serializer.serialize(result, type)}); | ||||
|       } catch (e) { | ||||
|         print(e); | ||||
|       } | ||||
|     }, (error: any) => { this._sendWorkerError(id, error); }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ReceivedMessage { | ||||
|   method: string; | ||||
|   args: List<any>; | ||||
|   id: string; | ||||
|   type: string; | ||||
| 
 | ||||
|   constructor(data: StringMap<string, any>) { | ||||
|     this.method = data['method']; | ||||
|     this.args = data['args']; | ||||
|     this.id = data['id']; | ||||
|     this.type = data['type']; | ||||
|   } | ||||
| } | ||||
| @ -2,15 +2,18 @@ library angular2.src.web_workers.worker; | ||||
| 
 | ||||
| import "package:angular2/src/web-workers/shared/message_bus.dart" | ||||
|     show MessageBus, MessageBusSource, MessageBusSink; | ||||
| import "package:angular2/src/web-workers/worker/application_common.dart" | ||||
|   show bootstrapWebworkerCommon; | ||||
| import "package:angular2/src/facade/async.dart" show Future; | ||||
| import "package:angular2/src/core/application.dart" show ApplicationRef; | ||||
| import "package:angular2/src/facade/lang.dart" show Type, BaseException; | ||||
| import "dart:isolate"; | ||||
| import "dart:async"; | ||||
| import 'dart:core'; | ||||
| 
 | ||||
| /** | ||||
|  * Bootstrapping a Webworker Application | ||||
|  *  | ||||
|  * | ||||
|  * You instantiate the application side by calling bootstrapWebworker from your webworker index | ||||
|  * script. | ||||
|  * You must supply a SendPort for communicating with the UI side in order to instantiate | ||||
| @ -21,9 +24,11 @@ import "dart:async"; | ||||
|  */ | ||||
| Future<ApplicationRef> bootstrapWebworker( | ||||
|     SendPort replyTo, Type appComponentType, | ||||
|     [List<dynamic> componentInjectableBindings = null, | ||||
|     Function errorReporter = null]) { | ||||
|   throw new BaseException("Not implemented"); | ||||
|     [List<dynamic> componentInjectableBindings = null]) { | ||||
|   ReceivePort rPort = new ReceivePort(); | ||||
|   WorkerMessageBus bus = new WorkerMessageBus.fromPorts(replyTo, rPort); | ||||
|   return bootstrapWebworkerCommon(appComponentType, bus, | ||||
|                                     componentInjectableBindings); | ||||
| } | ||||
| 
 | ||||
| class WorkerMessageBus extends MessageBus { | ||||
| @ -52,14 +57,24 @@ class WorkerMessageBusSink extends MessageBusSink { | ||||
| class WorkerMessageBusSource extends MessageBusSource { | ||||
|   final ReceivePort _port; | ||||
|   final Stream rawDataStream; | ||||
|   Map<int, StreamSubscription> _listenerStore = new Map<int, StreamSubscription>(); | ||||
|   int _numListeners = 0; | ||||
| 
 | ||||
|   WorkerMessageBusSource(ReceivePort rPort) | ||||
|       : _port = rPort, | ||||
|         rawDataStream = rPort.asBroadcastStream(); | ||||
| 
 | ||||
|   void listen(Function fn) { | ||||
|     rawDataStream.listen((message) { | ||||
|   int addListener(Function fn){ | ||||
|     var subscription = rawDataStream.listen((message){ | ||||
|       fn({"data": message}); | ||||
|     }); | ||||
| 
 | ||||
|     _listenerStore[++_numListeners] = subscription; | ||||
|     return _numListeners; | ||||
|   } | ||||
| 
 | ||||
|   void removeListener(int index){ | ||||
|     _listenerStore[index].cancel(); | ||||
|     _listenerStore.remove(index); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,9 @@ import { | ||||
| import {Type, BaseException} from "angular2/src/facade/lang"; | ||||
| import {Binding} from "angular2/di"; | ||||
| 
 | ||||
| import {bootstrapWebworkerCommon} from "angular2/src/web-workers/worker/application_common"; | ||||
| import {ApplicationRef} from "angular2/src/core/application"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| 
 | ||||
| /** | ||||
|  * Bootstrapping a Webworker Application | ||||
| @ -19,11 +21,15 @@ import {ApplicationRef} from "angular2/src/core/application"; | ||||
|  * See the bootstrap() docs for more details. | ||||
|  */ | ||||
| export function bootstrapWebworker( | ||||
|     appComponentType: Type, componentInjectableBindings: List<Type | Binding | List<any>> = null, | ||||
|     errorReporter: Function = null): Promise<ApplicationRef> { | ||||
|   throw new BaseException("Not Implemented"); | ||||
|     appComponentType: Type, componentInjectableBindings: List<Type | Binding | List<any>> = null): | ||||
|     Promise<ApplicationRef> { | ||||
|   var bus: WorkerMessageBus = | ||||
|       new WorkerMessageBus(new WorkerMessageBusSink(), new WorkerMessageBusSource()); | ||||
| 
 | ||||
|   return bootstrapWebworkerCommon(appComponentType, bus, componentInjectableBindings); | ||||
| } | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WorkerMessageBus implements MessageBus { | ||||
|   sink: WorkerMessageBusSink; | ||||
|   source: WorkerMessageBusSource; | ||||
| @ -39,5 +45,22 @@ export class WorkerMessageBusSink implements MessageBusSink { | ||||
| } | ||||
| 
 | ||||
| export class WorkerMessageBusSource implements MessageBusSource { | ||||
|   public listen(fn: SourceListener) { addEventListener("message", fn); } | ||||
|   private listenerStore: Map<int, SourceListener>; | ||||
|   private numListeners: int; | ||||
| 
 | ||||
|   constructor() { | ||||
|     this.numListeners = 0; | ||||
|     this.listenerStore = new Map<int, SourceListener>(); | ||||
|   } | ||||
| 
 | ||||
|   public addListener(fn: SourceListener): int { | ||||
|     addEventListener("message", fn); | ||||
|     this.listenerStore[++this.numListeners] = fn; | ||||
|     return this.numListeners; | ||||
|   } | ||||
| 
 | ||||
|   public removeListener(index: int): void { | ||||
|     removeEventListener("message", this.listenerStore[index]); | ||||
|     this.listenerStore.delete(index); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										195
									
								
								modules/angular2/src/web-workers/worker/application_common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								modules/angular2/src/web-workers/worker/application_common.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,195 @@ | ||||
| import {Injector, bind, OpaqueToken, Binding} from 'angular2/di'; | ||||
| import { | ||||
|   NumberWrapper, | ||||
|   Type, | ||||
|   isBlank, | ||||
|   isPresent, | ||||
|   BaseException, | ||||
|   assertionsEnabled, | ||||
|   print, | ||||
|   stringify | ||||
| } from 'angular2/src/facade/lang'; | ||||
| import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; | ||||
| import {Reflector, reflector} from 'angular2/src/reflection/reflection'; | ||||
| import { | ||||
|   Parser, | ||||
|   Lexer, | ||||
|   ChangeDetection, | ||||
|   DynamicChangeDetection, | ||||
|   JitChangeDetection, | ||||
|   Pipes, | ||||
|   defaultPipes, | ||||
|   PreGeneratedChangeDetection | ||||
| } from 'angular2/change_detection'; | ||||
| import {StyleUrlResolver} from 'angular2/src/render/dom/compiler/style_url_resolver'; | ||||
| import {ExceptionHandler} from 'angular2/src/core/exception_handler'; | ||||
| import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver'; | ||||
| import {ViewResolver} from 'angular2/src/core/compiler/view_resolver'; | ||||
| import {List, ListWrapper} from 'angular2/src/facade/collection'; | ||||
| import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; | ||||
| import {NgZone} from 'angular2/src/core/zone/ng_zone'; | ||||
| import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; | ||||
| import {XHR} from 'angular2/src/render/xhr'; | ||||
| import {XHRImpl} from 'angular2/src/render/xhr_impl'; | ||||
| import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mapper'; | ||||
| import {UrlResolver} from 'angular2/src/services/url_resolver'; | ||||
| import {AppRootUrl} from 'angular2/src/services/app_root_url'; | ||||
| import { | ||||
|   ComponentRef, | ||||
|   DynamicComponentLoader | ||||
| } from 'angular2/src/core/compiler/dynamic_component_loader'; | ||||
| import {Testability} from 'angular2/src/core/testability/testability'; | ||||
| import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool'; | ||||
| import {AppViewManager} from 'angular2/src/core/compiler/view_manager'; | ||||
| import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils'; | ||||
| import {AppViewListener} from 'angular2/src/core/compiler/view_listener'; | ||||
| import {ProtoViewFactory} from 'angular2/src/core/compiler/proto_view_factory'; | ||||
| import {WorkerRenderer, WorkerCompiler} from './renderer'; | ||||
| import {Renderer, RenderCompiler} from 'angular2/src/render/api'; | ||||
| import {internalView} from 'angular2/src/core/compiler/view_ref'; | ||||
| 
 | ||||
| import {MessageBroker} from 'angular2/src/web-workers/worker/broker'; | ||||
| import {WorkerMessageBus} from 'angular2/src/web-workers/worker/application'; | ||||
| import { | ||||
|   appComponentRefPromiseToken, | ||||
|   appComponentTypeToken | ||||
| } from 'angular2/src/core/application_tokens'; | ||||
| import {ApplicationRef} from 'angular2/src/core/application'; | ||||
| import {createNgZone} from 'angular2/src/core/application_common'; | ||||
| import {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| import {ON_WEBWORKER} from "angular2/src/web-workers/shared/api"; | ||||
| import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store'; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| import {WorkerExceptionHandler} from 'angular2/src/web-workers/worker/exception_handler'; | ||||
| 
 | ||||
| var _rootInjector: Injector; | ||||
| 
 | ||||
| // Contains everything that is safe to share between applications.
 | ||||
| var _rootBindings = [bind(Reflector).toValue(reflector)]; | ||||
| 
 | ||||
| function _injectorBindings(appComponentType, bus: WorkerMessageBus, | ||||
|                            initData: StringMap<string, any>): List<Type | Binding | List<any>> { | ||||
|   var bestChangeDetection: Type = DynamicChangeDetection; | ||||
|   if (PreGeneratedChangeDetection.isSupported()) { | ||||
|     bestChangeDetection = PreGeneratedChangeDetection; | ||||
|   } else if (JitChangeDetection.isSupported()) { | ||||
|     bestChangeDetection = JitChangeDetection; | ||||
|   } | ||||
|   return [ | ||||
|     bind(appComponentTypeToken) | ||||
|         .toValue(appComponentType), | ||||
|     bind(appComponentRefPromiseToken) | ||||
|         .toFactory( | ||||
|             (dynamicComponentLoader, injector) => { | ||||
| 
 | ||||
|               // TODO(rado): investigate whether to support bindings on root component.
 | ||||
|               return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector) | ||||
|                   .then((componentRef) => { return componentRef; }); | ||||
|             }, | ||||
|             [DynamicComponentLoader, Injector]), | ||||
| 
 | ||||
|     bind(appComponentType).toFactory((ref) => ref.instance, [appComponentRefPromiseToken]), | ||||
|     bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()), | ||||
|                               [ExceptionHandler]), | ||||
|     Serializer, | ||||
|     bind(WorkerMessageBus).toValue(bus), | ||||
|     bind(MessageBroker) | ||||
|         .toFactory((a, b) => new MessageBroker(a, b), [WorkerMessageBus, Serializer]), | ||||
|     WorkerRenderer, | ||||
|     bind(Renderer).toAlias(WorkerRenderer), | ||||
|     WorkerCompiler, | ||||
|     bind(RenderCompiler).toAlias(WorkerCompiler), | ||||
|     bind(ON_WEBWORKER).toValue(true), | ||||
|     RenderViewWithFragmentsStore, | ||||
|     RenderProtoViewRefStore, | ||||
|     ProtoViewFactory, | ||||
|     AppViewPool, | ||||
|     bind(APP_VIEW_POOL_CAPACITY).toValue(10000), | ||||
|     AppViewManager, | ||||
|     AppViewManagerUtils, | ||||
|     AppViewListener, | ||||
|     Compiler, | ||||
|     CompilerCache, | ||||
|     ViewResolver, | ||||
|     bind(Pipes).toValue(defaultPipes), | ||||
|     bind(ChangeDetection).toClass(bestChangeDetection), | ||||
|     DirectiveResolver, | ||||
|     Parser, | ||||
|     Lexer, | ||||
|     WorkerExceptionHandler, | ||||
|     bind(ExceptionHandler).toAlias(WorkerExceptionHandler), | ||||
|     bind(XHR).toValue(new XHRImpl()), | ||||
|     ComponentUrlMapper, | ||||
|     UrlResolver, | ||||
|     StyleUrlResolver, | ||||
|     DynamicComponentLoader, | ||||
|     Testability, | ||||
|     bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])) | ||||
|   ]; | ||||
| } | ||||
| 
 | ||||
| export function bootstrapWebworkerCommon( | ||||
|     appComponentType: Type, bus: WorkerMessageBus, | ||||
|     componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> { | ||||
|   var bootstrapProcess = PromiseWrapper.completer(); | ||||
| 
 | ||||
|   var zone = createNgZone(new WorkerExceptionHandler()); | ||||
|   zone.run(() => { | ||||
|     // TODO(rado): prepopulate template cache, so applications with only
 | ||||
|     // index.html and main.js are possible.
 | ||||
|     //
 | ||||
| 
 | ||||
|     var listenerId: int; | ||||
|     listenerId = bus.source.addListener((message: StringMap<string, any>) => { | ||||
|       if (message["data"]["type"] !== "init") { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       var appInjector = _createAppInjector(appComponentType, componentInjectableBindings, zone, bus, | ||||
|                                            message["data"]["value"]); | ||||
|       var compRefToken = PromiseWrapper.wrap(() => { | ||||
|         try { | ||||
|           return appInjector.get(appComponentRefPromiseToken); | ||||
|         } catch (e) { | ||||
|           throw e; | ||||
|         } | ||||
|       }); | ||||
|       var tick = (componentRef) => { | ||||
|         var appChangeDetector = internalView(componentRef.hostView).changeDetector; | ||||
|         // retrieve life cycle: may have already been created if injected in root component
 | ||||
|         var lc = appInjector.get(LifeCycle); | ||||
|         lc.registerWith(zone, appChangeDetector); | ||||
|         lc.tick();  // the first tick that will bootstrap the app
 | ||||
| 
 | ||||
|         bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector)); | ||||
|       }; | ||||
|       PromiseWrapper.then(compRefToken, tick, | ||||
|                           (err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); }); | ||||
| 
 | ||||
|       PromiseWrapper.catchError(compRefToken, (err) => { | ||||
|         print(err); | ||||
|         bootstrapProcess.reject(err, err.stack); | ||||
|       }); | ||||
| 
 | ||||
|       bus.source.removeListener(listenerId); | ||||
|     }); | ||||
| 
 | ||||
|     bus.sink.send({'type': "ready"}); | ||||
|   }); | ||||
| 
 | ||||
|   return bootstrapProcess.promise; | ||||
| } | ||||
| 
 | ||||
| function _createAppInjector(appComponentType: Type, bindings: List<Type | Binding | List<any>>, | ||||
|                             zone: NgZone, bus: WorkerMessageBus, initData: StringMap<string, any>): | ||||
|     Injector { | ||||
|   if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings); | ||||
|   var mergedBindings: any[] = | ||||
|       isPresent(bindings) ? | ||||
|           ListWrapper.concat(_injectorBindings(appComponentType, bus, initData), bindings) : | ||||
|           _injectorBindings(appComponentType, bus, initData); | ||||
|   mergedBindings.push(bind(NgZone).toValue(zone)); | ||||
|   return _rootInjector.resolveAndCreateChild(mergedBindings); | ||||
| } | ||||
| @ -4,12 +4,15 @@ import {print, isPresent, DateWrapper, stringify} from "../../facade/lang"; | ||||
| import {Promise, PromiseCompleter, PromiseWrapper} from "angular2/src/facade/async"; | ||||
| import {ListWrapper, StringMapWrapper, MapWrapper} from "../../facade/collection"; | ||||
| import {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| import {Type} from "angular2/src/facade/lang"; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class MessageBroker { | ||||
|   private _pending: Map<string, Function> = new Map<string, Function>(); | ||||
| 
 | ||||
|   constructor(private _messageBus: MessageBus) { | ||||
|     this._messageBus.source.listen((data) => this._handleMessage(data['data'])); | ||||
|   constructor(private _messageBus: MessageBus, protected _serializer: Serializer) { | ||||
|     this._messageBus.source.addListener((data) => this._handleMessage(data['data'])); | ||||
|   } | ||||
| 
 | ||||
|   private _generateMessageId(name: string): string { | ||||
| @ -23,26 +26,48 @@ export class MessageBroker { | ||||
|     return id; | ||||
|   } | ||||
| 
 | ||||
|   runOnUiThread(args: UiArguments): Promise<any> { | ||||
|     var completer = PromiseWrapper.completer(); | ||||
|     var id: string = this._generateMessageId(args.type + args.method); | ||||
|     this._pending.set(id, completer.resolve); | ||||
|     PromiseWrapper.catchError(completer.promise, (err, stack?) => { | ||||
|       print(err); | ||||
|       completer.reject(err, stack); | ||||
|     }); | ||||
| 
 | ||||
|   runOnUiThread(args: UiArguments, returnType: Type): Promise<any> { | ||||
|     var fnArgs = []; | ||||
|     if (isPresent(args.args)) { | ||||
|       ListWrapper.forEach(args.args, (argument) => { | ||||
|         fnArgs.push(Serializer.serialize(argument.value, argument.type)); | ||||
|         if (argument.type != null) { | ||||
|           fnArgs.push(this._serializer.serialize(argument.value, argument.type)); | ||||
|         } else { | ||||
|           fnArgs.push(argument.value); | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     var promise: Promise<any>; | ||||
|     var id: string = null; | ||||
|     if (returnType != null) { | ||||
|       var completer = PromiseWrapper.completer(); | ||||
|       id = this._generateMessageId(args.type + args.method); | ||||
|       this._pending.set(id, completer.resolve); | ||||
|       PromiseWrapper.catchError(completer.promise, (err, stack?) => { | ||||
|         print(err); | ||||
|         completer.reject(err, stack); | ||||
|       }); | ||||
| 
 | ||||
|       promise = PromiseWrapper.then(completer.promise, (data: MessageResult) => { | ||||
|         if (this._serializer == null) { | ||||
|           return data.value; | ||||
|         } else { | ||||
|           return this._serializer.deserialize(data.value, returnType); | ||||
|         } | ||||
|       }); | ||||
|     } else { | ||||
|       promise = null; | ||||
|     } | ||||
| 
 | ||||
|     // TODO(jteplitz602): Create a class for these messages so we don't keep using StringMap
 | ||||
|     var message = {'type': args.type, 'method': args.method, 'args': fnArgs, 'id': id}; | ||||
|     var message = {'type': args.type, 'method': args.method, 'args': fnArgs}; | ||||
|     if (id != null) { | ||||
|       message['id'] = id; | ||||
|     } | ||||
|     this._messageBus.sink.send(message); | ||||
|     return completer.promise; | ||||
| 
 | ||||
|     return promise; | ||||
|   } | ||||
| 
 | ||||
|   private _handleMessage(message: StringMap<string, any>): void { | ||||
|  | ||||
							
								
								
									
										35
									
								
								modules/angular2/src/web-workers/worker/exception_handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								modules/angular2/src/web-workers/worker/exception_handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| import {isPresent, print, BaseException} from 'angular2/src/facade/lang'; | ||||
| import {ListWrapper, isListLikeIterable} from 'angular2/src/facade/collection'; | ||||
| import {ExceptionHandler} from 'angular2/src/core/exception_handler'; | ||||
| import {Injectable} from 'angular2/di'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WorkerExceptionHandler implements ExceptionHandler { | ||||
|   logError: Function = print; | ||||
| 
 | ||||
|   call(exception: Object, stackTrace: any = null, reason: string = null) { | ||||
|     var longStackTrace = isListLikeIterable(stackTrace) ? | ||||
|                              (<any>stackTrace).join("\n\n-----async gap-----\n") : | ||||
|                              stackTrace; | ||||
| 
 | ||||
|     this.logError(`${exception}\n\n${longStackTrace}`); | ||||
| 
 | ||||
|     if (isPresent(reason)) { | ||||
|       this.logError(`Reason: ${reason}`); | ||||
|     } | ||||
| 
 | ||||
|     var context = this._findContext(exception); | ||||
|     if (isPresent(context)) { | ||||
|       this.logError("Error Context:"); | ||||
|       this.logError(context); | ||||
|     } | ||||
| 
 | ||||
|     throw exception; | ||||
|   } | ||||
| 
 | ||||
|   _findContext(exception: any): any { | ||||
|     if (!(exception instanceof BaseException)) return null; | ||||
|     return isPresent(exception.context) ? exception.context : | ||||
|                                           this._findContext(exception.originalException); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										0
									
								
								modules/angular2/src/web-workers/worker/loader.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/angular2/src/web-workers/worker/loader.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										260
									
								
								modules/angular2/src/web-workers/worker/renderer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								modules/angular2/src/web-workers/worker/renderer.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,260 @@ | ||||
| import { | ||||
|   Renderer, | ||||
|   RenderCompiler, | ||||
|   DirectiveMetadata, | ||||
|   ProtoViewDto, | ||||
|   ViewDefinition, | ||||
|   RenderProtoViewRef, | ||||
|   RenderViewRef, | ||||
|   RenderElementRef, | ||||
|   RenderEventDispatcher, | ||||
|   RenderProtoViewMergeMapping, | ||||
|   RenderViewWithFragments, | ||||
|   RenderFragmentRef | ||||
| } from 'angular2/src/render/api'; | ||||
| import {Promise, PromiseWrapper} from "angular2/src/facade/async"; | ||||
| import {MessageBroker, FnArg, UiArguments} from "angular2/src/web-workers/worker/broker"; | ||||
| import {isPresent, print, BaseException} from "angular2/src/facade/lang"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore, | ||||
|   WorkerRenderViewRef | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| import {WorkerElementRef} from 'angular2/src/web-workers/shared/api'; | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WorkerCompiler implements RenderCompiler { | ||||
|   constructor(private _messageBroker: MessageBroker) {} | ||||
|   /** | ||||
|    * Creats a ProtoViewDto that contains a single nested component with the given componentId. | ||||
|    */ | ||||
|   compileHost(directiveMetadata: DirectiveMetadata): Promise<ProtoViewDto> { | ||||
|     var fnArgs: List<FnArg> = [new FnArg(directiveMetadata, DirectiveMetadata)]; | ||||
|     var args: UiArguments = new UiArguments("compiler", "compileHost", fnArgs); | ||||
|     return this._messageBroker.runOnUiThread(args, ProtoViewDto); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Compiles a single DomProtoView. Non recursive so that | ||||
|    * we don't need to serialize all possible components over the wire, | ||||
|    * but only the needed ones based on previous calls. | ||||
|    */ | ||||
|   compile(view: ViewDefinition): Promise<ProtoViewDto> { | ||||
|     var fnArgs: List<FnArg> = [new FnArg(view, ViewDefinition)]; | ||||
|     var args: UiArguments = new UiArguments("compiler", "compile", fnArgs); | ||||
|     return this._messageBroker.runOnUiThread(args, ProtoViewDto); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Merges ProtoViews. | ||||
|    * The first entry of the array is the protoview into which all the other entries of the array | ||||
|    * should be merged. | ||||
|    * If the array contains other arrays, they will be merged before processing the parent array. | ||||
|    * The array must contain an entry for every component and embedded ProtoView of the first entry. | ||||
|    * @param protoViewRefs List of ProtoViewRefs or nested | ||||
|    * @return the merge result for every input array in depth first order. | ||||
|    */ | ||||
|   mergeProtoViewsRecursively( | ||||
|       protoViewRefs: List<RenderProtoViewRef | List<any>>): Promise<RenderProtoViewMergeMapping> { | ||||
|     var fnArgs: List<FnArg> = [new FnArg(protoViewRefs, RenderProtoViewRef)]; | ||||
|     var args: UiArguments = new UiArguments("compiler", "mergeProtoViewsRecursively", fnArgs); | ||||
|     return this._messageBroker.runOnUiThread(args, RenderProtoViewMergeMapping); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WorkerRenderer implements Renderer { | ||||
|   constructor(private _messageBroker: MessageBroker, | ||||
|               private _renderViewStore: RenderViewWithFragmentsStore) {} | ||||
|   /** | ||||
|    * Creates a root host view that includes the given element. | ||||
|    * Note that the fragmentCount needs to be passed in so that we can create a result | ||||
|    * synchronously even when dealing with webworkers! | ||||
|    * | ||||
|    * @param {RenderProtoViewRef} hostProtoViewRef a RenderProtoViewRef of type | ||||
|    * 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 | ||||
|    */ | ||||
|   createRootHostView(hostProtoViewRef: RenderProtoViewRef, fragmentCount: number, | ||||
|                      hostElementSelector: string): RenderViewWithFragments { | ||||
|     return this._createViewHelper(hostProtoViewRef, fragmentCount, hostElementSelector); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Creates a regular view out of the given ProtoView | ||||
|    * Note that the fragmentCount needs to be passed in so that we can create a result | ||||
|    * synchronously even when dealing with webworkers! | ||||
|    */ | ||||
|   createView(protoViewRef: RenderProtoViewRef, fragmentCount: number): RenderViewWithFragments { | ||||
|     return this._createViewHelper(protoViewRef, fragmentCount); | ||||
|   } | ||||
| 
 | ||||
|   private _createViewHelper(protoViewRef: RenderProtoViewRef, fragmentCount: number, | ||||
|                             hostElementSelector?: string): RenderViewWithFragments { | ||||
|     var renderViewWithFragments = this._renderViewStore.allocate(fragmentCount); | ||||
| 
 | ||||
|     var startIndex = (<WorkerRenderViewRef>(renderViewWithFragments.viewRef)).refNumber; | ||||
|     var fnArgs: List<FnArg> = [ | ||||
|       new FnArg(protoViewRef, RenderProtoViewRef), | ||||
|       new FnArg(fragmentCount, null), | ||||
|     ]; | ||||
|     var method = "createView"; | ||||
|     if (isPresent(hostElementSelector) && hostElementSelector != null) { | ||||
|       fnArgs.push(new FnArg(hostElementSelector, null)); | ||||
|       method = "createRootHostView"; | ||||
|     } | ||||
|     fnArgs.push(new FnArg(startIndex, null)); | ||||
| 
 | ||||
|     var args = new UiArguments("renderer", method, fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
| 
 | ||||
|     return renderViewWithFragments; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Destroys the given view after it has been dehydrated and detached | ||||
|    */ | ||||
|   destroyView(viewRef: RenderViewRef) { | ||||
|     var fnArgs = [new FnArg(viewRef, RenderViewRef)]; | ||||
|     var args = new UiArguments("renderer", "destroyView", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Attaches a fragment after another fragment. | ||||
|    */ | ||||
|   attachFragmentAfterFragment(previousFragmentRef: RenderFragmentRef, | ||||
|                               fragmentRef: RenderFragmentRef) { | ||||
|     var fnArgs = [ | ||||
|       new FnArg(previousFragmentRef, RenderFragmentRef), | ||||
|       new FnArg(fragmentRef, RenderFragmentRef) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "attachFragmentAfterFragment", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Attaches a fragment after an element. | ||||
|    */ | ||||
|   attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) { | ||||
|     var fnArgs = | ||||
|         [new FnArg(elementRef, WorkerElementRef), new FnArg(fragmentRef, RenderFragmentRef)]; | ||||
|     var args = new UiArguments("renderer", "attachFragmentAfterElement", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Detaches a fragment. | ||||
|    */ | ||||
|   detachFragment(fragmentRef: RenderFragmentRef) { | ||||
|     var fnArgs = [new FnArg(fragmentRef, RenderFragmentRef)]; | ||||
|     var args = new UiArguments("renderer", "detachFragment", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Hydrates a view after it has been attached. Hydration/dehydration is used for reusing views | ||||
|    * inside of the view pool. | ||||
|    */ | ||||
|   hydrateView(viewRef: RenderViewRef) { | ||||
|     var fnArgs = [new FnArg(viewRef, RenderViewRef)]; | ||||
|     var args = new UiArguments("renderer", "hydrateView", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Dehydrates a view after it has been attached. Hydration/dehydration is used for reusing views | ||||
|    * inside of the view pool. | ||||
|    */ | ||||
|   dehydrateView(viewRef: RenderViewRef) { | ||||
|     var fnArgs = [new FnArg(viewRef, RenderViewRef)]; | ||||
|     var args = new UiArguments("renderer", "deyhdrateView", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the native element at the given location. | ||||
|    * Attention: In a WebWorker scenario, this should always return null! | ||||
|    */ | ||||
|   getNativeElementSync(location: RenderElementRef): any { return null; } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets a property on an element. | ||||
|    */ | ||||
|   setElementProperty(location: RenderElementRef, propertyName: string, propertyValue: any) { | ||||
|     var fnArgs = [ | ||||
|       new FnArg(location, WorkerElementRef), | ||||
|       new FnArg(propertyName, null), | ||||
|       new FnArg(propertyValue, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementProperty", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets an attribute on an element. | ||||
|    */ | ||||
|   setElementAttribute(location: RenderElementRef, attributeName: string, attributeValue: string) { | ||||
|     var fnArgs = [ | ||||
|       new FnArg(location, WorkerElementRef), | ||||
|       new FnArg(attributeName, null), | ||||
|       new FnArg(attributeValue, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementAttribute", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets a class on an element. | ||||
|    */ | ||||
|   setElementClass(location: RenderElementRef, className: string, isAdd: boolean) { | ||||
|     var fnArgs = | ||||
|         [new FnArg(location, WorkerElementRef), new FnArg(className, null), new FnArg(isAdd, null)]; | ||||
|     var args = new UiArguments("renderer", "setElementClass", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets a style on an element. | ||||
|    */ | ||||
|   setElementStyle(location: RenderElementRef, styleName: string, styleValue: string) { | ||||
|     var fnArgs = [ | ||||
|       new FnArg(location, WorkerElementRef), | ||||
|       new FnArg(styleName, null), | ||||
|       new FnArg(styleValue, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementStyle", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Calls a method on an element. | ||||
|    * Note: For now we're assuming that everything in the args list are primitive | ||||
|    */ | ||||
|   invokeElementMethod(location: RenderElementRef, methodName: string, args: List<any>) { | ||||
|     var fnArgs = | ||||
|         [new FnArg(location, WorkerElementRef), new FnArg(methodName, null), new FnArg(args, null)]; | ||||
|     var uiArgs = new UiArguments("renderer", "invokeElementMethod", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(uiArgs, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the value of a text node. | ||||
|    */ | ||||
|   setText(viewRef: RenderViewRef, textNodeIndex: number, text: string) { | ||||
|     var fnArgs = | ||||
|         [new FnArg(viewRef, RenderViewRef), new FnArg(textNodeIndex, null), new FnArg(text, null)]; | ||||
|     var args = new UiArguments("renderer", "setText", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the dispatcher for all events of the given view | ||||
|    */ | ||||
|   setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) { | ||||
|     // TODO(jteplitz602) support dom events in web worker. See #3046
 | ||||
|   } | ||||
| } | ||||
| @ -58,7 +58,8 @@ export function main() { | ||||
| 
 | ||||
|       protoViewFactory = new FakeProtoViewFactory(protoViewFactoryResults); | ||||
|       return new Compiler(directiveResolver, new CompilerCache(), tplResolver, cmpUrlMapper, | ||||
|                           urlResolver, renderCompiler, protoViewFactory, new FakeAppRootUrl()); | ||||
|                           urlResolver, renderCompiler, protoViewFactory, | ||||
|                           new AppRootUrl("http://www.app.com")); | ||||
|     } | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
| @ -398,8 +399,9 @@ export function main() { | ||||
|          var reader: any = new SpyDirectiveResolver(); | ||||
| 
 | ||||
|          // create the compiler
 | ||||
|          var compiler = new Compiler(reader, cache, tplResolver, cmpUrlMapper, new UrlResolver(), | ||||
|                                      renderCompiler, protoViewFactory, new FakeAppRootUrl()); | ||||
|          var compiler = | ||||
|              new Compiler(reader, cache, tplResolver, cmpUrlMapper, new UrlResolver(), | ||||
|                           renderCompiler, protoViewFactory, new AppRootUrl("http://www.app.com")); | ||||
|          compiler.compileInHost(MainComponent) | ||||
|              .then((protoViewRef) => { | ||||
|                // the test should have failed if the resolver was called, so we're good
 | ||||
| @ -669,10 +671,6 @@ class SpyDirectiveResolver extends SpyObject { | ||||
|   noSuchMethod(m) { return super.noSuchMethod(m) } | ||||
| } | ||||
| 
 | ||||
| class FakeAppRootUrl extends AppRootUrl { | ||||
|   get value() { return 'http://www.app.com'; } | ||||
| } | ||||
| 
 | ||||
| class FakeViewResolver extends ViewResolver { | ||||
|   _cmpViews: Map<Type, viewAnn.View> = new Map(); | ||||
| 
 | ||||
|  | ||||
| @ -276,5 +276,5 @@ export function main() { | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| var someComponent = DirectiveMetadata.create( | ||||
| export var someComponent = DirectiveMetadata.create( | ||||
|     {id: 'someComponent', type: DirectiveMetadata.COMPONENT_TYPE, selector: 'some-comp'}); | ||||
|  | ||||
| @ -68,7 +68,7 @@ export class DomTestbed { | ||||
|               @Inject(DOCUMENT_TOKEN) document) { | ||||
|     this.renderer = renderer; | ||||
|     this.compiler = compiler; | ||||
|     this.rootEl = el('<div id="root"></div>'); | ||||
|     this.rootEl = el('<div id="root" class="rootElem"></div>'); | ||||
|     var oldRoots = DOM.querySelectorAll(document, '#root'); | ||||
|     for (var i = 0; i < oldRoots.length; i++) { | ||||
|       DOM.remove(oldRoots[i]); | ||||
|  | ||||
| @ -0,0 +1,24 @@ | ||||
| import {AsyncTestCompleter, inject, describe, it, expect} from "angular2/test_lib"; | ||||
| import {RenderProtoViewRef} from "angular2/src/render/api"; | ||||
| import {RenderProtoViewRefStore} from "angular2/src/web-workers/shared/render_proto_view_ref_store"; | ||||
| 
 | ||||
| export function main() { | ||||
|   describe("RenderProtoViewRefStore", () => { | ||||
|     it("should store and return the correct reference", () => { | ||||
|       var store = new RenderProtoViewRefStore(true); | ||||
|       var ref1 = new RenderProtoViewRef(); | ||||
|       var index1 = store.storeRenderProtoViewRef(ref1); | ||||
|       expect(store.retreiveRenderProtoViewRef(index1)).toBe(ref1); | ||||
|       var ref2 = new RenderProtoViewRef(); | ||||
|       var index2 = store.storeRenderProtoViewRef(ref2); | ||||
|       expect(store.retreiveRenderProtoViewRef(index2)).toBe(ref2); | ||||
|     }); | ||||
| 
 | ||||
|     it("should cache index numbers", () => { | ||||
|       var store = new RenderProtoViewRefStore(true); | ||||
|       var ref = new RenderProtoViewRef(); | ||||
|       var index = store.storeRenderProtoViewRef(ref); | ||||
|       expect(store.storeRenderProtoViewRef(ref)).toEqual(index); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| @ -0,0 +1,120 @@ | ||||
| import {AsyncTestCompleter, beforeEach, inject, describe, it, expect} from "angular2/test_lib"; | ||||
| import {RenderViewWithFragments, RenderViewRef, RenderFragmentRef} from "angular2/src/render/api"; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore, | ||||
|   WorkerRenderViewRef, | ||||
|   WorkerRenderFragmentRef | ||||
| } from "angular2/src/web-workers/shared/render_view_with_fragments_store"; | ||||
| import {List, ListWrapper} from "angular2/src/facade/collection"; | ||||
| 
 | ||||
| export function main() { | ||||
|   describe("RenderViewWithFragmentsStore", () => { | ||||
|     describe("on WebWorker", () => { | ||||
|       var store; | ||||
|       beforeEach(() => { store = new RenderViewWithFragmentsStore(true); }); | ||||
| 
 | ||||
|       it("should allocate fragmentCount + 1 refs", () => { | ||||
|         var view: RenderViewWithFragments = store.allocate(10); | ||||
| 
 | ||||
|         var viewRef: WorkerRenderViewRef = <WorkerRenderViewRef>view.viewRef; | ||||
|         expect(viewRef.refNumber).toEqual(0); | ||||
| 
 | ||||
|         var fragmentRefs: List<WorkerRenderFragmentRef> = | ||||
|             <List<WorkerRenderFragmentRef>>view.fragmentRefs; | ||||
|         expect(fragmentRefs.length).toEqual(10); | ||||
| 
 | ||||
|         for (var i = 0; i < fragmentRefs.length; i++) { | ||||
|           expect(fragmentRefs[i].refNumber).toEqual(i + 1); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
|       it("should not reuse a reference", () => { | ||||
|         store.allocate(10); | ||||
|         var view = store.allocate(0); | ||||
|         var viewRef = <WorkerRenderViewRef>view.viewRef; | ||||
|         expect(viewRef.refNumber).toEqual(11); | ||||
|       }); | ||||
| 
 | ||||
|       it("should be serializable", () => { | ||||
|         var view = store.allocate(1); | ||||
|         expect(store.deserializeViewWithFragments(store.serializeViewWithFragments(view))) | ||||
|             .toEqual(view); | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     describe("on UI", () => { | ||||
|       var store; | ||||
|       beforeEach(() => { store = new RenderViewWithFragmentsStore(false); }); | ||||
|       function createMockRenderViewWithFragments(): RenderViewWithFragments { | ||||
|         var view = new MockRenderViewRef(); | ||||
|         var fragments = ListWrapper.createGrowableSize(20); | ||||
|         for (var i = 0; i < 20; i++) { | ||||
|           fragments[i] = new MockRenderFragmentRef(); | ||||
|         } | ||||
| 
 | ||||
|         return new RenderViewWithFragments(view, fragments); | ||||
|       } | ||||
|       it("should associate views with the correct references", () => { | ||||
|         var renderViewWithFragments = createMockRenderViewWithFragments(); | ||||
| 
 | ||||
|         store.store(renderViewWithFragments, 100); | ||||
|         expect(store.retreive(100)).toBe(renderViewWithFragments.viewRef); | ||||
| 
 | ||||
|         for (var i = 0; i < renderViewWithFragments.fragmentRefs.length; i++) { | ||||
|           expect(store.retreive(101 + i)).toBe(renderViewWithFragments.fragmentRefs[i]); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
|       describe("RenderViewWithFragments", () => { | ||||
|         it("should be serializable", () => { | ||||
|           var renderViewWithFragments = createMockRenderViewWithFragments(); | ||||
|           store.store(renderViewWithFragments, 0); | ||||
| 
 | ||||
|           var deserialized = store.deserializeViewWithFragments( | ||||
|               store.serializeViewWithFragments(renderViewWithFragments)); | ||||
|           expect(deserialized.viewRef).toBe(renderViewWithFragments.viewRef); | ||||
| 
 | ||||
|           expect(deserialized.fragmentRefs.length) | ||||
|               .toEqual(renderViewWithFragments.fragmentRefs.length); | ||||
| 
 | ||||
|           for (var i = 0; i < deserialized.fragmentRefs.length; i++) { | ||||
|             var val = deserialized.fragmentRefs[i]; | ||||
|             expect(val).toBe(renderViewWithFragments.fragmentRefs[i]); | ||||
|           }; | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       describe("RenderViewRef", () => { | ||||
|         it("should be serializable", () => { | ||||
|           var renderViewWithFragments = createMockRenderViewWithFragments(); | ||||
|           store.store(renderViewWithFragments, 0); | ||||
| 
 | ||||
|           var deserialized = store.deserializeRenderViewRef( | ||||
|               store.serializeRenderViewRef(renderViewWithFragments.viewRef)); | ||||
|           expect(deserialized).toBe(renderViewWithFragments.viewRef); | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       describe("RenderFragmentRef", () => { | ||||
|         it("should be serializable", () => { | ||||
|           var renderViewWithFragments = createMockRenderViewWithFragments(); | ||||
|           store.store(renderViewWithFragments, 0); | ||||
| 
 | ||||
|           var serialized = | ||||
|               store.serializeRenderFragmentRef(renderViewWithFragments.fragmentRefs[0]); | ||||
|           var deserialized = store.deserializeRenderFragmentRef(serialized); | ||||
| 
 | ||||
|           expect(deserialized).toBe(renderViewWithFragments.fragmentRefs[0]); | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| class MockRenderViewRef extends RenderViewRef { | ||||
|   constructor() { super(); } | ||||
| } | ||||
| 
 | ||||
| class MockRenderFragmentRef extends RenderFragmentRef { | ||||
|   constructor() { super(); } | ||||
| } | ||||
							
								
								
									
										343
									
								
								modules/angular2/test/web-workers/worker/renderer_spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								modules/angular2/test/web-workers/worker/renderer_spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,343 @@ | ||||
| import { | ||||
|   AsyncTestCompleter, | ||||
|   inject, | ||||
|   describe, | ||||
|   it, | ||||
|   expect, | ||||
|   beforeEach, | ||||
|   createTestInjector, | ||||
|   beforeEachBindings | ||||
| } from "angular2/test_lib"; | ||||
| import {DOM} from 'angular2/src/dom/dom_adapter'; | ||||
| import {DomTestbed, TestRootView, elRef} from '../../render/dom/dom_testbed'; | ||||
| import {bind} from 'angular2/di'; | ||||
| import {WorkerCompiler, WorkerRenderer} from "angular2/src/web-workers/worker/renderer"; | ||||
| import {MessageBroker, UiArguments, FnArg} from "angular2/src/web-workers/worker/broker"; | ||||
| import {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| import {isPresent, isBlank, BaseException, Type} from "angular2/src/facade/lang"; | ||||
| import {MapWrapper, ListWrapper} from "angular2/src/facade/collection"; | ||||
| import { | ||||
|   DirectiveMetadata, | ||||
|   ProtoViewDto, | ||||
|   RenderProtoViewRef, | ||||
|   RenderViewWithFragments, | ||||
|   ViewDefinition, | ||||
|   RenderProtoViewMergeMapping, | ||||
|   RenderViewRef, | ||||
|   RenderFragmentRef | ||||
| } from "angular2/src/render/api"; | ||||
| import { | ||||
|   MessageBus, | ||||
|   MessageBusSource, | ||||
|   MessageBusSink, | ||||
|   SourceListener | ||||
| } from "angular2/src/web-workers/shared/message_bus"; | ||||
| import { | ||||
|   RenderProtoViewRefStore, | ||||
|   WebworkerRenderProtoViewRef | ||||
| } from "angular2/src/web-workers/shared/render_proto_view_ref_store"; | ||||
| import { | ||||
|   RenderViewWithFragmentsStore, | ||||
|   WorkerRenderViewRef | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_view'; | ||||
| import {someComponent} from '../../render/dom/dom_renderer_integration_spec'; | ||||
| import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| 
 | ||||
| export function main() { | ||||
|   function createBroker(workerSerializer: Serializer, uiSerializer: Serializer, tb: DomTestbed, | ||||
|                         uiRenderViewStore: RenderViewWithFragmentsStore, | ||||
|                         workerRenderViewStore: RenderViewWithFragmentsStore): MessageBroker { | ||||
|     // set up the two message buses to pass messages to each other
 | ||||
|     var uiMessageBus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource()); | ||||
|     var workerMessageBus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource()); | ||||
|     uiMessageBus.attachToBus(workerMessageBus); | ||||
|     workerMessageBus.attachToBus(uiMessageBus); | ||||
| 
 | ||||
|     // set up the worker side
 | ||||
|     var broker = new MessageBroker(workerMessageBus, workerSerializer); | ||||
| 
 | ||||
|     // set up the ui side
 | ||||
|     var webWorkerMain = new WebWorkerMain(tb.compiler, tb.renderer, uiRenderViewStore, uiSerializer, | ||||
|                                           new AnchorBasedAppRootUrl()); | ||||
|     webWorkerMain.attachToWorker(uiMessageBus); | ||||
|     return broker; | ||||
|   } | ||||
| 
 | ||||
|   function createWorkerRenderer(workerSerializer: Serializer, uiSerializer: Serializer, | ||||
|                                 tb: DomTestbed, uiRenderViewStore: RenderViewWithFragmentsStore, | ||||
|                                 workerRenderViewStore: RenderViewWithFragmentsStore): | ||||
|       WorkerRenderer { | ||||
|     var broker = | ||||
|         createBroker(workerSerializer, uiSerializer, tb, uiRenderViewStore, workerRenderViewStore); | ||||
|     return new WorkerRenderer(broker, workerRenderViewStore); | ||||
|   } | ||||
| 
 | ||||
|   function createWorkerCompiler(workerSerializer: Serializer, uiSerializer: Serializer, | ||||
|                                 tb: DomTestbed): WorkerCompiler { | ||||
|     var broker = createBroker(workerSerializer, uiSerializer, tb, null, null); | ||||
|     return new WorkerCompiler(broker); | ||||
|   } | ||||
| 
 | ||||
|   describe("Web Worker Compiler", function() { | ||||
|     var workerSerializer: Serializer; | ||||
|     var uiSerializer: Serializer; | ||||
|     var workerRenderProtoViewRefStore: RenderProtoViewRefStore; | ||||
|     var uiRenderProtoViewRefStore: RenderProtoViewRefStore; | ||||
|     var tb: DomTestbed; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       workerRenderProtoViewRefStore = new RenderProtoViewRefStore(true); | ||||
|       uiRenderProtoViewRefStore = new RenderProtoViewRefStore(false); | ||||
|       workerSerializer = createSerializer(workerRenderProtoViewRefStore, null); | ||||
|       uiSerializer = createSerializer(uiRenderProtoViewRefStore, null); | ||||
|       tb = createTestInjector([DomTestbed]).get(DomTestbed); | ||||
|     }); | ||||
| 
 | ||||
|     function resolveWebWorkerRef(ref: RenderProtoViewRef) { | ||||
|       var refNumber = (<WebworkerRenderProtoViewRef>ref).refNumber; | ||||
|       return resolveInternalDomProtoView(uiRenderProtoViewRefStore.deserialize(refNumber)); | ||||
|     } | ||||
| 
 | ||||
|     it('should build the proto view', inject([AsyncTestCompleter], (async) => { | ||||
|          var compiler: WorkerCompiler = createWorkerCompiler(workerSerializer, uiSerializer, tb); | ||||
| 
 | ||||
|          var dirMetadata = DirectiveMetadata.create( | ||||
|              {id: 'id', selector: 'CUSTOM', type: DirectiveMetadata.COMPONENT_TYPE}); | ||||
|          compiler.compileHost(dirMetadata) | ||||
|              .then((protoView) => { | ||||
|                expect(DOM.tagName(DOM.firstChild( | ||||
|                           DOM.content(resolveWebWorkerRef(protoView.render).rootElement)))) | ||||
|                    .toEqual('CUSTOM'); | ||||
|                expect(protoView).not.toBeNull(); | ||||
|                async.done(); | ||||
|              }); | ||||
|        })); | ||||
|   }); | ||||
| 
 | ||||
|   describe("Web Worker Renderer", () => { | ||||
|     beforeEachBindings(() => [DomTestbed]); | ||||
|     var renderer: WorkerRenderer; | ||||
|     var workerSerializer: Serializer; | ||||
|     var workerRenderViewStore: RenderViewWithFragmentsStore; | ||||
|     var uiRenderViewStore: RenderViewWithFragmentsStore; | ||||
|     var uiSerializer: Serializer; | ||||
|     var tb: DomTestbed; | ||||
| 
 | ||||
|     /** | ||||
|      * Seriliazes the given obj with the uiSerializer and then returns the version that | ||||
|      * the worker would deserialize | ||||
|      */ | ||||
|     function serialize(obj: any, type: Type): any { | ||||
|       var serialized = uiSerializer.serialize(obj, type); | ||||
|       return workerSerializer.deserialize(serialized, type); | ||||
|     } | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       workerRenderViewStore = new RenderViewWithFragmentsStore(true); | ||||
|       tb = createTestInjector([DomTestbed]).get(DomTestbed); | ||||
|       uiRenderViewStore = new RenderViewWithFragmentsStore(false); | ||||
|       workerSerializer = createSerializer(new RenderProtoViewRefStore(true), workerRenderViewStore); | ||||
|       uiSerializer = createSerializer(new RenderProtoViewRefStore(false), uiRenderViewStore); | ||||
|       renderer = createWorkerRenderer(workerSerializer, uiSerializer, tb, uiRenderViewStore, | ||||
|                                       workerRenderViewStore); | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
|     it('should create and destroy root host views while using the given elements in place', | ||||
|        inject([AsyncTestCompleter], (async) => { | ||||
|          tb.compiler.compileHost(someComponent) | ||||
|              .then((hostProtoViewDto: any) => { | ||||
|                hostProtoViewDto = serialize(hostProtoViewDto, ProtoViewDto); | ||||
|                var viewWithFragments = | ||||
|                    renderer.createRootHostView(hostProtoViewDto.render, 1, '#root'); | ||||
|                var view = new WorkerTestRootView(viewWithFragments, uiRenderViewStore); | ||||
| 
 | ||||
|                expect(tb.rootEl.parentNode).toBeTruthy(); | ||||
|                expect(view.hostElement).toBe(tb.rootEl); | ||||
| 
 | ||||
|                renderer.detachFragment(viewWithFragments.fragmentRefs[0]); | ||||
|                renderer.destroyView(viewWithFragments.viewRef); | ||||
|                expect(tb.rootEl.parentNode).toBeFalsy(); | ||||
| 
 | ||||
|                async.done(); | ||||
|              }); | ||||
|        })); | ||||
| 
 | ||||
|     it('should update text nodes', inject([AsyncTestCompleter], (async) => { | ||||
|          tb.compileAndMerge( | ||||
|                someComponent, | ||||
|                [ | ||||
|                  new ViewDefinition( | ||||
|                      {componentId: 'someComponent', template: '{{a}}', directives: []}) | ||||
|                ]) | ||||
|              .then((protoViewMergeMappings) => { | ||||
|                protoViewMergeMappings = | ||||
|                    serialize(protoViewMergeMappings, RenderProtoViewMergeMapping); | ||||
|                var rootView = renderer.createView(protoViewMergeMappings.mergedProtoViewRef, 1); | ||||
|                renderer.hydrateView(rootView.viewRef); | ||||
| 
 | ||||
|                renderer.setText(rootView.viewRef, 0, 'hello'); | ||||
|                var view = new WorkerTestRootView(rootView, uiRenderViewStore); | ||||
|                expect(view.hostElement).toHaveText('hello'); | ||||
|                async.done(); | ||||
|              }); | ||||
|        })); | ||||
| 
 | ||||
| 
 | ||||
|     it('should update any element property/attributes/class/style independent of the compilation on the root element and other elements', | ||||
|        inject([AsyncTestCompleter], (async) => { | ||||
|          tb.compileAndMerge(someComponent, | ||||
|                             [ | ||||
|                               new ViewDefinition({ | ||||
|                                 componentId: 'someComponent', | ||||
|                                 template: '<input [title]="y" style="position:absolute">', | ||||
|                                 directives: [] | ||||
|                               }) | ||||
|                             ]) | ||||
|              .then((protoViewMergeMappings) => { | ||||
|                protoViewMergeMappings = | ||||
|                    serialize(protoViewMergeMappings, RenderProtoViewMergeMapping); | ||||
| 
 | ||||
|                var checkSetters = (elr, el) => { | ||||
|                  renderer.setElementProperty(elr, 'tabIndex', 1); | ||||
|                  expect((<HTMLInputElement>el).tabIndex).toEqual(1); | ||||
| 
 | ||||
|                  renderer.setElementClass(elr, 'a', true); | ||||
|                  expect(DOM.hasClass(el, 'a')).toBe(true); | ||||
|                  renderer.setElementClass(elr, 'a', false); | ||||
|                  expect(DOM.hasClass(el, 'a')).toBe(false); | ||||
| 
 | ||||
|                  renderer.setElementStyle(elr, 'width', '10px'); | ||||
|                  expect(DOM.getStyle(el, 'width')).toEqual('10px'); | ||||
|                  renderer.setElementStyle(elr, 'width', null); | ||||
|                  expect(DOM.getStyle(el, 'width')).toEqual(''); | ||||
| 
 | ||||
|                  renderer.setElementAttribute(elr, 'someAttr', 'someValue'); | ||||
|                  expect(DOM.getAttribute(el, 'some-attr')).toEqual('someValue'); | ||||
|                }; | ||||
| 
 | ||||
|                var rootViewWithFragments = | ||||
|                    renderer.createView(protoViewMergeMappings.mergedProtoViewRef, 1); | ||||
|                renderer.hydrateView(rootViewWithFragments.viewRef); | ||||
| 
 | ||||
|                var rootView = new WorkerTestRootView(rootViewWithFragments, uiRenderViewStore); | ||||
|                // root element
 | ||||
|                checkSetters(elRef(rootViewWithFragments.viewRef, 0), rootView.hostElement); | ||||
|                // nested elements
 | ||||
|                checkSetters(elRef(rootViewWithFragments.viewRef, 1), | ||||
|                             DOM.firstChild(rootView.hostElement)); | ||||
| 
 | ||||
|                async.done(); | ||||
|              }); | ||||
|        })); | ||||
| 
 | ||||
|     it('should add and remove empty fragments', inject([AsyncTestCompleter], (async) => { | ||||
|          tb.compileAndMerge(someComponent, | ||||
|                             [ | ||||
|                               new ViewDefinition({ | ||||
|                                 componentId: 'someComponent', | ||||
|                                 template: '<template></template><template></template>', | ||||
|                                 directives: [] | ||||
|                               }) | ||||
|                             ]) | ||||
|              .then((protoViewMergeMappings) => { | ||||
|                protoViewMergeMappings = | ||||
|                    serialize(protoViewMergeMappings, RenderProtoViewMergeMapping); | ||||
|                var rootViewWithFragments = | ||||
|                    renderer.createView(protoViewMergeMappings.mergedProtoViewRef, 3); | ||||
| 
 | ||||
|                var elr = elRef(rootViewWithFragments.viewRef, 1); | ||||
|                var rootView = new WorkerTestRootView(rootViewWithFragments, uiRenderViewStore); | ||||
|                expect(rootView.hostElement).toHaveText(''); | ||||
|                var fragment = rootViewWithFragments.fragmentRefs[1]; | ||||
|                var fragment2 = rootViewWithFragments.fragmentRefs[2]; | ||||
|                renderer.attachFragmentAfterElement(elr, fragment); | ||||
|                renderer.attachFragmentAfterFragment(fragment, fragment2); | ||||
|                renderer.detachFragment(fragment); | ||||
|                renderer.detachFragment(fragment2); | ||||
|                expect(rootView.hostElement).toHaveText(''); | ||||
| 
 | ||||
|                async.done(); | ||||
|              }); | ||||
|        })); | ||||
| 
 | ||||
|     if (DOM.supportsDOMEvents()) { | ||||
|       it('should call actions on the element independent of the compilation', | ||||
|          inject([AsyncTestCompleter], (async) => { | ||||
|            tb.compileAndMerge(someComponent, | ||||
|                               [ | ||||
|                                 new ViewDefinition({ | ||||
|                                   componentId: 'someComponent', | ||||
|                                   template: '<input [title]="y"></input>', | ||||
|                                   directives: [] | ||||
|                                 }) | ||||
|                               ]) | ||||
|                .then((protoViewMergeMappings) => { | ||||
|                  protoViewMergeMappings = | ||||
|                      serialize(protoViewMergeMappings, RenderProtoViewMergeMapping); | ||||
|                  var rootViewWithFragments = | ||||
|                      renderer.createView(protoViewMergeMappings.mergedProtoViewRef, 1); | ||||
|                  var rootView = new WorkerTestRootView(rootViewWithFragments, uiRenderViewStore); | ||||
| 
 | ||||
|                  renderer.invokeElementMethod(elRef(rootViewWithFragments.viewRef, 1), | ||||
|                                               'setAttribute', ['a', 'b']); | ||||
| 
 | ||||
|                  expect(DOM.getAttribute(DOM.childNodes(rootView.hostElement)[0], 'a')) | ||||
|                      .toEqual('b'); | ||||
|                  async.done(); | ||||
|                }); | ||||
|          })); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| class WorkerTestRootView extends TestRootView { | ||||
|   constructor(workerViewWithFragments: RenderViewWithFragments, uiRenderViewStore) { | ||||
|     super(new RenderViewWithFragments( | ||||
|         uiRenderViewStore.retreive( | ||||
|             (<WorkerRenderViewRef>workerViewWithFragments.viewRef).refNumber), | ||||
|         ListWrapper.map(workerViewWithFragments.fragmentRefs, | ||||
|                         (val) => { return uiRenderViewStore.retreive(val.refNumber); }))); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function createSerializer(protoViewRefStore: RenderProtoViewRefStore, | ||||
|                           renderViewStore: RenderViewWithFragmentsStore): Serializer { | ||||
|   var injector = createTestInjector([ | ||||
|     bind(RenderProtoViewRefStore) | ||||
|         .toValue(protoViewRefStore), | ||||
|     bind(RenderViewWithFragmentsStore).toValue(renderViewStore) | ||||
|   ]); | ||||
|   return injector.get(Serializer); | ||||
| } | ||||
| 
 | ||||
| class MockMessageBusSource implements MessageBusSource { | ||||
|   private _listenerStore: Map<int, SourceListener> = new Map<int, SourceListener>(); | ||||
|   private _numListeners: number = 0; | ||||
| 
 | ||||
|   addListener(fn: SourceListener): int { | ||||
|     this._listenerStore.set(++this._numListeners, fn); | ||||
|     return this._numListeners; | ||||
|   } | ||||
| 
 | ||||
|   removeListener(index: int): void { MapWrapper.delete(this._listenerStore, index); } | ||||
| 
 | ||||
|   receive(message: Object): void { | ||||
|     MapWrapper.forEach(this._listenerStore, (fn: SourceListener, key: int) => { fn(message); }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class MockMessageBusSink implements MessageBusSink { | ||||
|   private _sendTo: MockMessageBusSource; | ||||
| 
 | ||||
|   send(message: Object): void { this._sendTo.receive({'data': message}); } | ||||
| 
 | ||||
|   attachToSource(source: MockMessageBusSource) { this._sendTo = source; } | ||||
| } | ||||
| 
 | ||||
| class MockMessageBus implements MessageBus { | ||||
|   constructor(public sink: MockMessageBusSink, public source: MockMessageBusSource) {} | ||||
|   attachToBus(bus: MockMessageBus) { this.sink.attachToSource(bus.source); } | ||||
| } | ||||
| @ -41,7 +41,7 @@ export function main() { | ||||
|                                                  new ViewLoader(null, null, null)); | ||||
|   var compiler = new Compiler(reader, cache, viewResolver, new ComponentUrlMapper(), urlResolver, | ||||
|                               renderCompiler, new ProtoViewFactory(new DynamicChangeDetection()), | ||||
|                               new FakeAppRootUrl()); | ||||
|                               new AppRootUrl("")); | ||||
| 
 | ||||
|   function measureWrapper(func, desc) { | ||||
|     return function() { | ||||
| @ -161,7 +161,3 @@ class BenchmarkComponentNoBindings { | ||||
| }) | ||||
| class BenchmarkComponentWithBindings { | ||||
| } | ||||
| 
 | ||||
| class FakeAppRootUrl extends AppRootUrl { | ||||
|   get value() { return ''; } | ||||
| } | ||||
|  | ||||
							
								
								
									
										1773
									
								
								modules/examples/src/assets/zone-microtask-web-workers.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1773
									
								
								modules/examples/src/assets/zone-microtask-web-workers.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -10,16 +10,16 @@ import "dart:isolate"; | ||||
| main(List<String> args, SendPort replyTo) { | ||||
|   ReceivePort rPort = new ReceivePort(); | ||||
|   WorkerMessageBus bus = new WorkerMessageBus.fromPorts(replyTo, rPort); | ||||
|   bus.source.listen((message) { | ||||
|   bus.source.addListener((message) { | ||||
|     if (identical(message['data']['type'], "echo")) { | ||||
|       bus.sink | ||||
|           .send({"type": "echo_response", "value": message['data']['value']}); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   MessageBroker broker = new MessageBroker(bus); | ||||
|   MessageBroker broker = new MessageBroker(bus, null); | ||||
|   var args = new UiArguments("test", "tester"); | ||||
|   broker.runOnUiThread(args).then((data) { | ||||
|     bus.sink.send({"type": "result", "value": data.value}); | ||||
|   broker.runOnUiThread(args, String).then((data) { | ||||
|     bus.sink.send({"type": "result", "value": data}); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -4,17 +4,18 @@ import { | ||||
|   WorkerMessageBusSink | ||||
| } from "angular2/src/web-workers/worker/application"; | ||||
| import {MessageBroker, UiArguments} from "angular2/src/web-workers/worker/broker"; | ||||
| import {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| 
 | ||||
| export function main() { | ||||
|   var bus = new WorkerMessageBus(new WorkerMessageBusSink(), new WorkerMessageBusSource()); | ||||
|   bus.source.listen((message) => { | ||||
|   bus.source.addListener((message) => { | ||||
|     if (message.data.type === "echo") { | ||||
|       bus.sink.send({type: "echo_response", 'value': message.data.value}); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   var broker = new MessageBroker(bus); | ||||
|   var broker = new MessageBroker(bus, new Serializer(null)); | ||||
|   var args = new UiArguments("test", "tester"); | ||||
|   broker.runOnUiThread(args) | ||||
|       .then((data) => { bus.sink.send({type: "result", value: data.value}); }); | ||||
|   broker.runOnUiThread(args, String) | ||||
|       .then((data: string) => { bus.sink.send({type: "result", value: data}); }); | ||||
| } | ||||
|  | ||||
| @ -12,7 +12,7 @@ main() { | ||||
|       var val = (querySelector("#echo_input") as InputElement).value; | ||||
|       bus.sink.send({'type': 'echo', 'value': val}); | ||||
|     }); | ||||
|     bus.source.listen((message) { | ||||
|     bus.source.addListener((message) { | ||||
|       var data = message['data']; | ||||
|       if (identical(data['type'], "echo_response")) { | ||||
|         querySelector("#echo_result") | ||||
|  | ||||
| @ -13,7 +13,8 @@ document.getElementById("send_echo") | ||||
|       var val = (<HTMLInputElement>document.getElementById("echo_input")).value; | ||||
|       bus.sink.send({type: "echo", value: val}); | ||||
|     }); | ||||
| bus.source.listen((message) => { | ||||
| 
 | ||||
| bus.source.addListener((message) => { | ||||
|   if (message.data.type === "echo_response") { | ||||
|     document.getElementById("echo_result").innerHTML = | ||||
|         `<span class='response'>${message.data.value}</span>`; | ||||
|  | ||||
							
								
								
									
										12
									
								
								modules/examples/src/web_workers/background_index.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								modules/examples/src/web_workers/background_index.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| library examples.src.web_workers.index; | ||||
| 
 | ||||
| import "index_common.dart" show HelloCmp; | ||||
| import "dart:isolate"; | ||||
| import "package:angular2/src/web-workers/worker/application.dart" show bootstrapWebworker; | ||||
| import "package:angular2/src/reflection/reflection_capabilities.dart"; | ||||
| import "package:angular2/src/reflection/reflection.dart"; | ||||
| 
 | ||||
| main(List<String> args, SendPort replyTo){ | ||||
|   reflector.reflectionCapabilities = new ReflectionCapabilities(); | ||||
|   bootstrapWebworker(replyTo, HelloCmp); | ||||
| } | ||||
							
								
								
									
										6
									
								
								modules/examples/src/web_workers/background_index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								modules/examples/src/web_workers/background_index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| import {HelloCmp} from "./index_common"; | ||||
| import {bootstrapWebworker} from "angular2/src/web-workers/worker/application"; | ||||
| 
 | ||||
| export function main() { | ||||
|   bootstrapWebworker(HelloCmp); | ||||
| } | ||||
							
								
								
									
										10
									
								
								modules/examples/src/web_workers/example.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								modules/examples/src/web_workers/example.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| library angular2.examples.web_workers; | ||||
| 
 | ||||
| import "package:angular2/src/web-workers/ui/application.dart" show bootstrap; | ||||
| import "package:angular2/src/reflection/reflection_capabilities.dart"; | ||||
| import "package:angular2/src/reflection/reflection.dart"; | ||||
| 
 | ||||
| main(){ | ||||
|   reflector.reflectionCapabilities = new ReflectionCapabilities(); | ||||
|   bootstrap("background_index.dart"); | ||||
| } | ||||
							
								
								
									
										11
									
								
								modules/examples/src/web_workers/example.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								modules/examples/src/web_workers/example.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| <!doctype html> | ||||
| <html> | ||||
|   <title>Hello Angular 2.0</title> | ||||
| <body> | ||||
|   <hello-app> | ||||
|     Loading... | ||||
|   </hello-app> | ||||
| 
 | ||||
|   $SCRIPTS$ | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										2
									
								
								modules/examples/src/web_workers/example.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								modules/examples/src/web_workers/example.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| import {bootstrap} from "angular2/src/web-workers/ui/application"; | ||||
| bootstrap("loader.js"); | ||||
							
								
								
									
										53
									
								
								modules/examples/src/web_workers/index_common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								modules/examples/src/web_workers/index_common.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| import {ElementRef, Component, Directive, View, Injectable, Renderer} from 'angular2/angular2'; | ||||
| 
 | ||||
| // A service available to the Injector, used by the HelloCmp component.
 | ||||
| @Injectable() | ||||
| class GreetingService { | ||||
|   greeting: string = 'hello'; | ||||
| } | ||||
| 
 | ||||
| // Directives are light-weight. They don't allow new
 | ||||
| // expression contexts (use @Component for those needs).
 | ||||
| @Directive({selector: '[red]'}) | ||||
| class RedDec { | ||||
|   // ElementRef is always injectable and it wraps the element on which the
 | ||||
|   // directive was found by the compiler.
 | ||||
|   constructor(el: ElementRef, renderer: Renderer) { renderer.setElementStyle(el, 'color', 'red'); } | ||||
|   // constructor(renderer: Renderer) {}
 | ||||
| } | ||||
| 
 | ||||
| // Angular 2.0 supports 2 basic types of directives:
 | ||||
| // - Component - the basic building blocks of Angular 2.0 apps. Backed by
 | ||||
| //   ShadowDom.(http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
 | ||||
| // - Directive - add behavior to existing elements.
 | ||||
| 
 | ||||
| // @Component is AtScript syntax to annotate the HelloCmp class as an Angular
 | ||||
| // 2.0 component.
 | ||||
| @Component({ | ||||
|   // The Selector prop tells Angular on which elements to instantiate this
 | ||||
|   // class. The syntax supported is a basic subset of CSS selectors, for example
 | ||||
|   // 'element', '[attr]', [attr=foo]', etc.
 | ||||
|   selector: 'hello-app', | ||||
|   // These are services that would be created if a class in the component's
 | ||||
|   // template tries to inject them.
 | ||||
|   viewInjector: [GreetingService] | ||||
| }) | ||||
| // The template for the component.
 | ||||
| @View({ | ||||
|   // Expressions in the template (like {{greeting}}) are evaluated in the
 | ||||
|   // context of the HelloCmp class below.
 | ||||
|   template: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
 | ||||
|            <button class="changeButton">change greeting</button>`,
 | ||||
|   // All directives used in the template need to be specified. This allows for
 | ||||
|   // modularity (RedDec can only be used in this template)
 | ||||
|   // and better tooling (the template can be invalidated if the attribute is
 | ||||
|   // misspelled).
 | ||||
|   directives: [RedDec] | ||||
| }) | ||||
| export class HelloCmp { | ||||
|   greeting: string; | ||||
| 
 | ||||
|   constructor(service: GreetingService) { this.greeting = service.greeting; } | ||||
| 
 | ||||
|   changeGreeting(): void { this.greeting = 'howdy'; } | ||||
| } | ||||
							
								
								
									
										27
									
								
								modules/examples/src/web_workers/loader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								modules/examples/src/web_workers/loader.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| $SCRIPTS$ | ||||
| 
 | ||||
|     // TODO (jteplitz) Monkey patch this from within angular (#3207)
 | ||||
|     window = { | ||||
|       setTimeout: setTimeout, | ||||
|       Map: Map, | ||||
|       Set: Set, | ||||
|       Array: Array, | ||||
|       Reflect: Reflect, | ||||
|       RegExp: RegExp, | ||||
|       Promise: Promise, | ||||
|       Date: Date | ||||
|     }; | ||||
| assert = function() {} | ||||
| 
 | ||||
| 
 | ||||
|          System.import("examples/src/web_workers/background_index") | ||||
|              .then( | ||||
|                  function(m) { | ||||
|                    console.log("running main"); | ||||
|                    try { | ||||
|                      m.main(); | ||||
|                    } catch (e) { | ||||
|                      console.error(e); | ||||
|                    } | ||||
|                  }, | ||||
|                  function(error) { console.error("error loading background", error); }); | ||||
| @ -1,7 +1,3 @@ | ||||
| importScripts("traceur-runtime.js", | ||||
|     "es6-module-loader-sans-promises.src.js", | ||||
|     "system.src.js", | ||||
|     "extension-register.js", | ||||
|     "extension-cjs.js", | ||||
|     "Reflect.js", | ||||
|     "runtime_paths.js"); | ||||
| importScripts("/examples/src/assets/zone-microtask-web-workers.js", "long-stack-trace-zone.js", | ||||
|               "traceur-runtime.js", "es6-module-loader-sans-promises.src.js", "system.src.js", | ||||
|               "extension-register.js", "extension-cjs.js", "Reflect.js", "runtime_paths.js"); | ||||
|  | ||||
| @ -61,7 +61,8 @@ const kServedPaths = [ | ||||
|   'examples/src/material/progress-linear', | ||||
|   'examples/src/material/radio', | ||||
|   'examples/src/material/switcher', | ||||
|   'examples/src/message_broker' | ||||
|   'examples/src/message_broker', | ||||
|   'examples/src/web_workers' | ||||
| ]; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user