parent
8e960d4052
commit
7b834e02ec
|
@ -12,20 +12,22 @@ export class RenderViewWithFragmentsStore {
|
||||||
|
|
||||||
constructor(@Inject(ON_WEBWORKER) onWebWorker) {
|
constructor(@Inject(ON_WEBWORKER) onWebWorker) {
|
||||||
this._onWebWorker = onWebWorker;
|
this._onWebWorker = onWebWorker;
|
||||||
if (!onWebWorker) {
|
this._lookupByIndex = new Map<number, RenderViewRef | RenderFragmentRef>();
|
||||||
this._lookupByIndex = new Map<number, RenderViewRef | RenderFragmentRef>();
|
this._lookupByView = new Map<RenderViewRef | RenderFragmentRef, number>();
|
||||||
this._lookupByView = new Map<RenderViewRef | RenderFragmentRef, number>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allocate(fragmentCount: number): RenderViewWithFragments {
|
allocate(fragmentCount: number): RenderViewWithFragments {
|
||||||
|
var initialIndex = this._nextIndex;
|
||||||
|
|
||||||
var viewRef = new WorkerRenderViewRef(this._nextIndex++);
|
var viewRef = new WorkerRenderViewRef(this._nextIndex++);
|
||||||
var fragmentRefs = ListWrapper.createGrowableSize(fragmentCount);
|
var fragmentRefs = ListWrapper.createGrowableSize(fragmentCount);
|
||||||
|
|
||||||
for (var i = 0; i < fragmentCount; i++) {
|
for (var i = 0; i < fragmentCount; i++) {
|
||||||
fragmentRefs[i] = new WorkerRenderFragmentRef(this._nextIndex++);
|
fragmentRefs[i] = new WorkerRenderFragmentRef(this._nextIndex++);
|
||||||
}
|
}
|
||||||
return new RenderViewWithFragments(viewRef, fragmentRefs);
|
var renderViewWithFragments = new RenderViewWithFragments(viewRef, fragmentRefs);
|
||||||
|
this.store(renderViewWithFragments, initialIndex);
|
||||||
|
return renderViewWithFragments;
|
||||||
}
|
}
|
||||||
|
|
||||||
store(view: RenderViewWithFragments, startIndex: number) {
|
store(view: RenderViewWithFragments, startIndex: number) {
|
||||||
|
@ -60,11 +62,7 @@ export class RenderViewWithFragmentsStore {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._onWebWorker) {
|
return this.retreive(ref);
|
||||||
return WorkerRenderViewRef.deserialize(ref);
|
|
||||||
} else {
|
|
||||||
return this.retreive(ref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializeRenderFragmentRef(ref: number): RenderFragmentRef {
|
deserializeRenderFragmentRef(ref: number): RenderFragmentRef {
|
||||||
|
@ -72,11 +70,7 @@ export class RenderViewWithFragmentsStore {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._onWebWorker) {
|
return this.retreive(ref);
|
||||||
return WorkerRenderFragmentRef.deserialize(ref);
|
|
||||||
} else {
|
|
||||||
return this.retreive(ref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _serializeRenderFragmentOrViewRef(ref: RenderViewRef | RenderFragmentRef): number {
|
private _serializeRenderFragmentOrViewRef(ref: RenderViewRef | RenderFragmentRef): number {
|
||||||
|
@ -114,20 +108,11 @@ export class RenderViewWithFragmentsStore {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewRef: RenderViewRef | RenderFragmentRef;
|
var viewRef = this.deserializeRenderViewRef(obj['viewRef']);
|
||||||
var fragments: List<RenderViewRef | RenderFragmentRef>;
|
var fragments =
|
||||||
if (this._onWebWorker) {
|
ListWrapper.map(obj['fragmentRefs'], (val) => this.deserializeRenderFragmentRef(val));
|
||||||
viewRef = WorkerRenderViewRef.deserialize(obj['viewRef']);
|
|
||||||
fragments =
|
|
||||||
ListWrapper.map(obj['fragmentRefs'], (val) => WorkerRenderFragmentRef.deserialize(val));
|
|
||||||
|
|
||||||
return new RenderViewWithFragments(viewRef, fragments);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
import {Type, isArray, isPresent, serializeEnum, deserializeEnum} from "angular2/src/facade/lang";
|
import {
|
||||||
import {List, ListWrapper, Map, StringMapWrapper, MapWrapper} from "angular2/src/facade/collection";
|
Type,
|
||||||
|
isArray,
|
||||||
|
isPresent,
|
||||||
|
serializeEnum,
|
||||||
|
deserializeEnum,
|
||||||
|
BaseException
|
||||||
|
} from "angular2/src/facade/lang";
|
||||||
|
import {
|
||||||
|
List,
|
||||||
|
ListWrapper,
|
||||||
|
Map,
|
||||||
|
StringMap,
|
||||||
|
StringMapWrapper,
|
||||||
|
MapWrapper
|
||||||
|
} from "angular2/src/facade/collection";
|
||||||
import {
|
import {
|
||||||
ProtoViewDto,
|
ProtoViewDto,
|
||||||
DirectiveMetadata,
|
DirectiveMetadata,
|
||||||
|
@ -13,7 +27,8 @@ import {
|
||||||
RenderViewRef,
|
RenderViewRef,
|
||||||
RenderFragmentRef,
|
RenderFragmentRef,
|
||||||
RenderElementRef,
|
RenderElementRef,
|
||||||
ViewType
|
ViewType,
|
||||||
|
ViewEncapsulation
|
||||||
} from "angular2/src/render/api";
|
} from "angular2/src/render/api";
|
||||||
import {WorkerElementRef} from 'angular2/src/web-workers/shared/api';
|
import {WorkerElementRef} from 'angular2/src/web-workers/shared/api';
|
||||||
import {AST, ASTWithSource} from 'angular2/src/change_detection/change_detection';
|
import {AST, ASTWithSource} from 'angular2/src/change_detection/change_detection';
|
||||||
|
@ -30,11 +45,18 @@ export class Serializer {
|
||||||
constructor(private _parser: Parser, private _protoViewStore: RenderProtoViewRefStore,
|
constructor(private _parser: Parser, private _protoViewStore: RenderProtoViewRefStore,
|
||||||
private _renderViewStore: RenderViewWithFragmentsStore) {
|
private _renderViewStore: RenderViewWithFragmentsStore) {
|
||||||
this._enumRegistry = new Map<any, Map<int, any>>();
|
this._enumRegistry = new Map<any, Map<int, any>>();
|
||||||
|
|
||||||
var viewTypeMap = new Map<int, any>();
|
var viewTypeMap = new Map<int, any>();
|
||||||
viewTypeMap[0] = ViewType.HOST;
|
viewTypeMap[0] = ViewType.HOST;
|
||||||
viewTypeMap[1] = ViewType.COMPONENT;
|
viewTypeMap[1] = ViewType.COMPONENT;
|
||||||
viewTypeMap[2] = ViewType.EMBEDDED;
|
viewTypeMap[2] = ViewType.EMBEDDED;
|
||||||
this._enumRegistry.set(ViewType, viewTypeMap);
|
this._enumRegistry.set(ViewType, viewTypeMap);
|
||||||
|
|
||||||
|
var viewEncapsulationMap = new Map<int, any>();
|
||||||
|
viewEncapsulationMap[0] = ViewEncapsulation.EMULATED;
|
||||||
|
viewEncapsulationMap[1] = ViewEncapsulation.NATIVE;
|
||||||
|
viewEncapsulationMap[2] = ViewEncapsulation.NONE;
|
||||||
|
this._enumRegistry.set(ViewEncapsulation, viewEncapsulationMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(obj: any, type: Type): Object {
|
serialize(obj: any, type: Type): Object {
|
||||||
|
@ -71,8 +93,10 @@ export class Serializer {
|
||||||
return this._renderViewStore.serializeRenderFragmentRef(obj);
|
return this._renderViewStore.serializeRenderFragmentRef(obj);
|
||||||
} else if (type == WorkerElementRef) {
|
} else if (type == WorkerElementRef) {
|
||||||
return this._serializeWorkerElementRef(obj);
|
return this._serializeWorkerElementRef(obj);
|
||||||
|
} else if (type == EventBinding) {
|
||||||
|
return this._serializeEventBinding(obj);
|
||||||
} else {
|
} else {
|
||||||
throw "No serializer for " + type.toString();
|
throw new BaseException("No serializer for " + type.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +135,10 @@ export class Serializer {
|
||||||
return this._renderViewStore.deserializeRenderFragmentRef(map);
|
return this._renderViewStore.deserializeRenderFragmentRef(map);
|
||||||
} else if (type == WorkerElementRef) {
|
} else if (type == WorkerElementRef) {
|
||||||
return this._deserializeWorkerElementRef(map);
|
return this._deserializeWorkerElementRef(map);
|
||||||
|
} else if (type == EventBinding) {
|
||||||
|
return this._deserializeEventBinding(map);
|
||||||
} else {
|
} else {
|
||||||
throw "No deserializer for " + type.toString();
|
throw new BaseException("No deserializer for " + type.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +174,15 @@ export class Serializer {
|
||||||
|
|
||||||
allocateRenderViews(fragmentCount: number) { this._renderViewStore.allocate(fragmentCount); }
|
allocateRenderViews(fragmentCount: number) { this._renderViewStore.allocate(fragmentCount); }
|
||||||
|
|
||||||
|
private _serializeEventBinding(binding: EventBinding): StringMap<string, any> {
|
||||||
|
return {'fullName': binding.fullName, 'source': this.serialize(binding.source, ASTWithSource)};
|
||||||
|
}
|
||||||
|
|
||||||
|
private _deserializeEventBinding(map: StringMap<string, any>): EventBinding {
|
||||||
|
return new EventBinding(map['fullName'],
|
||||||
|
this.deserialize(map['source'], ASTWithSource, "binding"));
|
||||||
|
}
|
||||||
|
|
||||||
private _serializeWorkerElementRef(elementRef: RenderElementRef): StringMap<string, any> {
|
private _serializeWorkerElementRef(elementRef: RenderElementRef): StringMap<string, any> {
|
||||||
return {
|
return {
|
||||||
'renderView': this.serialize(elementRef.renderView, RenderViewRef),
|
'renderView': this.serialize(elementRef.renderView, RenderViewRef),
|
||||||
|
@ -214,7 +249,7 @@ export class Serializer {
|
||||||
'directives': this.serialize(view.directives, DirectiveMetadata),
|
'directives': this.serialize(view.directives, DirectiveMetadata),
|
||||||
'styleAbsUrls': view.styleAbsUrls,
|
'styleAbsUrls': view.styleAbsUrls,
|
||||||
'styles': view.styles,
|
'styles': view.styles,
|
||||||
'encapsulation': view.encapsulation
|
'encapsulation': serializeEnum(view.encapsulation)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +260,8 @@ export class Serializer {
|
||||||
directives: this.deserialize(obj['directives'], DirectiveMetadata),
|
directives: this.deserialize(obj['directives'], DirectiveMetadata),
|
||||||
styleAbsUrls: obj['styleAbsUrls'],
|
styleAbsUrls: obj['styleAbsUrls'],
|
||||||
styles: obj['styles'],
|
styles: obj['styles'],
|
||||||
encapsulation: obj['encapsulation']
|
encapsulation:
|
||||||
|
deserializeEnum(obj['encapsulation'], this._enumRegistry.get(ViewEncapsulation))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +329,7 @@ export class Serializer {
|
||||||
variableBindings: this.objectToMap(obj['variableBindings']),
|
variableBindings: this.objectToMap(obj['variableBindings']),
|
||||||
textBindings: this.deserialize(obj['textBindings'], ASTWithSource, "interpolation"),
|
textBindings: this.deserialize(obj['textBindings'], ASTWithSource, "interpolation"),
|
||||||
type: deserializeEnum(obj['type'], this._enumRegistry.get(ViewType)),
|
type: deserializeEnum(obj['type'], this._enumRegistry.get(ViewType)),
|
||||||
transitiveNgContentCount: obj['transitivengContentCount']
|
transitiveNgContentCount: obj['transitiveNgContentCount']
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// TODO: This whole file is nearly identical to core/application.ts.
|
// TODO (jteplitz602): This whole file is nearly identical to core/application.ts.
|
||||||
// There should be a way to refactor application so that this file is unnecessary
|
// There should be a way to refactor application so that this file is unnecessary. See #3277
|
||||||
import {Injector, bind, Binding} from "angular2/di";
|
import {Injector, bind, Binding} from "angular2/di";
|
||||||
import {Type, isBlank, isPresent} from "angular2/src/facade/lang";
|
import {Type, isBlank, isPresent} from "angular2/src/facade/lang";
|
||||||
import {Reflector, reflector} from 'angular2/src/reflection/reflection';
|
import {Reflector, reflector} from 'angular2/src/reflection/reflection';
|
||||||
|
@ -21,6 +21,7 @@ import {KeyEventsPlugin} from 'angular2/src/render/dom/events/key_events';
|
||||||
import {HammerGesturesPlugin} from 'angular2/src/render/dom/events/hammer_gestures';
|
import {HammerGesturesPlugin} from 'angular2/src/render/dom/events/hammer_gestures';
|
||||||
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
|
||||||
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
||||||
|
import {AppRootUrl} from 'angular2/src/services/app_root_url';
|
||||||
import {
|
import {
|
||||||
DomRenderer,
|
DomRenderer,
|
||||||
DOCUMENT_TOKEN,
|
DOCUMENT_TOKEN,
|
||||||
|
@ -28,6 +29,8 @@ import {
|
||||||
DefaultDomCompiler,
|
DefaultDomCompiler,
|
||||||
APP_ID_RANDOM_BINDING
|
APP_ID_RANDOM_BINDING
|
||||||
} from 'angular2/src/render/render';
|
} from 'angular2/src/render/render';
|
||||||
|
import {ElementSchemaRegistry} from 'angular2/src/render/dom/schema/element_schema_registry';
|
||||||
|
import {DomElementSchemaRegistry} from 'angular2/src/render/dom/schema/dom_element_schema_registry';
|
||||||
import {
|
import {
|
||||||
SharedStylesHost,
|
SharedStylesHost,
|
||||||
DomSharedStylesHost
|
DomSharedStylesHost
|
||||||
|
@ -73,11 +76,6 @@ function _injectorBindings(): List<Type | Binding | List<any>> {
|
||||||
} else if (JitChangeDetection.isSupported()) {
|
} else if (JitChangeDetection.isSupported()) {
|
||||||
bestChangeDetection = JitChangeDetection;
|
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 [
|
return [
|
||||||
bind(DOCUMENT_TOKEN)
|
bind(DOCUMENT_TOKEN)
|
||||||
|
@ -100,6 +98,7 @@ function _injectorBindings(): List<Type | Binding | List<any>> {
|
||||||
bind(SharedStylesHost).toAlias(DomSharedStylesHost),
|
bind(SharedStylesHost).toAlias(DomSharedStylesHost),
|
||||||
Serializer,
|
Serializer,
|
||||||
bind(ON_WEBWORKER).toValue(false),
|
bind(ON_WEBWORKER).toValue(false),
|
||||||
|
bind(ElementSchemaRegistry).toValue(new DomElementSchemaRegistry()),
|
||||||
RenderViewWithFragmentsStore,
|
RenderViewWithFragmentsStore,
|
||||||
RenderProtoViewRefStore,
|
RenderProtoViewRefStore,
|
||||||
ProtoViewFactory,
|
ProtoViewFactory,
|
||||||
|
@ -117,7 +116,7 @@ function _injectorBindings(): List<Type | Binding | List<any>> {
|
||||||
DirectiveResolver,
|
DirectiveResolver,
|
||||||
Parser,
|
Parser,
|
||||||
Lexer,
|
Lexer,
|
||||||
ExceptionHandler,
|
bind(ExceptionHandler).toFactory(() => new ExceptionHandler(DOM), []),
|
||||||
bind(XHR).toValue(new XHRImpl()),
|
bind(XHR).toValue(new XHRImpl()),
|
||||||
ComponentUrlMapper,
|
ComponentUrlMapper,
|
||||||
UrlResolver,
|
UrlResolver,
|
||||||
|
@ -126,6 +125,7 @@ function _injectorBindings(): List<Type | Binding | List<any>> {
|
||||||
DynamicComponentLoader,
|
DynamicComponentLoader,
|
||||||
Testability,
|
Testability,
|
||||||
AnchorBasedAppRootUrl,
|
AnchorBasedAppRootUrl,
|
||||||
|
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
|
||||||
WebWorkerMain
|
WebWorkerMain
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
library angular2.src.web_workers.event_serializer;
|
||||||
|
|
||||||
|
import 'package:angular2/src/facade/collection.dart';
|
||||||
|
// TODO(jteplitz602): Remove Mirrors from serialization #3348
|
||||||
|
@MirrorsUsed(
|
||||||
|
symbols: "altKey, bubbles, button, cancelable, client, ctrlKey, " +
|
||||||
|
"defaultPrevented, detail, eventPhase, layer, metaKey, offset, page, region, screen, " +
|
||||||
|
"shiftKey, timeStamp, type, magnitude, x, y, charCode, keyCode, keyLocation, location, repeat")
|
||||||
|
import 'dart:mirrors';
|
||||||
|
import 'dart:core';
|
||||||
|
import 'dart:html';
|
||||||
|
|
||||||
|
// These Maps can't be const due to a dartj2 bug (see http://github.com/dart-lang/sdk/issues/21825)
|
||||||
|
// Once that bug is fixed these should be const
|
||||||
|
final Map MOUSE_EVENT_PROPERTIES = {
|
||||||
|
#altKey: bool,
|
||||||
|
#bubbles: bool,
|
||||||
|
#button: int,
|
||||||
|
#cancelable: bool,
|
||||||
|
#client: Point,
|
||||||
|
#ctrlKey: bool,
|
||||||
|
#defaultPrevented: bool,
|
||||||
|
#detail: int,
|
||||||
|
#eventPhase: int,
|
||||||
|
#layer: Point,
|
||||||
|
#metaKey: bool,
|
||||||
|
#offset: Point,
|
||||||
|
#page: Point,
|
||||||
|
#region: String,
|
||||||
|
#screen: Point,
|
||||||
|
#shiftKey: bool,
|
||||||
|
#timeStamp: int,
|
||||||
|
#type: String
|
||||||
|
};
|
||||||
|
|
||||||
|
final Map KEYBOARD_EVENT_PROPERTIES = {
|
||||||
|
#altKey: bool,
|
||||||
|
#bubbles: bool,
|
||||||
|
#cancelable: bool,
|
||||||
|
#charCode: int,
|
||||||
|
#ctrlKey: bool,
|
||||||
|
#defaultPrevented: bool,
|
||||||
|
#detail: int,
|
||||||
|
#eventPhase: int,
|
||||||
|
#keyCode: int,
|
||||||
|
#keyLocation: int,
|
||||||
|
#layer: Point,
|
||||||
|
#location: int,
|
||||||
|
#repeat: bool,
|
||||||
|
#shiftKey: bool,
|
||||||
|
#timeStamp: int,
|
||||||
|
#type: String
|
||||||
|
};
|
||||||
|
|
||||||
|
Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
||||||
|
return serializeEvent(e, MOUSE_EVENT_PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
||||||
|
return serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> serializeEvent(dynamic e, Map<Symbol, Type> PROPERTIES) {
|
||||||
|
var serialized = StringMapWrapper.create();
|
||||||
|
var mirror = reflect(e);
|
||||||
|
PROPERTIES.forEach((property, type) {
|
||||||
|
var value = mirror.getField(property).reflectee;
|
||||||
|
var propertyName = MirrorSystem.getName(property);
|
||||||
|
if (type == int || type == bool || type == String) {
|
||||||
|
serialized[propertyName] = value;
|
||||||
|
} else if (type == Point) {
|
||||||
|
var point = reflect(value);
|
||||||
|
serialized[propertyName] = {
|
||||||
|
'magnitude': point.getField(#magnitude).reflectee,
|
||||||
|
'x': point.getField(#x).reflectee,
|
||||||
|
'y': point.getField(#y).reflectee
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return serialized;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import {StringMap} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
const MOUSE_EVENT_PROPERTIES = [
|
||||||
|
"altKey",
|
||||||
|
"button",
|
||||||
|
"clientX",
|
||||||
|
"clientY",
|
||||||
|
"metaKey",
|
||||||
|
"movementX",
|
||||||
|
"movementY",
|
||||||
|
"offsetX",
|
||||||
|
"offsetY",
|
||||||
|
"region",
|
||||||
|
"screenX",
|
||||||
|
"screenY",
|
||||||
|
"shiftKey"
|
||||||
|
];
|
||||||
|
|
||||||
|
const KEYBOARD_EVENT_PROPERTIES = [
|
||||||
|
'altkey',
|
||||||
|
'charCode',
|
||||||
|
'code',
|
||||||
|
'ctrlKey',
|
||||||
|
'isComposing',
|
||||||
|
'key',
|
||||||
|
'keyCode',
|
||||||
|
'location',
|
||||||
|
'metaKey',
|
||||||
|
'repeat',
|
||||||
|
'shiftKey',
|
||||||
|
'which'
|
||||||
|
];
|
||||||
|
|
||||||
|
export function serializeMouseEvent(e: MouseEvent): StringMap<string, any> {
|
||||||
|
return serializeEvent(e, MOUSE_EVENT_PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serializeKeyboardEvent(e: KeyboardEvent): StringMap<string, any> {
|
||||||
|
return serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
function serializeEvent(e: any, properties: List<string>): StringMap<string, any> {
|
||||||
|
var serialized = {};
|
||||||
|
for (var i = 0; i < properties.length; i++) {
|
||||||
|
var prop = properties[i];
|
||||||
|
serialized[prop] = e[prop];
|
||||||
|
}
|
||||||
|
return serialized;
|
||||||
|
}
|
|
@ -3,7 +3,6 @@
|
||||||
* It takes care of spawning the worker and sending it the initial init message
|
* 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
|
* It also acts and the messenger between the worker thread and the renderer running on the UI
|
||||||
* thread
|
* thread
|
||||||
* TODO: This class might need to be refactored to match application.ts...
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {createInjector} from "./di_bindings";
|
import {createInjector} from "./di_bindings";
|
||||||
|
@ -16,12 +15,14 @@ import {
|
||||||
RenderProtoViewRef,
|
RenderProtoViewRef,
|
||||||
RenderProtoViewMergeMapping,
|
RenderProtoViewMergeMapping,
|
||||||
RenderViewRef,
|
RenderViewRef,
|
||||||
|
RenderEventDispatcher,
|
||||||
RenderFragmentRef
|
RenderFragmentRef
|
||||||
} from "angular2/src/render/api";
|
} from "angular2/src/render/api";
|
||||||
import {Type, print, BaseException} from "angular2/src/facade/lang";
|
import {Type, print, BaseException, isFunction} from "angular2/src/facade/lang";
|
||||||
import {Promise, PromiseWrapper} from "angular2/src/facade/async";
|
import {Promise, PromiseWrapper} from "angular2/src/facade/async";
|
||||||
|
import {StringMapWrapper, SetWrapper} from 'angular2/src/facade/collection';
|
||||||
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
||||||
import {MessageBus} from "angular2/src/web-workers/shared/message_bus";
|
import {MessageBus, MessageBusSink} from "angular2/src/web-workers/shared/message_bus";
|
||||||
import {
|
import {
|
||||||
RenderViewWithFragmentsStore
|
RenderViewWithFragmentsStore
|
||||||
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
||||||
|
@ -32,6 +33,10 @@ import {ExceptionHandler} from 'angular2/src/core/exception_handler';
|
||||||
import {Injectable} from 'angular2/di';
|
import {Injectable} from 'angular2/di';
|
||||||
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||||
|
import {
|
||||||
|
serializeMouseEvent,
|
||||||
|
serializeKeyboardEvent
|
||||||
|
} from 'angular2/src/web-workers/ui/event_serializer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a zone, sets up the DI bindings
|
* Creates a zone, sets up the DI bindings
|
||||||
|
@ -74,11 +79,11 @@ export class WebWorkerMain {
|
||||||
* Sends an error back to the worker thread in response to an opeartion on the UI thread
|
* Sends an error back to the worker thread in response to an opeartion on the UI thread
|
||||||
*/
|
*/
|
||||||
private _sendWorkerError(id: string, error: any) {
|
private _sendWorkerError(id: string, error: any) {
|
||||||
this._sendWorkerMessage("error", {"id": id, "error": error});
|
this._sendWorkerMessage("error", {"error": error}, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _sendWorkerMessage(type: string, data: StringMap<string, any>) {
|
private _sendWorkerMessage(type: string, value: StringMap<string, any>, id?: string) {
|
||||||
this._bus.sink.send({'type': type, 'value': data});
|
this._bus.sink.send({'type': type, 'id': id, 'value': value});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Transfer the types with the serialized data so this can be automated?
|
// TODO: Transfer the types with the serialized data so this can be automated?
|
||||||
|
@ -190,12 +195,17 @@ export class WebWorkerMain {
|
||||||
var methodArgs = args[2];
|
var methodArgs = args[2];
|
||||||
this._renderer.invokeElementMethod(elementRef, methodName, methodArgs);
|
this._renderer.invokeElementMethod(elementRef, methodName, methodArgs);
|
||||||
break;
|
break;
|
||||||
|
case "setEventDispatcher":
|
||||||
|
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
||||||
|
var dispatcher = new EventDispatcher(viewRef, this._bus.sink, this._serializer);
|
||||||
|
this._renderer.setEventDispatcher(viewRef, dispatcher);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new BaseException("Not Implemented");
|
throw new BaseException("Not Implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Create message type
|
// TODO(jteplitz602): Create message type enum #3044
|
||||||
private _handleWorkerMessage(message: StringMap<string, any>) {
|
private _handleWorkerMessage(message: StringMap<string, any>) {
|
||||||
var data: ReceivedMessage = new ReceivedMessage(message['data']);
|
var data: ReceivedMessage = new ReceivedMessage(message['data']);
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
|
@ -211,8 +221,7 @@ export class WebWorkerMain {
|
||||||
private _wrapWorkerPromise(id: string, promise: Promise<any>, type: Type): void {
|
private _wrapWorkerPromise(id: string, promise: Promise<any>, type: Type): void {
|
||||||
PromiseWrapper.then(promise, (result: any) => {
|
PromiseWrapper.then(promise, (result: any) => {
|
||||||
try {
|
try {
|
||||||
this._sendWorkerMessage("result",
|
this._sendWorkerMessage("result", this._serializer.serialize(result, type), id);
|
||||||
{"id": id, "value": this._serializer.serialize(result, type)});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
}
|
}
|
||||||
|
@ -220,6 +229,50 @@ export class WebWorkerMain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EventDispatcher implements RenderEventDispatcher {
|
||||||
|
constructor(private _viewRef: RenderViewRef, private _sink: MessageBusSink,
|
||||||
|
private _serializer: Serializer) {}
|
||||||
|
|
||||||
|
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
|
||||||
|
var e = locals.get('$event');
|
||||||
|
var serializedEvent;
|
||||||
|
switch (eventName) {
|
||||||
|
case "click":
|
||||||
|
case "mouseup":
|
||||||
|
case "mousedown":
|
||||||
|
case "dblclick":
|
||||||
|
case "contextmenu":
|
||||||
|
case "mouseenter":
|
||||||
|
case "mouseleave":
|
||||||
|
case "mousemove":
|
||||||
|
case "mouseout":
|
||||||
|
case "mouseover":
|
||||||
|
case "show":
|
||||||
|
serializedEvent = serializeMouseEvent(e);
|
||||||
|
break;
|
||||||
|
case "keydown":
|
||||||
|
case "keypress":
|
||||||
|
case "keyup":
|
||||||
|
serializedEvent = serializeKeyboardEvent(e);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BaseException(eventName + " not supported on WebWorkers");
|
||||||
|
}
|
||||||
|
var serializedLocals = StringMapWrapper.create();
|
||||||
|
StringMapWrapper.set(serializedLocals, '$event', serializedEvent);
|
||||||
|
|
||||||
|
this._sink.send({
|
||||||
|
"type": "event",
|
||||||
|
"value": {
|
||||||
|
"viewRef": this._serializer.serialize(this._viewRef, RenderViewRef),
|
||||||
|
"elementIndex": elementIndex,
|
||||||
|
"eventName": eventName,
|
||||||
|
"locals": serializedLocals
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ReceivedMessage {
|
class ReceivedMessage {
|
||||||
method: string;
|
method: string;
|
||||||
args: List<any>;
|
args: List<any>;
|
||||||
|
|
|
@ -101,7 +101,7 @@ function _injectorBindings(appComponentType, bus: WorkerMessageBus,
|
||||||
Serializer,
|
Serializer,
|
||||||
bind(WorkerMessageBus).toValue(bus),
|
bind(WorkerMessageBus).toValue(bus),
|
||||||
bind(MessageBroker)
|
bind(MessageBroker)
|
||||||
.toFactory((a, b) => new MessageBroker(a, b), [WorkerMessageBus, Serializer]),
|
.toFactory((a, b, c) => new MessageBroker(a, b, c), [WorkerMessageBus, Serializer, NgZone]),
|
||||||
WorkerRenderer,
|
WorkerRenderer,
|
||||||
bind(Renderer).toAlias(WorkerRenderer),
|
bind(Renderer).toAlias(WorkerRenderer),
|
||||||
WorkerCompiler,
|
WorkerCompiler,
|
||||||
|
@ -172,11 +172,6 @@ export function bootstrapWebworkerCommon(
|
||||||
PromiseWrapper.then(compRefToken, tick,
|
PromiseWrapper.then(compRefToken, tick,
|
||||||
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
|
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
|
||||||
|
|
||||||
PromiseWrapper.catchError(compRefToken, (err) => {
|
|
||||||
print(err);
|
|
||||||
bootstrapProcess.reject(err, err.stack);
|
|
||||||
});
|
|
||||||
|
|
||||||
bus.source.removeListener(listenerId);
|
bus.source.removeListener(listenerId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,17 @@ import {ListWrapper, StringMapWrapper, MapWrapper} from "../../facade/collection
|
||||||
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
||||||
import {Injectable} from "angular2/di";
|
import {Injectable} from "angular2/di";
|
||||||
import {Type} from "angular2/src/facade/lang";
|
import {Type} from "angular2/src/facade/lang";
|
||||||
|
import {RenderViewRef, RenderEventDispatcher} from 'angular2/src/render/api';
|
||||||
|
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MessageBroker {
|
export class MessageBroker {
|
||||||
private _pending: Map<string, Function> = new Map<string, Function>();
|
private _pending: Map<string, PromiseCompleter<any>> = new Map<string, PromiseCompleter<any>>();
|
||||||
|
private _eventDispatchRegistry: Map<RenderViewRef, RenderEventDispatcher> =
|
||||||
|
new Map<RenderViewRef, RenderEventDispatcher>();
|
||||||
|
|
||||||
constructor(private _messageBus: MessageBus, protected _serializer: Serializer) {
|
constructor(private _messageBus: MessageBus, protected _serializer: Serializer,
|
||||||
|
private _zone: NgZone) {
|
||||||
this._messageBus.source.addListener((data) => this._handleMessage(data['data']));
|
this._messageBus.source.addListener((data) => this._handleMessage(data['data']));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,17 +48,17 @@ export class MessageBroker {
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
var completer: PromiseCompleter<any> = PromiseWrapper.completer();
|
var completer: PromiseCompleter<any> = PromiseWrapper.completer();
|
||||||
id = this._generateMessageId(args.type + args.method);
|
id = this._generateMessageId(args.type + args.method);
|
||||||
this._pending.set(id, completer.resolve);
|
this._pending.set(id, completer);
|
||||||
PromiseWrapper.catchError(completer.promise, (err, stack?) => {
|
PromiseWrapper.catchError(completer.promise, (err, stack?) => {
|
||||||
print(err);
|
print(err);
|
||||||
completer.reject(err, stack);
|
completer.reject(err, stack);
|
||||||
});
|
});
|
||||||
|
|
||||||
promise = PromiseWrapper.then(completer.promise, (data: MessageResult) => {
|
promise = PromiseWrapper.then(completer.promise, (value: any) => {
|
||||||
if (this._serializer == null) {
|
if (this._serializer == null) {
|
||||||
return data.value;
|
return value;
|
||||||
} else {
|
} else {
|
||||||
return this._serializer.deserialize(data.value, returnType);
|
return this._serializer.deserialize(value, returnType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,35 +78,67 @@ export class MessageBroker {
|
||||||
private _handleMessage(message: StringMap<string, any>): void {
|
private _handleMessage(message: StringMap<string, any>): void {
|
||||||
var data = new MessageData(message);
|
var data = new MessageData(message);
|
||||||
// TODO(jteplitz602): replace these strings with messaging constants
|
// TODO(jteplitz602): replace these strings with messaging constants
|
||||||
var id = data.value.id;
|
if (data.type === "event") {
|
||||||
if (this._pending.has(id)) {
|
this._dispatchEvent(new RenderEventData(data.value, this._serializer));
|
||||||
this._pending.get(id)(data.value);
|
} else if (data.type === "result" || data.type === "error") {
|
||||||
this._pending.delete(id);
|
var id = data.id;
|
||||||
|
if (this._pending.has(id)) {
|
||||||
|
if (data.type === "result") {
|
||||||
|
this._pending.get(id).resolve(data.value);
|
||||||
|
} else {
|
||||||
|
this._pending.get(id).reject(data.value, null);
|
||||||
|
}
|
||||||
|
this._pending.delete(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _dispatchEvent(eventData: RenderEventData): void {
|
||||||
|
var dispatcher = this._eventDispatchRegistry.get(eventData.viewRef);
|
||||||
|
this._zone.run(() => {
|
||||||
|
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: StringMap<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']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageData {
|
class MessageData {
|
||||||
type: string;
|
type: string;
|
||||||
value: MessageResult;
|
value: any;
|
||||||
|
id: string;
|
||||||
|
|
||||||
constructor(data: StringMap<string, any>) {
|
constructor(data: StringMap<string, any>) {
|
||||||
this.type = StringMapWrapper.get(data, "type");
|
this.type = StringMapWrapper.get(data, "type");
|
||||||
if (StringMapWrapper.contains(data, "value")) {
|
this.id = this._getValueIfPresent(data, "id");
|
||||||
this.value = new MessageResult(StringMapWrapper.get(data, "value"));
|
this.value = this._getValueIfPresent(data, "value");
|
||||||
} else {
|
|
||||||
this.value = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class MessageResult {
|
/**
|
||||||
id: string;
|
* Returns the value from the StringMap if present. Otherwise returns null
|
||||||
value: any;
|
*/
|
||||||
|
_getValueIfPresent(data: StringMap<string, any>, key: string) {
|
||||||
constructor(result: StringMap<string, any>) {
|
if (StringMapWrapper.contains(data, key)) {
|
||||||
this.id = StringMapWrapper.get(result, "id");
|
return StringMapWrapper.get(data, key);
|
||||||
this.value = StringMapWrapper.get(result, "value");
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,6 +255,9 @@ export class WorkerRenderer implements Renderer {
|
||||||
* Sets the dispatcher for all events of the given view
|
* Sets the dispatcher for all events of the given view
|
||||||
*/
|
*/
|
||||||
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) {
|
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) {
|
||||||
// TODO(jteplitz602) support dom events in web worker. See #3046
|
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
||||||
|
var args = new UiArguments("renderer", "setEventDispatcher", fnArgs);
|
||||||
|
this._messageBroker.registerEventDispatcher(viewRef, dispatcher);
|
||||||
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
import {
|
||||||
|
AsyncTestCompleter,
|
||||||
|
inject,
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
createTestInjector,
|
||||||
|
beforeEachBindings,
|
||||||
|
SpyObject,
|
||||||
|
proxy
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||||
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
|
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
|
import {MessageBroker} from 'angular2/src/web-workers/worker/broker';
|
||||||
|
import {MockMessageBus, MockMessageBusSink, MockMessageBusSource} from './worker_test_util';
|
||||||
|
import {ON_WEBWORKER} from 'angular2/src/web-workers/shared/api';
|
||||||
|
import {bind} from 'angular2/di';
|
||||||
|
import {RenderProtoViewRefStore} 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 {RenderEventDispatcher, RenderViewRef} from 'angular2/src/render/api';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe("MessageBroker", () => {
|
||||||
|
beforeEachBindings(() => [
|
||||||
|
bind(ON_WEBWORKER)
|
||||||
|
.toValue(true),
|
||||||
|
RenderProtoViewRefStore,
|
||||||
|
RenderViewWithFragmentsStore
|
||||||
|
]);
|
||||||
|
|
||||||
|
it("should dispatch events", inject([Serializer, NgZone], (serializer, zone) => {
|
||||||
|
var bus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource());
|
||||||
|
var broker = new MessageBroker(bus, serializer, zone);
|
||||||
|
|
||||||
|
var eventDispatcher = new SpyEventDispatcher();
|
||||||
|
var viewRef = new WorkerRenderViewRef(0);
|
||||||
|
serializer.allocateRenderViews(0); // serialize the ref so it's in the store
|
||||||
|
viewRef =
|
||||||
|
serializer.deserialize(serializer.serialize(viewRef, RenderViewRef), RenderViewRef);
|
||||||
|
broker.registerEventDispatcher(viewRef, eventDispatcher);
|
||||||
|
|
||||||
|
var elementIndex = 15;
|
||||||
|
var eventName = 'click';
|
||||||
|
|
||||||
|
bus.source.receive({
|
||||||
|
'data': {
|
||||||
|
'type': 'event',
|
||||||
|
'value': {
|
||||||
|
'viewRef': viewRef.serialize(),
|
||||||
|
'elementIndex': elementIndex,
|
||||||
|
'eventName': eventName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(eventDispatcher.wasDispatched).toBeTruthy();
|
||||||
|
expect(eventDispatcher.elementIndex).toEqual(elementIndex);
|
||||||
|
expect(eventDispatcher.eventName).toEqual(eventName);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpyEventDispatcher implements RenderEventDispatcher {
|
||||||
|
wasDispatched: boolean = false;
|
||||||
|
elementIndex: number;
|
||||||
|
eventName: string;
|
||||||
|
|
||||||
|
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
|
||||||
|
this.wasDispatched = true;
|
||||||
|
this.elementIndex = elementIndex;
|
||||||
|
this.eventName = eventName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,12 +26,6 @@ import {
|
||||||
RenderViewRef,
|
RenderViewRef,
|
||||||
RenderFragmentRef
|
RenderFragmentRef
|
||||||
} from "angular2/src/render/api";
|
} from "angular2/src/render/api";
|
||||||
import {
|
|
||||||
MessageBus,
|
|
||||||
MessageBusSource,
|
|
||||||
MessageBusSink,
|
|
||||||
SourceListener
|
|
||||||
} from "angular2/src/web-workers/shared/message_bus";
|
|
||||||
import {
|
import {
|
||||||
RenderProtoViewRefStore,
|
RenderProtoViewRefStore,
|
||||||
WebworkerRenderProtoViewRef
|
WebworkerRenderProtoViewRef
|
||||||
|
@ -44,6 +38,7 @@ import {resolveInternalDomProtoView} from 'angular2/src/render/dom/view/proto_vi
|
||||||
import {someComponent} from '../../render/dom/dom_renderer_integration_spec';
|
import {someComponent} from '../../render/dom/dom_renderer_integration_spec';
|
||||||
import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl';
|
import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl';
|
||||||
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
||||||
|
import {MockMessageBus, MockMessageBusSink, MockMessageBusSource} from './worker_test_util';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
function createBroker(workerSerializer: Serializer, uiSerializer: Serializer, tb: DomTestbed,
|
function createBroker(workerSerializer: Serializer, uiSerializer: Serializer, tb: DomTestbed,
|
||||||
|
@ -56,7 +51,7 @@ export function main() {
|
||||||
workerMessageBus.attachToBus(uiMessageBus);
|
workerMessageBus.attachToBus(uiMessageBus);
|
||||||
|
|
||||||
// set up the worker side
|
// set up the worker side
|
||||||
var broker = new MessageBroker(workerMessageBus, workerSerializer);
|
var broker = new MessageBroker(workerMessageBus, workerSerializer, null);
|
||||||
|
|
||||||
// set up the ui side
|
// set up the ui side
|
||||||
var webWorkerMain = new WebWorkerMain(tb.compiler, tb.renderer, uiRenderViewStore, uiSerializer,
|
var webWorkerMain = new WebWorkerMain(tb.compiler, tb.renderer, uiRenderViewStore, uiSerializer,
|
||||||
|
@ -118,7 +113,6 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Web Worker Renderer", () => {
|
describe("Web Worker Renderer", () => {
|
||||||
beforeEachBindings(() => [DomTestbed]);
|
|
||||||
var renderer: WorkerRenderer;
|
var renderer: WorkerRenderer;
|
||||||
var workerSerializer: Serializer;
|
var workerSerializer: Serializer;
|
||||||
var workerRenderViewStore: RenderViewWithFragmentsStore;
|
var workerRenderViewStore: RenderViewWithFragmentsStore;
|
||||||
|
@ -145,7 +139,6 @@ export function main() {
|
||||||
workerRenderViewStore);
|
workerRenderViewStore);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should create and destroy root host views while using the given elements in place',
|
it('should create and destroy root host views while using the given elements in place',
|
||||||
inject([AsyncTestCompleter], (async) => {
|
inject([AsyncTestCompleter], (async) => {
|
||||||
tb.compiler.compileHost(someComponent)
|
tb.compiler.compileHost(someComponent)
|
||||||
|
@ -313,32 +306,3 @@ function createSerializer(protoViewRefStore: RenderProtoViewRefStore,
|
||||||
]);
|
]);
|
||||||
return injector.get(Serializer);
|
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); }
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import {
|
||||||
|
MessageBus,
|
||||||
|
MessageBusSource,
|
||||||
|
MessageBusSink,
|
||||||
|
SourceListener
|
||||||
|
} from "angular2/src/web-workers/shared/message_bus";
|
||||||
|
import {MapWrapper} from "angular2/src/facade/collection";
|
||||||
|
|
||||||
|
export 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); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MockMessageBusSink implements MessageBusSink {
|
||||||
|
private _sendTo: MockMessageBusSource;
|
||||||
|
|
||||||
|
send(message: Object): void { this._sendTo.receive({'data': message}); }
|
||||||
|
|
||||||
|
attachToSource(source: MockMessageBusSource) { this._sendTo = source; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MockMessageBus implements MessageBus {
|
||||||
|
constructor(public sink: MockMessageBusSink, public source: MockMessageBusSource) {}
|
||||||
|
attachToBus(bus: MockMessageBus) { this.sink.attachToSource(bus.source); }
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import {verifyNoBrowserErrors} from 'angular2/src/test_lib/e2e_util';
|
import {verifyNoBrowserErrors} from 'angular2/src/test_lib/e2e_util';
|
||||||
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
function waitForElement(selector) {
|
function waitForElement(selector) {
|
||||||
var EC = (<any>protractor).ExpectedConditions;
|
var EC = (<any>protractor).ExpectedConditions;
|
||||||
|
@ -6,6 +7,12 @@ function waitForElement(selector) {
|
||||||
browser.wait(EC.presenceOf($(selector)), 10000);
|
browser.wait(EC.presenceOf($(selector)), 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns a promise that resolves in the given number of milliseconds
|
||||||
|
function wait(time) {
|
||||||
|
var promise = new Promise((resolve, reject) => { setTimeout(resolve, time); });
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
describe('routing inbox-app', function() {
|
describe('routing inbox-app', function() {
|
||||||
|
|
||||||
afterEach(verifyNoBrowserErrors);
|
afterEach(verifyNoBrowserErrors);
|
||||||
|
@ -62,6 +69,7 @@ describe('routing inbox-app', function() {
|
||||||
waitForElement('#item-10');
|
waitForElement('#item-10');
|
||||||
element(by.css('#item-10')).click();
|
element(by.css('#item-10')).click();
|
||||||
waitForElement('#record-id');
|
waitForElement('#record-id');
|
||||||
|
browser.wait(wait(500), 600);
|
||||||
expect(element(by.css('#record-id')).getText()).toEqual('ID: 10');
|
expect(element(by.css('#record-id')).getText()).toEqual('ID: 10');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
library examples.e2e_test.web_workers.web_workers_spec;
|
||||||
|
|
||||||
|
main() {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import {verifyNoBrowserErrors} from 'angular2/src/test_lib/e2e_util';
|
||||||
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
// returns a promise that resolves in the given number of milliseconds
|
||||||
|
function wait(time) {
|
||||||
|
var promise = new Promise((resolve, reject) => { setTimeout(resolve, time); });
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WebWorkers', function() {
|
||||||
|
afterEach(verifyNoBrowserErrors);
|
||||||
|
var selector = "hello-app .greeting";
|
||||||
|
var URL = "examples/src/web_workers/index.html";
|
||||||
|
|
||||||
|
it('should greet', () => {
|
||||||
|
browser.get(URL);
|
||||||
|
|
||||||
|
browser.wait(protractor.until.elementLocated(by.css(selector)), 5000);
|
||||||
|
expect(element.all(by.css(selector)).first().getText()).toEqual("hello world!");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should change greeting', () => {
|
||||||
|
browser.get(URL);
|
||||||
|
|
||||||
|
browser.wait(protractor.until.elementLocated(by.css(selector)), 5000);
|
||||||
|
element.all(by.css(".changeButton")).first().click();
|
||||||
|
browser.wait(wait(500), 600);
|
||||||
|
expect(element.all(by.css(selector)).first().getText()).toEqual("howdy world!");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should display correct key names", () => {
|
||||||
|
browser.get(URL);
|
||||||
|
browser.wait(protractor.until.elementLocated(by.css(".sample-area")), 5000);
|
||||||
|
|
||||||
|
var area = element.all(by.css(".sample-area")).first();
|
||||||
|
expect(area.getText()).toEqual('(none)');
|
||||||
|
browser.wait(wait(500), 600);
|
||||||
|
|
||||||
|
area.sendKeys('u');
|
||||||
|
expect(area.getText()).toEqual("U");
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,6 +4,7 @@ import "package:angular2/src/web-workers/worker/application.dart"
|
||||||
show WorkerMessageBus, WorkerMessageBusSource, WorkerMessageBusSink;
|
show WorkerMessageBus, WorkerMessageBusSource, WorkerMessageBusSink;
|
||||||
import "package:angular2/src/web-workers/worker/broker.dart"
|
import "package:angular2/src/web-workers/worker/broker.dart"
|
||||||
show MessageBroker, UiArguments;
|
show MessageBroker, UiArguments;
|
||||||
|
import "package:angular2/src/web-workers/shared/serializer.dart" show Serializer;
|
||||||
|
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ main(List<String> args, SendPort replyTo) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
MessageBroker broker = new MessageBroker(bus, null);
|
MessageBroker broker = new MessageBroker(bus, new Serializer(null, null, null), null);
|
||||||
var args = new UiArguments("test", "tester");
|
var args = new UiArguments("test", "tester");
|
||||||
broker.runOnUiThread(args, String).then((data) {
|
broker.runOnUiThread(args, String).then((data) {
|
||||||
bus.sink.send({"type": "result", "value": data});
|
bus.sink.send({"type": "result", "value": data});
|
||||||
|
|
|
@ -14,7 +14,7 @@ export function main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var broker = new MessageBroker(bus, new Serializer(null));
|
var broker = new MessageBroker(bus, new Serializer(null, null, null), null);
|
||||||
var args = new UiArguments("test", "tester");
|
var args = new UiArguments("test", "tester");
|
||||||
broker.runOnUiThread(args, String)
|
broker.runOnUiThread(args, String)
|
||||||
.then((data: string) => { bus.sink.send({type: "result", value: data}); });
|
.then((data: string) => { bus.sink.send({type: "result", value: data}); });
|
||||||
|
|
|
@ -19,7 +19,7 @@ main() {
|
||||||
.appendHtml("<span class='response'>${data['value']}</span>");
|
.appendHtml("<span class='response'>${data['value']}</span>");
|
||||||
} else if (identical(data['type'], "test")) {
|
} else if (identical(data['type'], "test")) {
|
||||||
bus.sink.send(
|
bus.sink.send(
|
||||||
{'type': "result", 'value': {'id': data['id'], 'value': VALUE}});
|
{'type': "result", 'id': data['id'], 'value': VALUE});
|
||||||
} else if (identical(data['type'], "result")) {
|
} else if (identical(data['type'], "result")) {
|
||||||
querySelector("#ui_result")
|
querySelector("#ui_result")
|
||||||
.appendHtml("<span class='result'>${data['value']}</span>");
|
.appendHtml("<span class='result'>${data['value']}</span>");
|
||||||
|
|
|
@ -19,7 +19,7 @@ bus.source.addListener((message) => {
|
||||||
document.getElementById("echo_result").innerHTML =
|
document.getElementById("echo_result").innerHTML =
|
||||||
`<span class='response'>${message.data.value}</span>`;
|
`<span class='response'>${message.data.value}</span>`;
|
||||||
} else if (message.data.type === "test") {
|
} else if (message.data.type === "test") {
|
||||||
bus.sink.send({type: "result", value: {id: message.data.id, value: VALUE}});
|
bus.sink.send({type: "result", id: message.data.id, value: VALUE});
|
||||||
} else if (message.data.type == "result") {
|
} else if (message.data.type == "result") {
|
||||||
document.getElementById("ui_result").innerHTML =
|
document.getElementById("ui_result").innerHTML =
|
||||||
`<span class='result'>${message.data.value}</span>`;
|
`<span class='result'>${message.data.value}</span>`;
|
||||||
|
|
|
@ -9,5 +9,5 @@ import "package:angular2/src/reflection/reflection.dart";
|
||||||
|
|
||||||
main(List<String> args, SendPort replyTo) {
|
main(List<String> args, SendPort replyTo) {
|
||||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
bootstrapWebworker(replyTo, HelloCmp);
|
bootstrapWebworker(replyTo, HelloCmp).catchError((error) => throw error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<title>Hello Angular 2.0</title>
|
|
||||||
<body>
|
|
||||||
<hello-app>
|
|
||||||
Loading...
|
|
||||||
</hello-app>
|
|
||||||
|
|
||||||
$SCRIPTS$
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<title>Hello Angular 2.0</title>
|
||||||
|
<style>
|
||||||
|
.sample-area {
|
||||||
|
text-align: center;
|
||||||
|
margin: 5px;
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #d0d0d0;
|
||||||
|
}
|
||||||
|
.sample-area:focus {
|
||||||
|
border: 1px solid blue;
|
||||||
|
color: blue;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<hello-app>
|
||||||
|
Loading...
|
||||||
|
</hello-app>
|
||||||
|
|
||||||
|
$SCRIPTS$
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,4 +1,5 @@
|
||||||
import {ElementRef, Component, Directive, View, Injectable, Renderer} from 'angular2/angular2';
|
import {ElementRef, Component, Directive, View, Injectable, Renderer} from 'angular2/angular2';
|
||||||
|
import {StringWrapper} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
// A service available to the Injector, used by the HelloCmp component.
|
// A service available to the Injector, used by the HelloCmp component.
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -37,7 +38,8 @@ class RedDec {
|
||||||
// Expressions in the template (like {{greeting}}) are evaluated in the
|
// Expressions in the template (like {{greeting}}) are evaluated in the
|
||||||
// context of the HelloCmp class below.
|
// context of the HelloCmp class below.
|
||||||
template: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
|
template: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
|
||||||
<button class="changeButton">change greeting</button>`,
|
<button class="changeButton" (click)="changeGreeting()">change greeting</button>
|
||||||
|
<div (keydown)="onKeyDown($event)" class="sample-area" tabindex="0">{{lastKey}}</div><br>`,
|
||||||
// All directives used in the template need to be specified. This allows for
|
// All directives used in the template need to be specified. This allows for
|
||||||
// modularity (RedDec can only be used in this template)
|
// modularity (RedDec can only be used in this template)
|
||||||
// and better tooling (the template can be invalidated if the attribute is
|
// and better tooling (the template can be invalidated if the attribute is
|
||||||
|
@ -46,8 +48,11 @@ class RedDec {
|
||||||
})
|
})
|
||||||
export class HelloCmp {
|
export class HelloCmp {
|
||||||
greeting: string;
|
greeting: string;
|
||||||
|
lastKey: string = '(none)';
|
||||||
|
|
||||||
constructor(service: GreetingService) { this.greeting = service.greeting; }
|
constructor(service: GreetingService) { this.greeting = service.greeting; }
|
||||||
|
|
||||||
changeGreeting(): void { this.greeting = 'howdy'; }
|
changeGreeting(): void { this.greeting = 'howdy'; }
|
||||||
|
|
||||||
|
onKeyDown(event): void { this.lastKey = StringWrapper.fromCharCode(event['keyCode']); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
$SCRIPTS$
|
$SCRIPTS$ window = {
|
||||||
|
setTimeout: setTimeout,
|
||||||
|
Map: Map,
|
||||||
|
Set: Set,
|
||||||
|
Array: Array,
|
||||||
|
Reflect: Reflect,
|
||||||
|
RegExp: RegExp,
|
||||||
|
Promise: Promise,
|
||||||
|
Date: Date,
|
||||||
|
zone: zone
|
||||||
|
};
|
||||||
|
assert = function() {};
|
||||||
|
|
||||||
// TODO (jteplitz) Monkey patch this from within angular (#3207)
|
System.import("examples/src/web_workers/background_index")
|
||||||
window = {
|
.then(
|
||||||
setTimeout: setTimeout,
|
function(m) {
|
||||||
Map: Map,
|
console.log("running main");
|
||||||
Set: Set,
|
try {
|
||||||
Array: Array,
|
m.main();
|
||||||
Reflect: Reflect,
|
} catch (e) {
|
||||||
RegExp: RegExp,
|
console.error(e);
|
||||||
Promise: Promise,
|
}
|
||||||
Date: Date
|
},
|
||||||
};
|
function(error) { console.error("error loading background", error); });
|
||||||
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); });
|
|
||||||
|
|
Loading…
Reference in New Issue