feat(core): speed up view creation via code gen for view factories.
BREAKING CHANGE: - Platform pipes can only contain types and arrays of types, but no bindings any more. - When using transformers, platform pipes need to be specified explicitly in the pubspec.yaml via the new config option `platform_pipes`. - `Compiler.compileInHost` now returns a `HostViewFactoryRef` - Component view is not yet created when component constructor is called. -> use `onInit` lifecycle callback to access the view of a component - `ViewRef#setLocal` has been moved to new type `EmbeddedViewRef` - `internalView` is gone, use `EmbeddedViewRef.rootNodes` to access the root nodes of an embedded view - `renderer.setElementProperty`, `..setElementStyle`, `..setElementAttribute` now take a native element instead of an ElementRef - `Renderer` interface now operates on plain native nodes, instead of `RenderElementRef`s or `RenderViewRef`s Closes #5993
This commit is contained in:
@ -1,75 +1,4 @@
|
||||
import {CONST_EXPR} from "angular2/src/facade/lang";
|
||||
import {OpaqueToken} from "angular2/src/core/di";
|
||||
import {
|
||||
RenderElementRef,
|
||||
RenderViewRef,
|
||||
RenderTemplateCmd,
|
||||
RenderTextCmd,
|
||||
RenderNgContentCmd,
|
||||
RenderBeginElementCmd,
|
||||
RenderBeginComponentCmd,
|
||||
RenderEmbeddedTemplateCmd,
|
||||
RenderCommandVisitor
|
||||
} from "angular2/src/core/render/api";
|
||||
|
||||
export const ON_WEB_WORKER = CONST_EXPR(new OpaqueToken('WebWorker.onWebWorker'));
|
||||
|
||||
export class WebWorkerElementRef implements RenderElementRef {
|
||||
constructor(public renderView: RenderViewRef, public boundElementIndex: number) {}
|
||||
}
|
||||
|
||||
export class WebWorkerTemplateCmd implements RenderTemplateCmd {
|
||||
visit(visitor: RenderCommandVisitor, context: any): any { return null; }
|
||||
}
|
||||
|
||||
export class WebWorkerTextCmd implements RenderTextCmd {
|
||||
constructor(public isBound: boolean, public ngContentIndex: number, public value: string) {}
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitText(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerNgContentCmd implements RenderNgContentCmd {
|
||||
constructor(public index: number, public ngContentIndex: number) {}
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitNgContent(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerBeginElementCmd implements RenderBeginElementCmd {
|
||||
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
||||
public attrNameAndValues: string[], public eventTargetAndNames: string[]) {}
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitBeginElement(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerEndElementCmd implements RenderTemplateCmd {
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitEndElement(context);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerBeginComponentCmd implements RenderBeginComponentCmd {
|
||||
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
||||
public attrNameAndValues: string[], public eventTargetAndNames: string[],
|
||||
public templateId: string) {}
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitBeginComponent(this, context);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerEndComponentCmd implements RenderTemplateCmd {
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitEndComponent(context);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerEmbeddedTemplateCmd implements RenderEmbeddedTemplateCmd {
|
||||
constructor(public isBound: boolean, public ngContentIndex: number, public name: string,
|
||||
public attrNameAndValues: string[], public eventTargetAndNames: string[],
|
||||
public isMerged: boolean, public children: RenderTemplateCmd[]) {}
|
||||
visit(visitor: RenderCommandVisitor, context: any): any {
|
||||
return visitor.visitEmbeddedTemplate(this, context);
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
import {Injectable, Inject} from "angular2/src/core/di";
|
||||
import {RenderProtoViewRef} from "angular2/src/core/render/api";
|
||||
import {ON_WEB_WORKER} 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_WEB_WORKER) onWebworker) { this._onWebworker = onWebworker; }
|
||||
|
||||
allocate(): RenderProtoViewRef {
|
||||
var index = this._nextIndex++;
|
||||
var result = new WebWorkerRenderProtoViewRef(index);
|
||||
this.store(result, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
store(ref: RenderProtoViewRef, index: number): void {
|
||||
this._lookupByProtoView.set(ref, index);
|
||||
this._lookupByIndex.set(index, ref);
|
||||
}
|
||||
|
||||
deserialize(index: number): RenderProtoViewRef {
|
||||
if (index == null) {
|
||||
return null;
|
||||
}
|
||||
return this._lookupByIndex.get(index);
|
||||
}
|
||||
|
||||
serialize(ref: RenderProtoViewRef): number {
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
if (this._onWebworker) {
|
||||
return (<WebWorkerRenderProtoViewRef>ref).refNumber;
|
||||
} else {
|
||||
return this._lookupByProtoView.get(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerRenderProtoViewRef extends RenderProtoViewRef {
|
||||
constructor(public refNumber: number) { super(); }
|
||||
}
|
45
modules/angular2/src/web_workers/shared/render_store.ts
Normal file
45
modules/angular2/src/web_workers/shared/render_store.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import {Injectable} from "angular2/src/core/di";
|
||||
|
||||
@Injectable()
|
||||
export class RenderStore {
|
||||
private _nextIndex: number = 0;
|
||||
private _lookupById: Map<number, any>;
|
||||
private _lookupByObject: Map<any, number>;
|
||||
|
||||
constructor() {
|
||||
this._lookupById = new Map<number, any>();
|
||||
this._lookupByObject = new Map<any, number>();
|
||||
}
|
||||
|
||||
allocateId(): number { return this._nextIndex++; }
|
||||
|
||||
store(obj: any, id: number): void {
|
||||
this._lookupById.set(id, obj);
|
||||
this._lookupByObject.set(obj, id);
|
||||
}
|
||||
|
||||
remove(obj: any): void {
|
||||
var index = this._lookupByObject.get(obj);
|
||||
this._lookupByObject.delete(obj);
|
||||
this._lookupById.delete(index);
|
||||
}
|
||||
|
||||
deserialize(id: number): any {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._lookupById.has(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._lookupById.get(id);
|
||||
}
|
||||
|
||||
serialize(obj: any): number {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
return this._lookupByObject.get(obj);
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
import {Injectable, Inject} from "angular2/src/core/di";
|
||||
import {
|
||||
RenderViewRef,
|
||||
RenderFragmentRef,
|
||||
RenderViewWithFragments
|
||||
} from "angular2/src/core/render/api";
|
||||
import {ON_WEB_WORKER} from "angular2/src/web_workers/shared/api";
|
||||
import {MapWrapper, 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>;
|
||||
private _viewFragments: Map<RenderViewRef, RenderFragmentRef[]>;
|
||||
|
||||
constructor(@Inject(ON_WEB_WORKER) onWebWorker) {
|
||||
this._onWebWorker = onWebWorker;
|
||||
this._lookupByIndex = new Map<number, RenderViewRef | RenderFragmentRef>();
|
||||
this._lookupByView = new Map<RenderViewRef | RenderFragmentRef, number>();
|
||||
this._viewFragments = new Map<RenderViewRef, RenderFragmentRef[]>();
|
||||
}
|
||||
|
||||
allocate(fragmentCount: number): RenderViewWithFragments {
|
||||
var initialIndex = this._nextIndex;
|
||||
|
||||
var viewRef = new WebWorkerRenderViewRef(this._nextIndex++);
|
||||
var fragmentRefs = ListWrapper.createGrowableSize(fragmentCount);
|
||||
|
||||
for (var i = 0; i < fragmentCount; i++) {
|
||||
fragmentRefs[i] = new WebWorkerRenderFragmentRef(this._nextIndex++);
|
||||
}
|
||||
var renderViewWithFragments = new RenderViewWithFragments(viewRef, fragmentRefs);
|
||||
this.store(renderViewWithFragments, initialIndex);
|
||||
return renderViewWithFragments;
|
||||
}
|
||||
|
||||
store(view: RenderViewWithFragments, startIndex: number): void {
|
||||
this._lookupByIndex.set(startIndex, view.viewRef);
|
||||
this._lookupByView.set(view.viewRef, startIndex);
|
||||
startIndex++;
|
||||
|
||||
view.fragmentRefs.forEach(ref => {
|
||||
this._lookupByIndex.set(startIndex, ref);
|
||||
this._lookupByView.set(ref, startIndex);
|
||||
startIndex++;
|
||||
});
|
||||
|
||||
this._viewFragments.set(view.viewRef, view.fragmentRefs);
|
||||
}
|
||||
|
||||
remove(view: RenderViewRef): void {
|
||||
this._removeRef(view);
|
||||
var fragments = this._viewFragments.get(view);
|
||||
fragments.forEach((fragment) => { this._removeRef(fragment); });
|
||||
this._viewFragments.delete(view);
|
||||
}
|
||||
|
||||
private _removeRef(ref: RenderViewRef | RenderFragmentRef) {
|
||||
var index = this._lookupByView.get(ref);
|
||||
this._lookupByView.delete(ref);
|
||||
this._lookupByIndex.delete(index);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return this._retrieve(ref);
|
||||
}
|
||||
|
||||
deserializeRenderFragmentRef(ref: number): RenderFragmentRef {
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._retrieve(ref);
|
||||
}
|
||||
|
||||
private _retrieve(ref: number): RenderViewRef | RenderFragmentRef {
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._lookupByIndex.has(ref)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._lookupByIndex.get(ref);
|
||||
}
|
||||
|
||||
|
||||
private _serializeRenderFragmentOrViewRef(ref: RenderViewRef | RenderFragmentRef): number {
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._onWebWorker) {
|
||||
return (<WebWorkerRenderFragmentRef | WebWorkerRenderViewRef>ref).serialize();
|
||||
} else {
|
||||
return this._lookupByView.get(ref);
|
||||
}
|
||||
}
|
||||
|
||||
serializeViewWithFragments(view: RenderViewWithFragments): {[key: string]: any} {
|
||||
if (view == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._onWebWorker) {
|
||||
return {
|
||||
'viewRef': (<WebWorkerRenderViewRef>view.viewRef).serialize(),
|
||||
'fragmentRefs': view.fragmentRefs.map(val => (<any>val).serialize())
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'viewRef': this._lookupByView.get(view.viewRef),
|
||||
'fragmentRefs': view.fragmentRefs.map(val => this._lookupByView.get(val))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
deserializeViewWithFragments(obj: {[key: string]: any}): RenderViewWithFragments {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var viewRef = this.deserializeRenderViewRef(obj['viewRef']);
|
||||
var fragments = (<any[]>obj['fragmentRefs']).map(val => this.deserializeRenderFragmentRef(val));
|
||||
|
||||
return new RenderViewWithFragments(viewRef, fragments);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerRenderViewRef extends RenderViewRef {
|
||||
constructor(public refNumber: number) { super(); }
|
||||
serialize(): number { return this.refNumber; }
|
||||
|
||||
static deserialize(ref: number): WebWorkerRenderViewRef {
|
||||
return new WebWorkerRenderViewRef(ref);
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerRenderFragmentRef extends RenderFragmentRef {
|
||||
constructor(public refNumber: number) { super(); }
|
||||
|
||||
serialize(): number { return this.refNumber; }
|
||||
|
||||
static deserialize(ref: number): WebWorkerRenderFragmentRef {
|
||||
return new WebWorkerRenderFragmentRef(ref);
|
||||
}
|
||||
}
|
@ -2,36 +2,9 @@ import {Type, isArray, isPresent, serializeEnum, deserializeEnum} from "angular2
|
||||
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
|
||||
import {Map, StringMapWrapper, MapWrapper} from "angular2/src/facade/collection";
|
||||
import {
|
||||
RenderProtoViewRef,
|
||||
RenderViewRef,
|
||||
RenderFragmentRef,
|
||||
RenderElementRef,
|
||||
RenderTemplateCmd,
|
||||
RenderCommandVisitor,
|
||||
RenderTextCmd,
|
||||
RenderNgContentCmd,
|
||||
RenderBeginElementCmd,
|
||||
RenderBeginComponentCmd,
|
||||
RenderEmbeddedTemplateCmd,
|
||||
RenderComponentTemplate
|
||||
} from "angular2/src/core/render/api";
|
||||
import {
|
||||
WebWorkerElementRef,
|
||||
WebWorkerTemplateCmd,
|
||||
WebWorkerTextCmd,
|
||||
WebWorkerNgContentCmd,
|
||||
WebWorkerBeginElementCmd,
|
||||
WebWorkerEndElementCmd,
|
||||
WebWorkerBeginComponentCmd,
|
||||
WebWorkerEndComponentCmd,
|
||||
WebWorkerEmbeddedTemplateCmd
|
||||
} from 'angular2/src/web_workers/shared/api';
|
||||
import {RenderComponentType} from "angular2/src/core/render/api";
|
||||
import {Injectable} from "angular2/src/core/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';
|
||||
import {RenderStore} from 'angular2/src/web_workers/shared/render_store';
|
||||
import {ViewEncapsulation, VIEW_ENCAPSULATION_VALUES} from 'angular2/src/core/metadata/view';
|
||||
|
||||
// PRIMITIVE is any type that does not need to be serialized (string, number, boolean)
|
||||
@ -40,8 +13,7 @@ export const PRIMITIVE: Type = String;
|
||||
|
||||
@Injectable()
|
||||
export class Serializer {
|
||||
constructor(private _protoViewStore: RenderProtoViewRefStore,
|
||||
private _renderViewStore: RenderViewWithFragmentsStore) {}
|
||||
constructor(private _renderStore: RenderStore) {}
|
||||
|
||||
serialize(obj: any, type: any): Object {
|
||||
if (!isPresent(obj)) {
|
||||
@ -53,18 +25,10 @@ export class Serializer {
|
||||
if (type == PRIMITIVE) {
|
||||
return obj;
|
||||
}
|
||||
if (type == RenderProtoViewRef) {
|
||||
return this._protoViewStore.serialize(obj);
|
||||
} else if (type == RenderViewRef) {
|
||||
return this._renderViewStore.serializeRenderViewRef(obj);
|
||||
} else if (type == RenderFragmentRef) {
|
||||
return this._renderViewStore.serializeRenderFragmentRef(obj);
|
||||
} else if (type == WebWorkerElementRef) {
|
||||
return this._serializeWorkerElementRef(obj);
|
||||
} else if (type == WebWorkerTemplateCmd) {
|
||||
return serializeTemplateCmd(obj);
|
||||
} else if (type === RenderComponentTemplate) {
|
||||
return this._serializeRenderTemplate(obj);
|
||||
if (type == RenderStoreObject) {
|
||||
return this._renderStore.serialize(obj);
|
||||
} else if (type === RenderComponentType) {
|
||||
return this._serializeRenderComponentType(obj);
|
||||
} else if (type === ViewEncapsulation) {
|
||||
return serializeEnum(obj);
|
||||
} else {
|
||||
@ -85,18 +49,10 @@ export class Serializer {
|
||||
return map;
|
||||
}
|
||||
|
||||
if (type == RenderProtoViewRef) {
|
||||
return this._protoViewStore.deserialize(map);
|
||||
} else if (type == RenderViewRef) {
|
||||
return this._renderViewStore.deserializeRenderViewRef(map);
|
||||
} else if (type == RenderFragmentRef) {
|
||||
return this._renderViewStore.deserializeRenderFragmentRef(map);
|
||||
} else if (type == WebWorkerElementRef) {
|
||||
return this._deserializeWorkerElementRef(map);
|
||||
} else if (type == WebWorkerTemplateCmd) {
|
||||
return deserializeTemplateCmd(map);
|
||||
} else if (type === RenderComponentTemplate) {
|
||||
return this._deserializeRenderTemplate(map);
|
||||
if (type == RenderStoreObject) {
|
||||
return this._renderStore.deserialize(map);
|
||||
} else if (type === RenderComponentType) {
|
||||
return this._deserializeRenderComponentType(map);
|
||||
} else if (type === ViewEncapsulation) {
|
||||
return VIEW_ENCAPSULATION_VALUES[map];
|
||||
} else {
|
||||
@ -134,114 +90,20 @@ export class Serializer {
|
||||
}
|
||||
}
|
||||
|
||||
allocateRenderViews(fragmentCount: number) { this._renderViewStore.allocate(fragmentCount); }
|
||||
|
||||
private _serializeWorkerElementRef(elementRef: RenderElementRef): {[key: string]: any} {
|
||||
return {
|
||||
'renderView': this.serialize(elementRef.renderView, RenderViewRef),
|
||||
'boundElementIndex': elementRef.boundElementIndex
|
||||
};
|
||||
}
|
||||
|
||||
private _deserializeWorkerElementRef(map: {[key: string]: any}): RenderElementRef {
|
||||
return new WebWorkerElementRef(this.deserialize(map['renderView'], RenderViewRef),
|
||||
map['boundElementIndex']);
|
||||
}
|
||||
|
||||
|
||||
private _serializeRenderTemplate(obj: RenderComponentTemplate): Object {
|
||||
private _serializeRenderComponentType(obj: RenderComponentType): Object {
|
||||
return {
|
||||
'id': obj.id,
|
||||
'shortId': obj.shortId,
|
||||
'encapsulation': this.serialize(obj.encapsulation, ViewEncapsulation),
|
||||
'commands': this.serialize(obj.commands, WebWorkerTemplateCmd),
|
||||
'styles': this.serialize(obj.styles, PRIMITIVE)
|
||||
};
|
||||
}
|
||||
|
||||
private _deserializeRenderTemplate(map: {[key: string]: any}): RenderComponentTemplate {
|
||||
return new RenderComponentTemplate(map['id'], map['shortId'],
|
||||
this.deserialize(map['encapsulation'], ViewEncapsulation),
|
||||
this.deserialize(map['commands'], WebWorkerTemplateCmd),
|
||||
this.deserialize(map['styles'], PRIMITIVE));
|
||||
private _deserializeRenderComponentType(map: {[key: string]: any}): RenderComponentType {
|
||||
return new RenderComponentType(map['id'],
|
||||
this.deserialize(map['encapsulation'], ViewEncapsulation),
|
||||
this.deserialize(map['styles'], PRIMITIVE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function serializeTemplateCmd(cmd: RenderTemplateCmd): Object {
|
||||
return cmd.visit(RENDER_TEMPLATE_CMD_SERIALIZER, null);
|
||||
}
|
||||
|
||||
function deserializeTemplateCmd(data: {[key: string]: any}): RenderTemplateCmd {
|
||||
return RENDER_TEMPLATE_CMD_DESERIALIZERS[data['deserializerIndex']](data);
|
||||
}
|
||||
|
||||
class RenderTemplateCmdSerializer implements RenderCommandVisitor {
|
||||
visitText(cmd: RenderTextCmd, context: any): any {
|
||||
return {
|
||||
'deserializerIndex': 0,
|
||||
'isBound': cmd.isBound,
|
||||
'ngContentIndex': cmd.ngContentIndex,
|
||||
'value': cmd.value
|
||||
};
|
||||
}
|
||||
visitNgContent(cmd: RenderNgContentCmd, context: any): any {
|
||||
return {'deserializerIndex': 1, 'index': cmd.index, 'ngContentIndex': cmd.ngContentIndex};
|
||||
}
|
||||
visitBeginElement(cmd: RenderBeginElementCmd, context: any): any {
|
||||
return {
|
||||
'deserializerIndex': 2,
|
||||
'isBound': cmd.isBound,
|
||||
'ngContentIndex': cmd.ngContentIndex,
|
||||
'name': cmd.name,
|
||||
'attrNameAndValues': cmd.attrNameAndValues,
|
||||
'eventTargetAndNames': cmd.eventTargetAndNames
|
||||
};
|
||||
}
|
||||
visitEndElement(context: any): any { return {'deserializerIndex': 3}; }
|
||||
visitBeginComponent(cmd: RenderBeginComponentCmd, context: any): any {
|
||||
return {
|
||||
'deserializerIndex': 4,
|
||||
'isBound': cmd.isBound,
|
||||
'ngContentIndex': cmd.ngContentIndex,
|
||||
'name': cmd.name,
|
||||
'attrNameAndValues': cmd.attrNameAndValues,
|
||||
'eventTargetAndNames': cmd.eventTargetAndNames,
|
||||
'templateId': cmd.templateId
|
||||
};
|
||||
}
|
||||
visitEndComponent(context: any): any { return {'deserializerIndex': 5}; }
|
||||
visitEmbeddedTemplate(cmd: RenderEmbeddedTemplateCmd, context: any): any {
|
||||
var children = cmd.children.map(child => child.visit(this, null));
|
||||
return {
|
||||
'deserializerIndex': 6,
|
||||
'isBound': cmd.isBound,
|
||||
'ngContentIndex': cmd.ngContentIndex,
|
||||
'name': cmd.name,
|
||||
'attrNameAndValues': cmd.attrNameAndValues,
|
||||
'eventTargetAndNames': cmd.eventTargetAndNames,
|
||||
'isMerged': cmd.isMerged,
|
||||
'children': children
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var RENDER_TEMPLATE_CMD_SERIALIZER = new RenderTemplateCmdSerializer();
|
||||
|
||||
var RENDER_TEMPLATE_CMD_DESERIALIZERS = [
|
||||
(data: {[key: string]: any}) =>
|
||||
new WebWorkerTextCmd(data['isBound'], data['ngContentIndex'], data['value']),
|
||||
(data: {[key: string]: any}) => new WebWorkerNgContentCmd(data['index'], data['ngContentIndex']),
|
||||
(data: {[key: string]: any}) =>
|
||||
new WebWorkerBeginElementCmd(data['isBound'], data['ngContentIndex'], data['name'],
|
||||
data['attrNameAndValues'], data['eventTargetAndNames']),
|
||||
(data: {[key: string]: any}) => new WebWorkerEndElementCmd(),
|
||||
(data: {[key: string]: any}) => new WebWorkerBeginComponentCmd(
|
||||
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
||||
data['eventTargetAndNames'], data['templateId']),
|
||||
(data: {[key: string]: any}) => new WebWorkerEndComponentCmd(),
|
||||
(data: {[key: string]: any}) => new WebWorkerEmbeddedTemplateCmd(
|
||||
data['isBound'], data['ngContentIndex'], data['name'], data['attrNameAndValues'],
|
||||
data['eventTargetAndNames'], data['isMerged'],
|
||||
(<any[]>data['children']).map(childData => deserializeTemplateCmd(childData))),
|
||||
];
|
||||
export class RenderStoreObject {}
|
@ -1,8 +1,4 @@
|
||||
import {
|
||||
RenderViewRef,
|
||||
RenderEventDispatcher,
|
||||
} from 'angular2/src/core/render/api';
|
||||
import {Serializer} from 'angular2/src/web_workers/shared/serializer';
|
||||
import {Serializer, RenderStoreObject} from 'angular2/src/web_workers/shared/serializer';
|
||||
import {
|
||||
serializeMouseEvent,
|
||||
serializeKeyboardEvent,
|
||||
@ -13,15 +9,13 @@ import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
export class EventDispatcher implements RenderEventDispatcher {
|
||||
constructor(private _viewRef: RenderViewRef, private _sink: EventEmitter<any>,
|
||||
private _serializer: Serializer) {}
|
||||
export class EventDispatcher {
|
||||
constructor(private _sink: EventEmitter<any>, private _serializer: Serializer) {}
|
||||
|
||||
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>): boolean {
|
||||
var e = locals.get('$event');
|
||||
dispatchRenderEvent(element: any, eventTarget: string, eventName: string, event: any): boolean {
|
||||
var serializedEvent;
|
||||
// TODO (jteplitz602): support custom events #3350
|
||||
switch (e.type) {
|
||||
switch (event.type) {
|
||||
case "click":
|
||||
case "mouseup":
|
||||
case "mousedown":
|
||||
@ -33,17 +27,17 @@ export class EventDispatcher implements RenderEventDispatcher {
|
||||
case "mouseout":
|
||||
case "mouseover":
|
||||
case "show":
|
||||
serializedEvent = serializeMouseEvent(e);
|
||||
serializedEvent = serializeMouseEvent(event);
|
||||
break;
|
||||
case "keydown":
|
||||
case "keypress":
|
||||
case "keyup":
|
||||
serializedEvent = serializeKeyboardEvent(e);
|
||||
serializedEvent = serializeKeyboardEvent(event);
|
||||
break;
|
||||
case "input":
|
||||
case "change":
|
||||
case "blur":
|
||||
serializedEvent = serializeEventWithTarget(e);
|
||||
serializedEvent = serializeEventWithTarget(event);
|
||||
break;
|
||||
case "abort":
|
||||
case "afterprint":
|
||||
@ -93,19 +87,16 @@ export class EventDispatcher implements RenderEventDispatcher {
|
||||
case "visibilitychange":
|
||||
case "volumechange":
|
||||
case "waiting":
|
||||
serializedEvent = serializeGenericEvent(e);
|
||||
serializedEvent = serializeGenericEvent(event);
|
||||
break;
|
||||
default:
|
||||
throw new BaseException(eventName + " not supported on WebWorkers");
|
||||
}
|
||||
var serializedLocals = StringMapWrapper.create();
|
||||
StringMapWrapper.set(serializedLocals, '$event', serializedEvent);
|
||||
|
||||
ObservableWrapper.callEmit(this._sink, {
|
||||
"viewRef": this._serializer.serialize(this._viewRef, RenderViewRef),
|
||||
"elementIndex": elementIndex,
|
||||
"element": this._serializer.serialize(element, RenderStoreObject),
|
||||
"eventName": eventName,
|
||||
"locals": serializedLocals
|
||||
"eventTarget": eventTarget,
|
||||
"event": serializedEvent
|
||||
});
|
||||
|
||||
// TODO(kegluneq): Eventually, we want the user to indicate from the UI side whether the event
|
||||
|
@ -1,99 +1,172 @@
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
||||
import {Serializer, PRIMITIVE} from 'angular2/src/web_workers/shared/serializer';
|
||||
import {
|
||||
RenderViewRef,
|
||||
RenderFragmentRef,
|
||||
RenderProtoViewRef,
|
||||
Renderer,
|
||||
RenderTemplateCmd,
|
||||
RenderComponentTemplate
|
||||
} from 'angular2/src/core/render/api';
|
||||
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
|
||||
import {Serializer, PRIMITIVE, RenderStoreObject} from 'angular2/src/web_workers/shared/serializer';
|
||||
import {RootRenderer, Renderer, RenderComponentType} from 'angular2/src/core/render/api';
|
||||
import {EVENT_CHANNEL, RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||
import {Type} from 'angular2/src/facade/lang';
|
||||
import {bind} from './bind';
|
||||
import {EventDispatcher} from 'angular2/src/web_workers/ui/event_dispatcher';
|
||||
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 {RenderStore} from 'angular2/src/web_workers/shared/render_store';
|
||||
import {ServiceMessageBrokerFactory} from 'angular2/src/web_workers/shared/service_message_broker';
|
||||
|
||||
@Injectable()
|
||||
export class MessageBasedRenderer {
|
||||
private _eventDispatcher: EventDispatcher;
|
||||
|
||||
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _bus: MessageBus,
|
||||
private _serializer: Serializer,
|
||||
private _renderProtoViewRefStore: RenderProtoViewRefStore,
|
||||
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
|
||||
private _renderer: Renderer) {}
|
||||
private _serializer: Serializer, private _renderStore: RenderStore,
|
||||
private _rootRenderer: RootRenderer) {}
|
||||
|
||||
start(): void {
|
||||
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||
this._bus.initChannel(EVENT_CHANNEL);
|
||||
this._eventDispatcher = new EventDispatcher(this._bus.to(EVENT_CHANNEL), this._serializer);
|
||||
|
||||
broker.registerMethod("registerComponentTemplate", [RenderComponentTemplate],
|
||||
bind(this._renderer.registerComponentTemplate, this._renderer));
|
||||
broker.registerMethod("createProtoView", [PRIMITIVE, WebWorkerTemplateCmd, PRIMITIVE],
|
||||
bind(this._createProtoView, this));
|
||||
broker.registerMethod("createRootHostView",
|
||||
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._createRootHostView, this));
|
||||
broker.registerMethod("createView", [RenderProtoViewRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._createView, this));
|
||||
broker.registerMethod("destroyView", [RenderViewRef], bind(this._destroyView, this));
|
||||
broker.registerMethod("attachFragmentAfterFragment", [RenderFragmentRef, RenderFragmentRef],
|
||||
bind(this._renderer.attachFragmentAfterFragment, this._renderer));
|
||||
broker.registerMethod("attachFragmentAfterElement", [WebWorkerElementRef, RenderFragmentRef],
|
||||
bind(this._renderer.attachFragmentAfterElement, this._renderer));
|
||||
broker.registerMethod("detachFragment", [RenderFragmentRef],
|
||||
bind(this._renderer.detachFragment, this._renderer));
|
||||
broker.registerMethod("hydrateView", [RenderViewRef],
|
||||
bind(this._renderer.hydrateView, this._renderer));
|
||||
broker.registerMethod("dehydrateView", [RenderViewRef],
|
||||
bind(this._renderer.dehydrateView, this._renderer));
|
||||
broker.registerMethod("setText", [RenderViewRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.setText, this._renderer));
|
||||
broker.registerMethod("setElementProperty", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.setElementProperty, this._renderer));
|
||||
broker.registerMethod("setElementAttribute", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.setElementAttribute, this._renderer));
|
||||
broker.registerMethod("setBindingDebugInfo", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.setBindingDebugInfo, this._renderer));
|
||||
broker.registerMethod("setElementClass", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.setElementClass, this._renderer));
|
||||
broker.registerMethod("setElementStyle", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.setElementStyle, this._renderer));
|
||||
broker.registerMethod("invokeElementMethod", [WebWorkerElementRef, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._renderer.invokeElementMethod, this._renderer));
|
||||
broker.registerMethod("setEventDispatcher", [RenderViewRef],
|
||||
bind(this._setEventDispatcher, this));
|
||||
broker.registerMethod("renderComponent", [RenderComponentType, PRIMITIVE],
|
||||
bind(this._renderComponent, this));
|
||||
|
||||
broker.registerMethod("selectRootElement", [RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._selectRootElement, this));
|
||||
broker.registerMethod("createElement",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._createElement, this));
|
||||
broker.registerMethod("createViewRoot", [RenderStoreObject, RenderStoreObject, PRIMITIVE],
|
||||
bind(this._createViewRoot, this));
|
||||
broker.registerMethod("createTemplateAnchor", [RenderStoreObject, RenderStoreObject, PRIMITIVE],
|
||||
bind(this._createTemplateAnchor, this));
|
||||
broker.registerMethod("createText",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._createText, this));
|
||||
broker.registerMethod("projectNodes", [RenderStoreObject, RenderStoreObject, RenderStoreObject],
|
||||
bind(this._projectNodes, this));
|
||||
broker.registerMethod("attachViewAfter",
|
||||
[RenderStoreObject, RenderStoreObject, RenderStoreObject],
|
||||
bind(this._attachViewAfter, this));
|
||||
broker.registerMethod("detachView", [RenderStoreObject, RenderStoreObject],
|
||||
bind(this._detachView, this));
|
||||
broker.registerMethod("destroyView", [RenderStoreObject, RenderStoreObject, RenderStoreObject],
|
||||
bind(this._destroyView, this));
|
||||
broker.registerMethod("setElementProperty",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._setElementProperty, this));
|
||||
broker.registerMethod("setElementAttribute",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._setElementAttribute, this));
|
||||
broker.registerMethod("setBindingDebugInfo",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._setBindingDebugInfo, this));
|
||||
broker.registerMethod("setElementClass",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._setElementClass, this));
|
||||
broker.registerMethod("setElementStyle",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._setElementStyle, this));
|
||||
broker.registerMethod("invokeElementMethod",
|
||||
[RenderStoreObject, RenderStoreObject, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._invokeElementMethod, this));
|
||||
broker.registerMethod("setText", [RenderStoreObject, RenderStoreObject, PRIMITIVE],
|
||||
bind(this._setText, this));
|
||||
broker.registerMethod("listen", [RenderStoreObject, RenderStoreObject, PRIMITIVE],
|
||||
bind(this._listen, this));
|
||||
broker.registerMethod("listenGlobal", [RenderStoreObject, PRIMITIVE, PRIMITIVE, PRIMITIVE],
|
||||
bind(this._listenGlobal, this));
|
||||
broker.registerMethod("listenGlobalDone", [RenderStoreObject, RenderStoreObject],
|
||||
bind(this._listenGlobalDone, this));
|
||||
}
|
||||
|
||||
private _destroyView(viewRef: RenderViewRef): void {
|
||||
this._renderer.destroyView(viewRef);
|
||||
this._renderViewWithFragmentsStore.remove(viewRef);
|
||||
private _renderComponent(renderComponentType: RenderComponentType, rendererId: number) {
|
||||
var renderer = this._rootRenderer.renderComponent(renderComponentType);
|
||||
this._renderStore.store(renderer, rendererId);
|
||||
}
|
||||
|
||||
private _createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[],
|
||||
refIndex: number) {
|
||||
var protoViewRef = this._renderer.createProtoView(componentTemplateId, cmds);
|
||||
this._renderProtoViewRefStore.store(protoViewRef, refIndex);
|
||||
private _selectRootElement(renderer: Renderer, selector: string, elId: number) {
|
||||
this._renderStore.store(renderer.selectRootElement(selector), elId);
|
||||
}
|
||||
|
||||
private _createRootHostView(ref: RenderProtoViewRef, fragmentCount: number, selector: string,
|
||||
startIndex: number) {
|
||||
var renderViewWithFragments = this._renderer.createRootHostView(ref, fragmentCount, selector);
|
||||
this._renderViewWithFragmentsStore.store(renderViewWithFragments, startIndex);
|
||||
private _createElement(renderer: Renderer, parentElement: any, name: string, elId: number) {
|
||||
this._renderStore.store(renderer.createElement(parentElement, name), elId);
|
||||
}
|
||||
|
||||
private _createView(ref: RenderProtoViewRef, fragmentCount: number, startIndex: number) {
|
||||
var renderViewWithFragments = this._renderer.createView(ref, fragmentCount);
|
||||
this._renderViewWithFragmentsStore.store(renderViewWithFragments, startIndex);
|
||||
private _createViewRoot(renderer: Renderer, hostElement: any, elId: number) {
|
||||
var viewRoot = renderer.createViewRoot(hostElement);
|
||||
if (this._renderStore.serialize(hostElement) !== elId) {
|
||||
this._renderStore.store(viewRoot, elId);
|
||||
}
|
||||
}
|
||||
|
||||
private _setEventDispatcher(viewRef: RenderViewRef) {
|
||||
var dispatcher = new EventDispatcher(viewRef, this._bus.to(EVENT_CHANNEL), this._serializer);
|
||||
this._renderer.setEventDispatcher(viewRef, dispatcher);
|
||||
private _createTemplateAnchor(renderer: Renderer, parentElement: any, elId: number) {
|
||||
this._renderStore.store(renderer.createTemplateAnchor(parentElement), elId);
|
||||
}
|
||||
|
||||
private _createText(renderer: Renderer, parentElement: any, value: string, elId: number) {
|
||||
this._renderStore.store(renderer.createText(parentElement, value), elId);
|
||||
}
|
||||
|
||||
private _projectNodes(renderer: Renderer, parentElement: any, nodes: any[]) {
|
||||
renderer.projectNodes(parentElement, nodes);
|
||||
}
|
||||
|
||||
private _attachViewAfter(renderer: Renderer, node: any, viewRootNodes: any[]) {
|
||||
renderer.attachViewAfter(node, viewRootNodes);
|
||||
}
|
||||
|
||||
private _detachView(renderer: Renderer, viewRootNodes: any[]) {
|
||||
renderer.detachView(viewRootNodes);
|
||||
}
|
||||
|
||||
private _destroyView(renderer: Renderer, hostElement: any, viewAllNodes: any[]) {
|
||||
renderer.destroyView(hostElement, viewAllNodes);
|
||||
for (var i = 0; i < viewAllNodes.length; i++) {
|
||||
this._renderStore.remove(viewAllNodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private _setElementProperty(renderer: Renderer, renderElement: any, propertyName: string,
|
||||
propertyValue: any) {
|
||||
renderer.setElementProperty(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
private _setElementAttribute(renderer: Renderer, renderElement: any, attributeName: string,
|
||||
attributeValue: string) {
|
||||
renderer.setElementAttribute(renderElement, attributeName, attributeValue);
|
||||
}
|
||||
|
||||
private _setBindingDebugInfo(renderer: Renderer, renderElement: any, propertyName: string,
|
||||
propertyValue: string) {
|
||||
renderer.setBindingDebugInfo(renderElement, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
private _setElementClass(renderer: Renderer, renderElement: any, className: string,
|
||||
isAdd: boolean) {
|
||||
renderer.setElementClass(renderElement, className, isAdd);
|
||||
}
|
||||
|
||||
private _setElementStyle(renderer: Renderer, renderElement: any, styleName: string,
|
||||
styleValue: string) {
|
||||
renderer.setElementStyle(renderElement, styleName, styleValue);
|
||||
}
|
||||
|
||||
private _invokeElementMethod(renderer: Renderer, renderElement: any, methodName: string,
|
||||
args: any[]) {
|
||||
renderer.invokeElementMethod(renderElement, methodName, args);
|
||||
}
|
||||
|
||||
private _setText(renderer: Renderer, renderNode: any, text: string) {
|
||||
renderer.setText(renderNode, text);
|
||||
}
|
||||
|
||||
private _listen(renderer: Renderer, renderElement: any, eventName: string) {
|
||||
renderer.listen(renderElement, eventName, (event) => this._eventDispatcher.dispatchRenderEvent(
|
||||
renderElement, null, eventName, event));
|
||||
}
|
||||
|
||||
private _listenGlobal(renderer: Renderer, eventTarget: string, eventName: string,
|
||||
unlistenId: number) {
|
||||
var unregisterCallback = renderer.listenGlobal(
|
||||
eventTarget, eventName,
|
||||
(event) => this._eventDispatcher.dispatchRenderEvent(null, eventTarget, eventName, event));
|
||||
this._renderStore.store(unregisterCallback, unlistenId);
|
||||
}
|
||||
|
||||
private _listenGlobalDone(renderer: Renderer, unlistenCallback: Function) { unlistenCallback(); }
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
import {Injectable} from 'angular2/src/core/di';
|
||||
import {Map, MapWrapper} from 'angular2/src/facade/collection';
|
||||
import {RenderViewRef, RenderEventDispatcher} from 'angular2/src/core/render/api';
|
||||
import {Serializer} from 'angular2/src/web_workers/shared/serializer';
|
||||
import {EVENT_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {deserializeGenericEvent} from './event_deserializer';
|
||||
|
||||
@Injectable()
|
||||
export class WebWorkerEventDispatcher {
|
||||
private _eventDispatchRegistry: Map<RenderViewRef, RenderEventDispatcher> =
|
||||
new Map<RenderViewRef, RenderEventDispatcher>();
|
||||
|
||||
constructor(bus: MessageBus, private _serializer: Serializer) {
|
||||
bus.initChannel(EVENT_CHANNEL);
|
||||
var source = bus.from(EVENT_CHANNEL);
|
||||
ObservableWrapper.subscribe(
|
||||
source, (message) => this._dispatchEvent(new RenderEventData(message, _serializer)));
|
||||
}
|
||||
|
||||
|
||||
private _dispatchEvent(eventData: RenderEventData): void {
|
||||
var dispatcher = this._eventDispatchRegistry.get(eventData.viewRef);
|
||||
eventData.locals['$event'] = deserializeGenericEvent(eventData.locals['$event']);
|
||||
dispatcher.dispatchRenderEvent(eventData.elementIndex, eventData.eventName, eventData.locals);
|
||||
}
|
||||
|
||||
registerEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher): void {
|
||||
this._eventDispatchRegistry.set(viewRef, dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RenderEventData {
|
||||
viewRef: RenderViewRef;
|
||||
elementIndex: number;
|
||||
eventName: string;
|
||||
locals: Map<string, any>;
|
||||
|
||||
constructor(message: {[key: string]: any}, serializer: Serializer) {
|
||||
this.viewRef = serializer.deserialize(message['viewRef'], RenderViewRef);
|
||||
this.elementIndex = message['elementIndex'];
|
||||
this.eventName = message['eventName'];
|
||||
this.locals = MapWrapper.createFromStringMap(message['locals']);
|
||||
}
|
||||
}
|
@ -1,269 +1,270 @@
|
||||
import {
|
||||
Renderer,
|
||||
RenderProtoViewRef,
|
||||
RenderViewRef,
|
||||
RenderElementRef,
|
||||
RenderEventDispatcher,
|
||||
RenderViewWithFragments,
|
||||
RenderFragmentRef,
|
||||
RenderTemplateCmd,
|
||||
RenderComponentTemplate
|
||||
} from 'angular2/src/core/render/api';
|
||||
import {Renderer, RootRenderer, RenderComponentType} from 'angular2/src/core/render/api';
|
||||
import {
|
||||
ClientMessageBroker,
|
||||
ClientMessageBrokerFactory,
|
||||
FnArg,
|
||||
UiArguments
|
||||
} from "angular2/src/web_workers/shared/client_message_broker";
|
||||
import {isPresent, print} from "angular2/src/facade/lang";
|
||||
import {isPresent, isBlank, print} from "angular2/src/facade/lang";
|
||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {Injectable} from "angular2/src/core/di";
|
||||
import {RenderProtoViewRefStore} from 'angular2/src/web_workers/shared/render_proto_view_ref_store';
|
||||
import {
|
||||
RenderViewWithFragmentsStore,
|
||||
WebWorkerRenderViewRef
|
||||
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
|
||||
import {WebWorkerElementRef, WebWorkerTemplateCmd} from 'angular2/src/web_workers/shared/api';
|
||||
import {RenderStore} from 'angular2/src/web_workers/shared/render_store';
|
||||
import {RENDERER_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||
import {WebWorkerEventDispatcher} from 'angular2/src/web_workers/worker/event_dispatcher';
|
||||
import {Serializer, RenderStoreObject} from 'angular2/src/web_workers/shared/serializer';
|
||||
import {EVENT_CHANNEL} from 'angular2/src/web_workers/shared/messaging_api';
|
||||
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
|
||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
|
||||
import {deserializeGenericEvent} from './event_deserializer';
|
||||
|
||||
@Injectable()
|
||||
export class WebWorkerRenderer implements Renderer {
|
||||
export class WebWorkerRootRenderer implements RootRenderer {
|
||||
private _messageBroker;
|
||||
constructor(messageBrokerFactory: ClientMessageBrokerFactory,
|
||||
private _renderProtoViewRefStore: RenderProtoViewRefStore,
|
||||
private _renderViewStore: RenderViewWithFragmentsStore,
|
||||
private _eventDispatcher: WebWorkerEventDispatcher) {
|
||||
public globalEvents: NamedEventEmitter = new NamedEventEmitter();
|
||||
private _componentRenderers: Map<string, WebWorkerRenderer> =
|
||||
new Map<string, WebWorkerRenderer>();
|
||||
|
||||
constructor(messageBrokerFactory: ClientMessageBrokerFactory, bus: MessageBus,
|
||||
private _serializer: Serializer, private _renderStore: RenderStore) {
|
||||
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||
bus.initChannel(EVENT_CHANNEL);
|
||||
var source = bus.from(EVENT_CHANNEL);
|
||||
ObservableWrapper.subscribe(source, (message) => this._dispatchEvent(message));
|
||||
}
|
||||
|
||||
registerComponentTemplate(template: RenderComponentTemplate) {
|
||||
var fnArgs = [new FnArg(template, RenderComponentTemplate)];
|
||||
var args = new UiArguments("registerComponentTemplate", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
createProtoView(componentTemplateId: string, cmds: RenderTemplateCmd[]): RenderProtoViewRef {
|
||||
var renderProtoViewRef = this._renderProtoViewRefStore.allocate();
|
||||
|
||||
var fnArgs: FnArg[] = [
|
||||
new FnArg(componentTemplateId, null),
|
||||
new FnArg(cmds, WebWorkerTemplateCmd),
|
||||
new FnArg(renderProtoViewRef, RenderProtoViewRef)
|
||||
];
|
||||
var args: UiArguments = new UiArguments("createProtoView", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
return renderProtoViewRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = (<WebWorkerRenderViewRef>(renderViewWithFragments.viewRef)).refNumber;
|
||||
var fnArgs: 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";
|
||||
private _dispatchEvent(message: {[key: string]: any}): void {
|
||||
var eventName = message['eventName'];
|
||||
var target = message['eventTarget'];
|
||||
var event = deserializeGenericEvent(message['event']);
|
||||
if (isPresent(target)) {
|
||||
this.globalEvents.dispatchEvent(eventNameWithTarget(target, eventName), event);
|
||||
} else {
|
||||
var element =
|
||||
<WebWorkerRenderNode>this._serializer.deserialize(message['element'], RenderStoreObject);
|
||||
element.events.dispatchEvent(eventName, event);
|
||||
}
|
||||
fnArgs.push(new FnArg(startIndex, null));
|
||||
|
||||
var args = new UiArguments(method, fnArgs);
|
||||
this._messageBroker.runOnService(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("destroyView", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
this._renderViewStore.remove(viewRef);
|
||||
renderComponent(componentType: RenderComponentType): Renderer {
|
||||
var result = this._componentRenderers.get(componentType.id);
|
||||
if (isBlank(result)) {
|
||||
result = new WebWorkerRenderer(this, componentType);
|
||||
this._componentRenderers.set(componentType.id, result);
|
||||
var id = this._renderStore.allocateId();
|
||||
this._renderStore.store(result, id);
|
||||
this.runOnService('renderComponent', [
|
||||
new FnArg(componentType, RenderComponentType),
|
||||
new FnArg(result, RenderStoreObject),
|
||||
]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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("attachFragmentAfterFragment", fnArgs);
|
||||
runOnService(fnName: string, fnArgs: FnArg[]) {
|
||||
var args = new UiArguments(fnName, fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a fragment after an element.
|
||||
*/
|
||||
attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) {
|
||||
var fnArgs =
|
||||
[new FnArg(elementRef, WebWorkerElementRef), new FnArg(fragmentRef, RenderFragmentRef)];
|
||||
var args = new UiArguments("attachFragmentAfterElement", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
allocateNode(): WebWorkerRenderNode {
|
||||
var result = new WebWorkerRenderNode();
|
||||
var id = this._renderStore.allocateId();
|
||||
this._renderStore.store(result, id);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches a fragment.
|
||||
*/
|
||||
detachFragment(fragmentRef: RenderFragmentRef) {
|
||||
var fnArgs = [new FnArg(fragmentRef, RenderFragmentRef)];
|
||||
var args = new UiArguments("detachFragment", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
allocateId(): number { return this._renderStore.allocateId(); }
|
||||
|
||||
/**
|
||||
* 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("hydrateView", fnArgs);
|
||||
this._messageBroker.runOnService(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("dehydrateView", fnArgs);
|
||||
this._messageBroker.runOnService(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, WebWorkerElementRef),
|
||||
new FnArg(propertyName, null),
|
||||
new FnArg(propertyValue, null)
|
||||
];
|
||||
var args = new UiArguments("setElementProperty", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute on an element.
|
||||
*/
|
||||
setElementAttribute(location: RenderElementRef, attributeName: string, attributeValue: string) {
|
||||
var fnArgs = [
|
||||
new FnArg(location, WebWorkerElementRef),
|
||||
new FnArg(attributeName, null),
|
||||
new FnArg(attributeValue, null)
|
||||
];
|
||||
var args = new UiArguments("setElementAttribute", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
setBindingDebugInfo(location: RenderElementRef, propertyName: string,
|
||||
propertyValue: string): void {
|
||||
var fnArgs = [
|
||||
new FnArg(location, WebWorkerElementRef),
|
||||
new FnArg(propertyName, null),
|
||||
new FnArg(propertyValue, null)
|
||||
];
|
||||
var args = new UiArguments("setBindingDebugInfo", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a class on an element.
|
||||
*/
|
||||
setElementClass(location: RenderElementRef, className: string, isAdd: boolean) {
|
||||
var fnArgs = [
|
||||
new FnArg(location, WebWorkerElementRef),
|
||||
new FnArg(className, null),
|
||||
new FnArg(isAdd, null)
|
||||
];
|
||||
var args = new UiArguments("setElementClass", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a style on an element.
|
||||
*/
|
||||
setElementStyle(location: RenderElementRef, styleName: string, styleValue: string) {
|
||||
var fnArgs = [
|
||||
new FnArg(location, WebWorkerElementRef),
|
||||
new FnArg(styleName, null),
|
||||
new FnArg(styleValue, null)
|
||||
];
|
||||
var args = new UiArguments("setElementStyle", fnArgs);
|
||||
this._messageBroker.runOnService(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: any[]) {
|
||||
var fnArgs = [
|
||||
new FnArg(location, WebWorkerElementRef),
|
||||
new FnArg(methodName, null),
|
||||
new FnArg(args, null)
|
||||
];
|
||||
var uiArgs = new UiArguments("invokeElementMethod", fnArgs);
|
||||
this._messageBroker.runOnService(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("setText", fnArgs);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dispatcher for all events of the given view
|
||||
*/
|
||||
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) {
|
||||
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
||||
var args = new UiArguments("setEventDispatcher", fnArgs);
|
||||
this._eventDispatcher.registerEventDispatcher(viewRef, dispatcher);
|
||||
this._messageBroker.runOnService(args, null);
|
||||
destroyNodes(nodes: any[]) {
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
this._renderStore.remove(nodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class WebWorkerRenderer implements Renderer, RenderStoreObject {
|
||||
constructor(private _rootRenderer: WebWorkerRootRenderer,
|
||||
private _componentType: RenderComponentType) {}
|
||||
|
||||
renderComponent(componentType: RenderComponentType): Renderer {
|
||||
return this._rootRenderer.renderComponent(componentType);
|
||||
}
|
||||
|
||||
private _runOnService(fnName: string, fnArgs: FnArg[]) {
|
||||
var fnArgsWithRenderer = [new FnArg(this, RenderStoreObject)].concat(fnArgs);
|
||||
this._rootRenderer.runOnService(fnName, fnArgsWithRenderer);
|
||||
}
|
||||
|
||||
selectRootElement(selector: string): any {
|
||||
var node = this._rootRenderer.allocateNode();
|
||||
this._runOnService('selectRootElement',
|
||||
[new FnArg(selector, null), new FnArg(node, RenderStoreObject)]);
|
||||
return node;
|
||||
}
|
||||
|
||||
createElement(parentElement: any, name: string): any {
|
||||
var node = this._rootRenderer.allocateNode();
|
||||
this._runOnService('createElement', [
|
||||
new FnArg(parentElement, RenderStoreObject),
|
||||
new FnArg(name, null),
|
||||
new FnArg(node, RenderStoreObject)
|
||||
]);
|
||||
return node;
|
||||
}
|
||||
|
||||
createViewRoot(hostElement: any): any {
|
||||
var viewRoot = this._componentType.encapsulation === ViewEncapsulation.Native ?
|
||||
this._rootRenderer.allocateNode() :
|
||||
hostElement;
|
||||
this._runOnService(
|
||||
'createViewRoot',
|
||||
[new FnArg(hostElement, RenderStoreObject), new FnArg(viewRoot, RenderStoreObject)]);
|
||||
return viewRoot;
|
||||
}
|
||||
|
||||
createTemplateAnchor(parentElement: any): any {
|
||||
var node = this._rootRenderer.allocateNode();
|
||||
this._runOnService(
|
||||
'createTemplateAnchor',
|
||||
[new FnArg(parentElement, RenderStoreObject), new FnArg(node, RenderStoreObject)]);
|
||||
return node;
|
||||
}
|
||||
|
||||
createText(parentElement: any, value: string): any {
|
||||
var node = this._rootRenderer.allocateNode();
|
||||
this._runOnService('createText', [
|
||||
new FnArg(parentElement, RenderStoreObject),
|
||||
new FnArg(value, null),
|
||||
new FnArg(node, RenderStoreObject)
|
||||
]);
|
||||
return node;
|
||||
}
|
||||
|
||||
projectNodes(parentElement: any, nodes: any[]) {
|
||||
this._runOnService(
|
||||
'projectNodes',
|
||||
[new FnArg(parentElement, RenderStoreObject), new FnArg(nodes, RenderStoreObject)]);
|
||||
}
|
||||
|
||||
attachViewAfter(node: any, viewRootNodes: any[]) {
|
||||
this._runOnService(
|
||||
'attachViewAfter',
|
||||
[new FnArg(node, RenderStoreObject), new FnArg(viewRootNodes, RenderStoreObject)]);
|
||||
}
|
||||
|
||||
detachView(viewRootNodes: any[]) {
|
||||
this._runOnService('detachView', [new FnArg(viewRootNodes, RenderStoreObject)]);
|
||||
}
|
||||
|
||||
destroyView(hostElement: any, viewAllNodes: any[]) {
|
||||
this._runOnService(
|
||||
'destroyView',
|
||||
[new FnArg(hostElement, RenderStoreObject), new FnArg(viewAllNodes, RenderStoreObject)]);
|
||||
this._rootRenderer.destroyNodes(viewAllNodes);
|
||||
}
|
||||
|
||||
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
|
||||
this._runOnService('setElementProperty', [
|
||||
new FnArg(renderElement, RenderStoreObject),
|
||||
new FnArg(propertyName, null),
|
||||
new FnArg(propertyValue, null)
|
||||
]);
|
||||
}
|
||||
|
||||
setElementAttribute(renderElement: any, attributeName: string, attributeValue: string) {
|
||||
this._runOnService('setElementAttribute', [
|
||||
new FnArg(renderElement, RenderStoreObject),
|
||||
new FnArg(attributeName, null),
|
||||
new FnArg(attributeValue, null)
|
||||
]);
|
||||
}
|
||||
|
||||
setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string) {
|
||||
this._runOnService('setBindingDebugInfo', [
|
||||
new FnArg(renderElement, RenderStoreObject),
|
||||
new FnArg(propertyName, null),
|
||||
new FnArg(propertyValue, null)
|
||||
]);
|
||||
}
|
||||
|
||||
setElementClass(renderElement: any, className: string, isAdd: boolean) {
|
||||
this._runOnService('setElementClass', [
|
||||
new FnArg(renderElement, RenderStoreObject),
|
||||
new FnArg(className, null),
|
||||
new FnArg(isAdd, null)
|
||||
]);
|
||||
}
|
||||
|
||||
setElementStyle(renderElement: any, styleName: string, styleValue: string) {
|
||||
this._runOnService('setElementStyle', [
|
||||
new FnArg(renderElement, RenderStoreObject),
|
||||
new FnArg(styleName, null),
|
||||
new FnArg(styleValue, null)
|
||||
]);
|
||||
}
|
||||
|
||||
invokeElementMethod(renderElement: any, methodName: string, args: any[]) {
|
||||
this._runOnService('invokeElementMethod', [
|
||||
new FnArg(renderElement, RenderStoreObject),
|
||||
new FnArg(methodName, null),
|
||||
new FnArg(args, null)
|
||||
]);
|
||||
}
|
||||
|
||||
setText(renderNode: any, text: string) {
|
||||
this._runOnService('setText',
|
||||
[new FnArg(renderNode, RenderStoreObject), new FnArg(text, null)]);
|
||||
}
|
||||
|
||||
listen(renderElement: WebWorkerRenderNode, name: string, callback: Function) {
|
||||
renderElement.events.listen(name, callback);
|
||||
this._runOnService('listen',
|
||||
[new FnArg(renderElement, RenderStoreObject), new FnArg(name, null)]);
|
||||
}
|
||||
|
||||
listenGlobal(target: string, name: string, callback: Function): Function {
|
||||
this._rootRenderer.globalEvents.listen(eventNameWithTarget(target, name), callback);
|
||||
var unlistenCallbackId = this._rootRenderer.allocateId();
|
||||
this._runOnService(
|
||||
'listenGlobal',
|
||||
[new FnArg(target, null), new FnArg(name, null), new FnArg(unlistenCallbackId, null)]);
|
||||
return () => {
|
||||
this._rootRenderer.globalEvents.unlisten(eventNameWithTarget(target, name), callback);
|
||||
this._runOnService('listenGlobalDone', [new FnArg(unlistenCallbackId, null)]);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class NamedEventEmitter {
|
||||
private _listeners: Map<string, Function[]>;
|
||||
|
||||
private _getListeners(eventName: string): Function[] {
|
||||
if (isBlank(this._listeners)) {
|
||||
this._listeners = new Map<string, Function[]>();
|
||||
}
|
||||
var listeners = this._listeners.get(eventName);
|
||||
if (isBlank(listeners)) {
|
||||
listeners = [];
|
||||
this._listeners.set(eventName, listeners);
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
listen(eventName: string, callback: Function) { this._getListeners(eventName).push(callback); }
|
||||
|
||||
unlisten(eventName: string, callback: Function) {
|
||||
ListWrapper.remove(this._getListeners(eventName), callback);
|
||||
}
|
||||
|
||||
dispatchEvent(eventName: string, event: any) {
|
||||
var listeners = this._getListeners(eventName);
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
listeners[i](event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eventNameWithTarget(target: string, eventName: string): string {
|
||||
return `${target}:${eventName}`;
|
||||
}
|
||||
|
||||
export class WebWorkerRenderNode { events: NamedEventEmitter = new NamedEventEmitter(); }
|
||||
|
Reference in New Issue
Block a user