refactor(platform-webworker): cleanup

This commit is contained in:
Victor Berchet 2017-02-19 00:23:45 -08:00
parent 3517f28609
commit cdf99cf68b
15 changed files with 301 additions and 314 deletions

View File

@ -13,16 +13,13 @@ import {WORKER_SCRIPT, platformWorkerUi} from './worker_render';
export {VERSION} from './version'; export {VERSION} from './version';
export {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from './web_workers/shared/client_message_broker'; export {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from './web_workers/shared/client_message_broker';
export {MessageBus, MessageBusSink, MessageBusSource} from './web_workers/shared/message_bus'; export {MessageBus, MessageBusSink, MessageBusSource} from './web_workers/shared/message_bus';
export {SerializerTypes} from './web_workers/shared/serialized_types'; export {PRIMITIVE, SerializerTypes} from './web_workers/shared/serializer';
export {PRIMITIVE} from './web_workers/shared/serializer';
export {ReceivedMessage, ServiceMessageBroker, ServiceMessageBrokerFactory} from './web_workers/shared/service_message_broker'; export {ReceivedMessage, ServiceMessageBroker, ServiceMessageBrokerFactory} from './web_workers/shared/service_message_broker';
export {WORKER_UI_LOCATION_PROVIDERS} from './web_workers/ui/location_providers'; export {WORKER_UI_LOCATION_PROVIDERS} from './web_workers/ui/location_providers';
export {WORKER_APP_LOCATION_PROVIDERS} from './web_workers/worker/location_providers'; export {WORKER_APP_LOCATION_PROVIDERS} from './web_workers/worker/location_providers';
export {WorkerAppModule, platformWorkerApp} from './worker_app'; export {WorkerAppModule, platformWorkerApp} from './worker_app';
export {platformWorkerUi} from './worker_render'; export {platformWorkerUi} from './worker_render';
/** /**
* Bootstraps the worker ui. * Bootstraps the worker ui.
* *

View File

@ -12,8 +12,7 @@ import {EventEmitter} from '../../facade/async';
import {stringify} from '../../facade/lang'; import {stringify} from '../../facade/lang';
import {MessageBus} from './message_bus'; import {MessageBus} from './message_bus';
import {SerializerTypes} from './serialized_types'; import {Serializer, SerializerTypes} from './serializer';
import {Serializer} from './serializer';
/** /**
@ -48,7 +47,7 @@ export class ClientMessageBrokerFactory_ extends ClientMessageBrokerFactory {
* @experimental WebWorker support in Angular is experimental. * @experimental WebWorker support in Angular is experimental.
*/ */
export abstract class ClientMessageBroker { export abstract class ClientMessageBroker {
abstract runOnService(args: UiArguments, returnType: Type<any>): Promise<any>; abstract runOnService(args: UiArguments, returnType: Type<any>|SerializerTypes): Promise<any>;
} }
interface PromiseCompleter { interface PromiseCompleter {
@ -68,7 +67,7 @@ export class ClientMessageBroker_ extends ClientMessageBroker {
this._serializer = _serializer; this._serializer = _serializer;
const source = messageBus.from(channel); const source = messageBus.from(channel);
source.subscribe({next: (message: {[key: string]: any}) => this._handleMessage(message)}); source.subscribe({next: (message: MessageData) => this._handleMessage(message)});
} }
private _generateMessageId(name: string): string { private _generateMessageId(name: string): string {
@ -82,7 +81,7 @@ export class ClientMessageBroker_ extends ClientMessageBroker {
return id; return id;
} }
runOnService(args: UiArguments, returnType: Type<any>): Promise<any> { runOnService(args: UiArguments, returnType: Type<any>|SerializerTypes): Promise<any> {
const fnArgs: any[] = []; const fnArgs: any[] = [];
if (args.args) { if (args.args) {
args.args.forEach(argument => { args.args.forEach(argument => {
@ -127,15 +126,14 @@ export class ClientMessageBroker_ extends ClientMessageBroker {
return promise; return promise;
} }
private _handleMessage(message: {[key: string]: any}): void { private _handleMessage(message: MessageData): void {
const data = new MessageData(message); if (message.type === 'result' || message.type === 'error') {
if (data.type === 'result' || data.type === 'error') { const id = message.id;
const id = data.id;
if (this._pending.has(id)) { if (this._pending.has(id)) {
if (data.type === 'result') { if (message.type === 'result') {
this._pending.get(id).resolve(data.value); this._pending.get(id).resolve(message.value);
} else { } else {
this._pending.get(id).reject(data.value); this._pending.get(id).reject(message.value);
} }
this._pending.delete(id); this._pending.delete(id);
} }
@ -143,31 +141,18 @@ export class ClientMessageBroker_ extends ClientMessageBroker {
} }
} }
class MessageData { interface MessageData {
type: string; type: 'result'|'error';
value: any; value?: any;
id: string; id?: string;
constructor(data: {[key: string]: any}) {
this.type = data['type'];
this.id = this._getValueIfPresent(data, 'id');
this.value = this._getValueIfPresent(data, 'value');
}
/**
* Returns the value if present, otherwise returns null
* @internal
*/
_getValueIfPresent(data: {[key: string]: any}, key: string) {
return data.hasOwnProperty(key) ? data[key] : null;
}
} }
/** /**
* @experimental WebWorker support in Angular is experimental. * @experimental WebWorker support in Angular is experimental.
*/ */
export class FnArg { export class FnArg {
constructor(public value: any, public type: Type<any>|SerializerTypes = null) {} constructor(
public value: any, public type: Type<any>|SerializerTypes = SerializerTypes.PRIMITIVE) {}
} }
/** /**

View File

@ -1,24 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// This file contains interface versions of browser types that can be serialized to Plain Old
// JavaScript Objects
export class LocationType {
constructor(
public href: string, public protocol: string, public host: string, public hostname: string,
public port: string, public pathname: string, public search: string, public hash: string,
public origin: string) {}
}
/**
* @experimental WebWorker support in Angular is currently experimental.
*/
export const enum SerializerTypes {
// RendererTypeV2
RENDERER_TYPE_V2,
}

View File

@ -6,36 +6,52 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Injectable, RenderComponentType, RendererTypeV2, Type, ViewEncapsulation} from '@angular/core'; import {Injectable, RenderComponentType, RendererTypeV2, Type} from '@angular/core';
import {stringify} from '../../facade/lang'; import {stringify} from '../../facade/lang';
import {RenderStore} from './render_store'; import {RenderStore} from './render_store';
import {LocationType, SerializerTypes} from './serialized_types';
// PRIMITIVE is any type that does not need to be serialized (string, number, boolean) /**
// We set it to String so that it is considered a Type. * Any type that does not need to be serialized (string, number, boolean)
*
* @experimental WebWorker support in Angular is currently experimental.
* @deprecated in v4. Use SerializerTypes.PRIMITIVE instead
*/
export const PRIMITIVE: Type<any> = String;
export class LocationType {
constructor(
public href: string, public protocol: string, public host: string, public hostname: string,
public port: string, public pathname: string, public search: string, public hash: string,
public origin: string) {}
}
/** /**
* @experimental WebWorker support in Angular is currently experimental. * @experimental WebWorker support in Angular is currently experimental.
*/ */
export const PRIMITIVE: Type<any> = String; export const enum SerializerTypes {
// RendererTypeV2
RENDERER_TYPE_V2,
// Primitive types
PRIMITIVE,
// An object stored in a RenderStore
RENDER_STORE_OBJECT,
}
@Injectable() @Injectable()
export class Serializer { export class Serializer {
constructor(private _renderStore: RenderStore) {} constructor(private _renderStore: RenderStore) {}
serialize(obj: any, type: any): Object { serialize(obj: any, type: Type<any>|SerializerTypes = SerializerTypes.PRIMITIVE): Object {
if (obj == null) { if (obj == null || type === PRIMITIVE || type === SerializerTypes.PRIMITIVE) {
return null; return obj;
} }
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
return obj.map(v => this.serialize(v, type)); return obj.map(v => this.serialize(v, type));
} }
if (type == PRIMITIVE) { if (type === SerializerTypes.RENDER_STORE_OBJECT) {
return obj;
}
if (type == RenderStoreObject) {
return this._renderStore.serialize(obj); return this._renderStore.serialize(obj);
} }
if (type === RenderComponentType) { if (type === RenderComponentType) {
@ -44,26 +60,21 @@ export class Serializer {
if (type === SerializerTypes.RENDERER_TYPE_V2) { if (type === SerializerTypes.RENDERER_TYPE_V2) {
return this._serializeRendererTypeV2(obj); return this._serializeRendererTypeV2(obj);
} }
if (type === ViewEncapsulation) {
return obj;
}
if (type === LocationType) { if (type === LocationType) {
return this._serializeLocation(obj); return this._serializeLocation(obj);
} }
throw new Error(`No serializer for type ${stringify(type)}`); throw new Error(`No serializer for type ${stringify(type)}`);
} }
deserialize(map: any, type: any, data?: any): any { deserialize(map: any, type: Type<any>|SerializerTypes = SerializerTypes.PRIMITIVE, data?: any):
if (map == null) { any {
return null; if (map == null || type === PRIMITIVE || type === SerializerTypes.PRIMITIVE) {
return map;
} }
if (Array.isArray(map)) { if (Array.isArray(map)) {
return map.map(val => this.deserialize(val, type, data)); return map.map(val => this.deserialize(val, type, data));
} }
if (type === PRIMITIVE) { if (type === SerializerTypes.RENDER_STORE_OBJECT) {
return map;
}
if (type === RenderStoreObject) {
return this._renderStore.deserialize(map); return this._renderStore.deserialize(map);
} }
if (type === RenderComponentType) { if (type === RenderComponentType) {
@ -72,9 +83,6 @@ export class Serializer {
if (type === SerializerTypes.RENDERER_TYPE_V2) { if (type === SerializerTypes.RENDERER_TYPE_V2) {
return this._deserializeRendererTypeV2(map); return this._deserializeRendererTypeV2(map);
} }
if (type === ViewEncapsulation) {
return map as ViewEncapsulation;
}
if (type === LocationType) { if (type === LocationType) {
return this._deserializeLocation(map); return this._deserializeLocation(map);
} }
@ -106,24 +114,23 @@ export class Serializer {
'id': type.id, 'id': type.id,
'templateUrl': type.templateUrl, 'templateUrl': type.templateUrl,
'slotCount': type.slotCount, 'slotCount': type.slotCount,
'encapsulation': this.serialize(type.encapsulation, ViewEncapsulation), 'encapsulation': this.serialize(type.encapsulation),
'styles': this.serialize(type.styles, PRIMITIVE), 'styles': this.serialize(type.styles),
}; };
} }
private _deserializeRenderComponentType(props: {[key: string]: any}): RenderComponentType { private _deserializeRenderComponentType(props: {[key: string]: any}): RenderComponentType {
return new RenderComponentType( return new RenderComponentType(
props['id'], props['templateUrl'], props['slotCount'], props['id'], props['templateUrl'], props['slotCount'],
this.deserialize(props['encapsulation'], ViewEncapsulation), this.deserialize(props['encapsulation']), this.deserialize(props['styles']), {});
this.deserialize(props['styles'], PRIMITIVE), {});
} }
private _serializeRendererTypeV2(type: RendererTypeV2): {[key: string]: any} { private _serializeRendererTypeV2(type: RendererTypeV2): {[key: string]: any} {
return { return {
'id': type.id, 'id': type.id,
'encapsulation': this.serialize(type.encapsulation, ViewEncapsulation), 'encapsulation': this.serialize(type.encapsulation),
'styles': this.serialize(type.styles, PRIMITIVE), 'styles': this.serialize(type.styles),
'data': this.serialize(type.data, PRIMITIVE), 'data': this.serialize(type.data),
}; };
} }
@ -131,12 +138,10 @@ export class Serializer {
return { return {
id: props['id'], id: props['id'],
encapsulation: props['encapsulation'], encapsulation: props['encapsulation'],
styles: this.deserialize(props['styles'], PRIMITIVE), styles: this.deserialize(props['styles']),
data: this.deserialize(props['data'], PRIMITIVE) data: this.deserialize(props['data'])
}; };
} }
} }
export const ANIMATION_WORKER_PLAYER_PREFIX = 'AnimationPlayer.'; export const ANIMATION_WORKER_PLAYER_PREFIX = 'AnimationPlayer.';
export class RenderStoreObject {}

View File

@ -9,9 +9,8 @@
import {Injectable, Type} from '@angular/core'; import {Injectable, Type} from '@angular/core';
import {EventEmitter} from '../../facade/async'; import {EventEmitter} from '../../facade/async';
import {isPresent} from '../../facade/lang';
import {MessageBus} from '../shared/message_bus'; import {MessageBus} from '../shared/message_bus';
import {Serializer} from '../shared/serializer'; import {Serializer, SerializerTypes} from '../shared/serializer';
/** /**
* @experimental WebWorker support in Angular is currently experimental. * @experimental WebWorker support in Angular is currently experimental.
@ -49,12 +48,13 @@ export class ServiceMessageBrokerFactory_ extends ServiceMessageBrokerFactory {
*/ */
export abstract class ServiceMessageBroker { export abstract class ServiceMessageBroker {
abstract registerMethod( abstract registerMethod(
methodName: string, signature: Type<any>[], method: Function, returnType?: Type<any>): void; methodName: string, signature: Array<Type<any>|SerializerTypes>, method: Function,
returnType?: Type<any>|SerializerTypes): void;
} }
export class ServiceMessageBroker_ extends ServiceMessageBroker { export class ServiceMessageBroker_ extends ServiceMessageBroker {
private _sink: EventEmitter<any>; private _sink: EventEmitter<any>;
private _methods: Map<string, Function> = new Map<string, Function>(); private _methods = new Map<string, Function>();
constructor(messageBus: MessageBus, private _serializer: Serializer, public channel: string) { constructor(messageBus: MessageBus, private _serializer: Serializer, public channel: string) {
super(); super();
@ -64,11 +64,11 @@ export class ServiceMessageBroker_ extends ServiceMessageBroker {
} }
registerMethod( registerMethod(
methodName: string, signature: Type<any>[], method: (..._: any[]) => Promise<any>| void, methodName: string, signature: Array<Type<any>|SerializerTypes>,
returnType?: Type<any>): void { method: (..._: any[]) => Promise<any>| void, returnType?: Type<any>|SerializerTypes): void {
this._methods.set(methodName, (message: ReceivedMessage) => { this._methods.set(methodName, (message: ReceivedMessage) => {
const serializedArgs = message.args; const serializedArgs = message.args;
const numArgs = signature === null ? 0 : signature.length; const numArgs = signature ? signature.length : 0;
const deserializedArgs = new Array(numArgs); const deserializedArgs = new Array(numArgs);
for (let i = 0; i < numArgs; i++) { for (let i = 0; i < numArgs; i++) {
const serializedArg = serializedArgs[i]; const serializedArg = serializedArgs[i];
@ -82,14 +82,14 @@ export class ServiceMessageBroker_ extends ServiceMessageBroker {
}); });
} }
private _handleMessage(map: {[key: string]: any}): void { private _handleMessage(message: ReceivedMessage): void {
const message = new ReceivedMessage(map);
if (this._methods.has(message.method)) { if (this._methods.has(message.method)) {
this._methods.get(message.method)(message); this._methods.get(message.method)(message);
} }
} }
private _wrapWebWorkerPromise(id: string, promise: Promise<any>, type: Type<any>): void { private _wrapWebWorkerPromise(id: string, promise: Promise<any>, type: Type<any>|SerializerTypes):
void {
promise.then((result: any) => { promise.then((result: any) => {
this._sink.emit({ this._sink.emit({
'type': 'result', 'type': 'result',
@ -103,16 +103,9 @@ export class ServiceMessageBroker_ extends ServiceMessageBroker {
/** /**
* @experimental WebWorker support in Angular is currently experimental. * @experimental WebWorker support in Angular is currently experimental.
*/ */
export class ReceivedMessage { export interface ReceivedMessage {
method: string; method: string;
args: any[]; args: any[];
id: string; id: string;
type: string; type: string;
constructor(data: {[key: string]: any}) {
this.method = data['method'];
this.args = data['args'];
this.id = data['id'];
this.type = data['type'];
}
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {EventEmitter} from '../../facade/async'; import {EventEmitter} from '../../facade/async';
import {RenderStoreObject, Serializer} from '../shared/serializer'; import {Serializer, SerializerTypes} from '../shared/serializer';
import {serializeEventWithTarget, serializeGenericEvent, serializeKeyboardEvent, serializeMouseEvent, serializeTransitionEvent} from './event_serializer'; import {serializeEventWithTarget, serializeGenericEvent, serializeKeyboardEvent, serializeMouseEvent, serializeTransitionEvent} from './event_serializer';
@ -15,8 +15,8 @@ export class EventDispatcher {
dispatchAnimationEvent(player: any, phaseName: string, element: any): boolean { dispatchAnimationEvent(player: any, phaseName: string, element: any): boolean {
this._sink.emit({ this._sink.emit({
'element': this._serializer.serialize(element, RenderStoreObject), 'element': this._serializer.serialize(element, SerializerTypes.RENDER_STORE_OBJECT),
'animationPlayer': this._serializer.serialize(player, RenderStoreObject), 'animationPlayer': this._serializer.serialize(player, SerializerTypes.RENDER_STORE_OBJECT),
'phaseName': phaseName, 'phaseName': phaseName,
}); });
return true; return true;
@ -107,7 +107,7 @@ export class EventDispatcher {
} }
this._sink.emit({ this._sink.emit({
'element': this._serializer.serialize(element, RenderStoreObject), 'element': this._serializer.serialize(element, SerializerTypes.RENDER_STORE_OBJECT),
'eventName': eventName, 'eventName': eventName,
'eventTarget': eventTarget, 'eventTarget': eventTarget,
'event': serializedEvent, 'event': serializedEvent,

View File

@ -13,8 +13,7 @@ import {EventEmitter} from '../../facade/async';
import {BrowserPlatformLocation} from '../../private_import_platform-browser'; import {BrowserPlatformLocation} from '../../private_import_platform-browser';
import {MessageBus} from '../shared/message_bus'; import {MessageBus} from '../shared/message_bus';
import {ROUTER_CHANNEL} from '../shared/messaging_api'; import {ROUTER_CHANNEL} from '../shared/messaging_api';
import {LocationType} from '../shared/serialized_types'; import {LocationType, Serializer, SerializerTypes} from '../shared/serializer';
import {PRIMITIVE, Serializer} from '../shared/serializer';
import {ServiceMessageBroker, ServiceMessageBrokerFactory} from '../shared/service_message_broker'; import {ServiceMessageBroker, ServiceMessageBrokerFactory} from '../shared/service_message_broker';
@Injectable() @Injectable()
@ -34,13 +33,14 @@ export class MessageBasedPlatformLocation {
} }
start(): void { start(): void {
const P = SerializerTypes.PRIMITIVE;
this._broker.registerMethod('getLocation', null, this._getLocation.bind(this), LocationType); this._broker.registerMethod('getLocation', null, this._getLocation.bind(this), LocationType);
this._broker.registerMethod('setPathname', [PRIMITIVE], this._setPathname.bind(this)); this._broker.registerMethod('setPathname', [P], this._setPathname.bind(this));
this._broker.registerMethod( this._broker.registerMethod(
'pushState', [PRIMITIVE, PRIMITIVE, PRIMITIVE], 'pushState', [P, P, P], this._platformLocation.pushState.bind(this._platformLocation));
this._platformLocation.pushState.bind(this._platformLocation));
this._broker.registerMethod( this._broker.registerMethod(
'replaceState', [PRIMITIVE, PRIMITIVE, PRIMITIVE], 'replaceState', [P, P, P],
this._platformLocation.replaceState.bind(this._platformLocation)); this._platformLocation.replaceState.bind(this._platformLocation));
this._broker.registerMethod( this._broker.registerMethod(
'forward', null, this._platformLocation.forward.bind(this._platformLocation)); 'forward', null, this._platformLocation.forward.bind(this._platformLocation));
@ -52,11 +52,11 @@ export class MessageBasedPlatformLocation {
return Promise.resolve(this._platformLocation.location); return Promise.resolve(this._platformLocation.location);
} }
private _sendUrlChangeEvent(e: Event): void { private _sendUrlChangeEvent(e: Event): void {
const loc = this._serializer.serialize(this._platformLocation.location, LocationType); this._channelSink.emit({
const serializedEvent = {'type': e.type}; 'event': {'type': e.type},
this._channelSink.emit({'event': serializedEvent, 'location': loc}); 'location': this._serializer.serialize(this._platformLocation.location, LocationType),
});
} }
private _setPathname(pathname: string): void { this._platformLocation.pathname = pathname; } private _setPathname(pathname: string): void { this._platformLocation.pathname = pathname; }

View File

@ -11,8 +11,7 @@ import {AnimationPlayer, Injectable, RenderComponentType, Renderer, RendererFact
import {MessageBus} from '../shared/message_bus'; import {MessageBus} from '../shared/message_bus';
import {EVENT_CHANNEL, EVENT_V2_CHANNEL, RENDERER_CHANNEL, RENDERER_V2_CHANNEL} from '../shared/messaging_api'; import {EVENT_CHANNEL, EVENT_V2_CHANNEL, RENDERER_CHANNEL, RENDERER_V2_CHANNEL} from '../shared/messaging_api';
import {RenderStore} from '../shared/render_store'; import {RenderStore} from '../shared/render_store';
import {SerializerTypes} from '../shared/serialized_types'; import {ANIMATION_WORKER_PLAYER_PREFIX, Serializer, SerializerTypes} from '../shared/serializer';
import {ANIMATION_WORKER_PLAYER_PREFIX, PRIMITIVE, RenderStoreObject, Serializer} from '../shared/serializer';
import {ServiceMessageBroker, ServiceMessageBrokerFactory} from '../shared/service_message_broker'; import {ServiceMessageBroker, ServiceMessageBrokerFactory} from '../shared/service_message_broker';
import {EventDispatcher} from '../ui/event_dispatcher'; import {EventDispatcher} from '../ui/event_dispatcher';
@ -31,7 +30,11 @@ export class MessageBasedRenderer {
this._bus.initChannel(EVENT_CHANNEL); this._bus.initChannel(EVENT_CHANNEL);
this._eventDispatcher = new EventDispatcher(this._bus.to(EVENT_CHANNEL), this._serializer); this._eventDispatcher = new EventDispatcher(this._bus.to(EVENT_CHANNEL), this._serializer);
const [RCT, RSO, P] = [RenderComponentType, RenderStoreObject, PRIMITIVE]; const [RCT, RSO, P] = [
RenderComponentType,
SerializerTypes.RENDER_STORE_OBJECT,
SerializerTypes.PRIMITIVE,
];
const methods: any[][] = [ const methods: any[][] = [
['renderComponent', this._renderComponent, RCT, P], ['renderComponent', this._renderComponent, RCT, P],
@ -65,52 +68,51 @@ export class MessageBasedRenderer {
} }
private _bindAnimationPlayerMethods(broker: ServiceMessageBroker) { private _bindAnimationPlayerMethods(broker: ServiceMessageBroker) {
const [P, RSO] = [SerializerTypes.PRIMITIVE, SerializerTypes.RENDER_STORE_OBJECT];
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'play', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'play', [RSO, RSO],
(player: AnimationPlayer, element: any) => player.play()); (player: AnimationPlayer, element: any) => player.play());
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'pause', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'pause', [RSO, RSO],
(player: AnimationPlayer, element: any) => player.pause()); (player: AnimationPlayer, element: any) => player.pause());
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'init', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'init', [RSO, RSO],
(player: AnimationPlayer, element: any) => player.init()); (player: AnimationPlayer, element: any) => player.init());
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'restart', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'restart', [RSO, RSO],
(player: AnimationPlayer, element: any) => player.restart()); (player: AnimationPlayer, element: any) => player.restart());
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'destroy', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'destroy', [RSO, RSO],
(player: AnimationPlayer, element: any) => { (player: AnimationPlayer, element: any) => {
player.destroy(); player.destroy();
this._renderStore.remove(player); this._renderStore.remove(player);
}); });
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'finish', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'finish', [RSO, RSO],
(player: AnimationPlayer, element: any) => player.finish()); (player: AnimationPlayer, element: any) => player.finish());
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'getPosition', [RenderStoreObject, RenderStoreObject], ANIMATION_WORKER_PLAYER_PREFIX + 'getPosition', [RSO, RSO],
(player: AnimationPlayer, element: any) => player.getPosition()); (player: AnimationPlayer, element: any) => player.getPosition());
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'onStart', ANIMATION_WORKER_PLAYER_PREFIX + 'onStart', [RSO, RSO, P],
[RenderStoreObject, RenderStoreObject, PRIMITIVE],
(player: AnimationPlayer, element: any) => (player: AnimationPlayer, element: any) =>
this._listenOnAnimationPlayer(player, element, 'onStart')); this._listenOnAnimationPlayer(player, element, 'onStart'));
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'onDone', ANIMATION_WORKER_PLAYER_PREFIX + 'onDone', [RSO, RSO, P],
[RenderStoreObject, RenderStoreObject, PRIMITIVE],
(player: AnimationPlayer, element: any) => (player: AnimationPlayer, element: any) =>
this._listenOnAnimationPlayer(player, element, 'onDone')); this._listenOnAnimationPlayer(player, element, 'onDone'));
broker.registerMethod( broker.registerMethod(
ANIMATION_WORKER_PLAYER_PREFIX + 'setPosition', ANIMATION_WORKER_PLAYER_PREFIX + 'setPosition', [RSO, RSO, P],
[RenderStoreObject, RenderStoreObject, PRIMITIVE],
(player: AnimationPlayer, element: any, position: number) => player.setPosition(position)); (player: AnimationPlayer, element: any, position: number) => player.setPosition(position));
} }
@ -254,7 +256,11 @@ export class MessageBasedRendererV2 {
this._bus.initChannel(EVENT_V2_CHANNEL); this._bus.initChannel(EVENT_V2_CHANNEL);
this._eventDispatcher = new EventDispatcher(this._bus.to(EVENT_V2_CHANNEL), this._serializer); this._eventDispatcher = new EventDispatcher(this._bus.to(EVENT_V2_CHANNEL), this._serializer);
const [RSO, P, CRT] = [RenderStoreObject, PRIMITIVE, SerializerTypes.RENDERER_TYPE_V2]; const [RSO, P, CRT] = [
SerializerTypes.RENDER_STORE_OBJECT,
SerializerTypes.PRIMITIVE,
SerializerTypes.RENDERER_TYPE_V2,
];
const methods: any[][] = [ const methods: any[][] = [
['createRenderer', this.createRenderer, RSO, CRT, P], ['createRenderer', this.createRenderer, RSO, CRT, P],

View File

@ -13,8 +13,7 @@ import {EventEmitter} from '../../facade/async';
import {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from '../shared/client_message_broker'; import {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from '../shared/client_message_broker';
import {MessageBus} from '../shared/message_bus'; import {MessageBus} from '../shared/message_bus';
import {ROUTER_CHANNEL} from '../shared/messaging_api'; import {ROUTER_CHANNEL} from '../shared/messaging_api';
import {LocationType} from '../shared/serialized_types'; import {LocationType, Serializer, SerializerTypes} from '../shared/serializer';
import {PRIMITIVE, Serializer} from '../shared/serializer';
@Injectable() @Injectable()
export class WebWorkerPlatformLocation extends PlatformLocation { export class WebWorkerPlatformLocation extends PlatformLocation {
@ -28,8 +27,8 @@ export class WebWorkerPlatformLocation extends PlatformLocation {
brokerFactory: ClientMessageBrokerFactory, bus: MessageBus, private _serializer: Serializer) { brokerFactory: ClientMessageBrokerFactory, bus: MessageBus, private _serializer: Serializer) {
super(); super();
this._broker = brokerFactory.createMessageBroker(ROUTER_CHANNEL); this._broker = brokerFactory.createMessageBroker(ROUTER_CHANNEL);
this._channelSource = bus.from(ROUTER_CHANNEL); this._channelSource = bus.from(ROUTER_CHANNEL);
this._channelSource.subscribe({ this._channelSource.subscribe({
next: (msg: {[key: string]: any}) => { next: (msg: {[key: string]: any}) => {
let listeners: Array<Function> = null; let listeners: Array<Function> = null;
@ -86,21 +85,27 @@ export class WebWorkerPlatformLocation extends PlatformLocation {
this._location.pathname = newPath; this._location.pathname = newPath;
const fnArgs = [new FnArg(newPath, PRIMITIVE)]; const fnArgs = [new FnArg(newPath, SerializerTypes.PRIMITIVE)];
const args = new UiArguments('setPathname', fnArgs); const args = new UiArguments('setPathname', fnArgs);
this._broker.runOnService(args, null); this._broker.runOnService(args, null);
} }
pushState(state: any, title: string, url: string): void { pushState(state: any, title: string, url: string): void {
const fnArgs = const fnArgs = [
[new FnArg(state, PRIMITIVE), new FnArg(title, PRIMITIVE), new FnArg(url, PRIMITIVE)]; new FnArg(state, SerializerTypes.PRIMITIVE),
new FnArg(title, SerializerTypes.PRIMITIVE),
new FnArg(url, SerializerTypes.PRIMITIVE),
];
const args = new UiArguments('pushState', fnArgs); const args = new UiArguments('pushState', fnArgs);
this._broker.runOnService(args, null); this._broker.runOnService(args, null);
} }
replaceState(state: any, title: string, url: string): void { replaceState(state: any, title: string, url: string): void {
const fnArgs = const fnArgs = [
[new FnArg(state, PRIMITIVE), new FnArg(title, PRIMITIVE), new FnArg(url, PRIMITIVE)]; new FnArg(state, SerializerTypes.PRIMITIVE),
new FnArg(title, SerializerTypes.PRIMITIVE),
new FnArg(url, SerializerTypes.PRIMITIVE),
];
const args = new UiArguments('replaceState', fnArgs); const args = new UiArguments('replaceState', fnArgs);
this._broker.runOnService(args, null); this._broker.runOnService(args, null);
} }

View File

@ -8,19 +8,50 @@
import {Injectable, RenderComponentType, Renderer, RendererFactoryV2, RendererTypeV2, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core'; import {Injectable, RenderComponentType, Renderer, RendererFactoryV2, RendererTypeV2, RendererV2, RootRenderer, ViewEncapsulation} from '@angular/core';
import {ListWrapper} from '../../facade/collection';
import {AnimationKeyframe, AnimationPlayer, AnimationStyles, RenderDebugInfo} from '../../private_import_core'; import {AnimationKeyframe, AnimationPlayer, AnimationStyles, RenderDebugInfo} from '../../private_import_core';
import {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from '../shared/client_message_broker'; import {ClientMessageBroker, ClientMessageBrokerFactory, FnArg, UiArguments} from '../shared/client_message_broker';
import {MessageBus} from '../shared/message_bus'; import {MessageBus} from '../shared/message_bus';
import {EVENT_CHANNEL, EVENT_V2_CHANNEL, RENDERER_CHANNEL, RENDERER_V2_CHANNEL} from '../shared/messaging_api'; import {EVENT_CHANNEL, EVENT_V2_CHANNEL, RENDERER_CHANNEL, RENDERER_V2_CHANNEL} from '../shared/messaging_api';
import {RenderStore} from '../shared/render_store'; import {RenderStore} from '../shared/render_store';
import {SerializerTypes} from '../shared/serialized_types'; import {ANIMATION_WORKER_PLAYER_PREFIX, Serializer, SerializerTypes} from '../shared/serializer';
import {ANIMATION_WORKER_PLAYER_PREFIX, RenderStoreObject, Serializer} from '../shared/serializer';
export class NamedEventEmitter {
private _listeners: Map<string, Function[]>;
listen(eventName: string, callback: Function) { this._getListeners(eventName).push(callback); }
unlisten(eventName: string, listener: Function) {
const listeners = this._getListeners(eventName);
const index = listeners.indexOf(listener);
if (index > -1) {
listeners.splice(index, 1);
}
}
dispatchEvent(eventName: string, event: any) {
const listeners = this._getListeners(eventName);
for (let i = 0; i < listeners.length; i++) {
listeners[i](event);
}
}
private _getListeners(eventName: string): Function[] {
if (!this._listeners) {
this._listeners = new Map<string, Function[]>();
}
let listeners = this._listeners.get(eventName);
if (!listeners) {
listeners = [];
this._listeners.set(eventName, listeners);
}
return listeners;
}
}
const globalEvents = new NamedEventEmitter();
@Injectable() @Injectable()
export class WebWorkerRootRenderer implements RootRenderer { export class WebWorkerRootRenderer implements RootRenderer {
globalEvents = new NamedEventEmitter();
private _messageBroker: ClientMessageBroker; private _messageBroker: ClientMessageBroker;
private _componentRenderers = new Map<string, WebWorkerRenderer>(); private _componentRenderers = new Map<string, WebWorkerRenderer>();
@ -34,20 +65,21 @@ export class WebWorkerRootRenderer implements RootRenderer {
} }
private _dispatchEvent(message: {[key: string]: any}): void { private _dispatchEvent(message: {[key: string]: any}): void {
const element = const element: WebWorkerRenderNode =
<WebWorkerRenderNode>this._serializer.deserialize(message['element'], RenderStoreObject); this._serializer.deserialize(message['element'], SerializerTypes.RENDER_STORE_OBJECT);
const playerData = message['animationPlayer']; const playerData = message['animationPlayer'];
if (playerData) { if (playerData) {
const phaseName = message['phaseName']; const phaseName = message['phaseName'];
const player = <AnimationPlayer>this._serializer.deserialize(playerData, RenderStoreObject); const player: AnimationPlayer =
this._serializer.deserialize(playerData, SerializerTypes.RENDER_STORE_OBJECT);
element.animationPlayerEvents.dispatchEvent(player, phaseName); element.animationPlayerEvents.dispatchEvent(player, phaseName);
} else { } else {
const eventName = message['eventName']; const eventName = message['eventName'];
const target = message['eventTarget']; const target = message['eventTarget'];
const event = message['event']; const event = message['event'];
if (target) { if (target) {
this.globalEvents.dispatchEvent(eventNameWithTarget(target, eventName), event); globalEvents.dispatchEvent(eventNameWithTarget(target, eventName), event);
} else { } else {
element.events.dispatchEvent(eventName, event); element.events.dispatchEvent(eventName, event);
} }
@ -63,7 +95,7 @@ export class WebWorkerRootRenderer implements RootRenderer {
this.renderStore.store(result, id); this.renderStore.store(result, id);
this.runOnService('renderComponent', [ this.runOnService('renderComponent', [
new FnArg(componentType, RenderComponentType), new FnArg(componentType, RenderComponentType),
new FnArg(result, RenderStoreObject), new FnArg(result, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
} }
return result; return result;
@ -90,27 +122,30 @@ export class WebWorkerRootRenderer implements RootRenderer {
} }
} }
export class WebWorkerRenderer implements Renderer, RenderStoreObject { export class WebWorkerRenderer implements Renderer {
constructor( constructor(
private _rootRenderer: WebWorkerRootRenderer, private _componentType: RenderComponentType) {} private _rootRenderer: WebWorkerRootRenderer, private _componentType: RenderComponentType) {}
private _runOnService(fnName: string, fnArgs: FnArg[]) { private _runOnService(fnName: string, fnArgs: FnArg[]) {
const fnArgsWithRenderer = [new FnArg(this, RenderStoreObject)].concat(fnArgs); const fnArgsWithRenderer = [new FnArg(this, SerializerTypes.RENDER_STORE_OBJECT), ...fnArgs];
this._rootRenderer.runOnService(fnName, fnArgsWithRenderer); this._rootRenderer.runOnService(fnName, fnArgsWithRenderer);
} }
selectRootElement(selectorOrNode: string, debugInfo?: RenderDebugInfo): any { selectRootElement(selectorOrNode: string, debugInfo?: RenderDebugInfo): any {
const node = this._rootRenderer.allocateNode(); const node = this._rootRenderer.allocateNode();
this._runOnService( this._runOnService('selectRootElement', [
'selectRootElement', [new FnArg(selectorOrNode, null), new FnArg(node, RenderStoreObject)]); new FnArg(selectorOrNode),
new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]);
return node; return node;
} }
createElement(parentElement: any, name: string, debugInfo?: RenderDebugInfo): any { createElement(parentElement: any, name: string, debugInfo?: RenderDebugInfo): any {
const node = this._rootRenderer.allocateNode(); const node = this._rootRenderer.allocateNode();
this._runOnService('createElement', [ this._runOnService('createElement', [
new FnArg(parentElement, RenderStoreObject), new FnArg(name, null), new FnArg(parentElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(node, RenderStoreObject) new FnArg(name),
new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return node; return node;
} }
@ -119,121 +154,139 @@ export class WebWorkerRenderer implements Renderer, RenderStoreObject {
const viewRoot = this._componentType.encapsulation === ViewEncapsulation.Native ? const viewRoot = this._componentType.encapsulation === ViewEncapsulation.Native ?
this._rootRenderer.allocateNode() : this._rootRenderer.allocateNode() :
hostElement; hostElement;
this._runOnService( this._runOnService('createViewRoot', [
'createViewRoot', new FnArg(hostElement, SerializerTypes.RENDER_STORE_OBJECT),
[new FnArg(hostElement, RenderStoreObject), new FnArg(viewRoot, RenderStoreObject)]); new FnArg(viewRoot, SerializerTypes.RENDER_STORE_OBJECT),
]);
return viewRoot; return viewRoot;
} }
createTemplateAnchor(parentElement: any, debugInfo?: RenderDebugInfo): any { createTemplateAnchor(parentElement: any, debugInfo?: RenderDebugInfo): any {
const node = this._rootRenderer.allocateNode(); const node = this._rootRenderer.allocateNode();
this._runOnService( this._runOnService('createTemplateAnchor', [
'createTemplateAnchor', new FnArg(parentElement, SerializerTypes.RENDER_STORE_OBJECT),
[new FnArg(parentElement, RenderStoreObject), new FnArg(node, RenderStoreObject)]); new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]);
return node; return node;
} }
createText(parentElement: any, value: string, debugInfo?: RenderDebugInfo): any { createText(parentElement: any, value: string, debugInfo?: RenderDebugInfo): any {
const node = this._rootRenderer.allocateNode(); const node = this._rootRenderer.allocateNode();
this._runOnService('createText', [ this._runOnService('createText', [
new FnArg(parentElement, RenderStoreObject), new FnArg(value, null), new FnArg(parentElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(node, RenderStoreObject) new FnArg(value),
new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return node; return node;
} }
projectNodes(parentElement: any, nodes: any[]) { projectNodes(parentElement: any, nodes: any[]) {
this._runOnService( this._runOnService('projectNodes', [
'projectNodes', new FnArg(parentElement, SerializerTypes.RENDER_STORE_OBJECT),
[new FnArg(parentElement, RenderStoreObject), new FnArg(nodes, RenderStoreObject)]); new FnArg(nodes, SerializerTypes.RENDER_STORE_OBJECT),
]);
} }
attachViewAfter(node: any, viewRootNodes: any[]) { attachViewAfter(node: any, viewRootNodes: any[]) {
this._runOnService( this._runOnService('attachViewAfter', [
'attachViewAfter', new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
[new FnArg(node, RenderStoreObject), new FnArg(viewRootNodes, RenderStoreObject)]); new FnArg(viewRootNodes, SerializerTypes.RENDER_STORE_OBJECT),
]);
} }
detachView(viewRootNodes: any[]) { detachView(viewRootNodes: any[]) {
this._runOnService('detachView', [new FnArg(viewRootNodes, RenderStoreObject)]); this._runOnService(
'detachView', [new FnArg(viewRootNodes, SerializerTypes.RENDER_STORE_OBJECT)]);
} }
destroyView(hostElement: any, viewAllNodes: any[]) { destroyView(hostElement: any, viewAllNodes: any[]) {
this._runOnService( this._runOnService('destroyView', [
'destroyView', new FnArg(hostElement, SerializerTypes.RENDER_STORE_OBJECT),
[new FnArg(hostElement, RenderStoreObject), new FnArg(viewAllNodes, RenderStoreObject)]); new FnArg(viewAllNodes, SerializerTypes.RENDER_STORE_OBJECT),
]);
this._rootRenderer.destroyNodes(viewAllNodes); this._rootRenderer.destroyNodes(viewAllNodes);
} }
setElementProperty(renderElement: any, propertyName: string, propertyValue: any) { setElementProperty(renderElement: any, propertyName: string, propertyValue: any) {
this._runOnService('setElementProperty', [ this._runOnService('setElementProperty', [
new FnArg(renderElement, RenderStoreObject), new FnArg(propertyName, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(propertyValue, null) new FnArg(propertyName),
new FnArg(propertyValue),
]); ]);
} }
setElementAttribute(renderElement: any, attributeName: string, attributeValue: string) { setElementAttribute(renderElement: any, attributeName: string, attributeValue: string) {
this._runOnService('setElementAttribute', [ this._runOnService('setElementAttribute', [
new FnArg(renderElement, RenderStoreObject), new FnArg(attributeName, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(attributeValue, null) new FnArg(attributeName),
new FnArg(attributeValue),
]); ]);
} }
setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string) { setBindingDebugInfo(renderElement: any, propertyName: string, propertyValue: string) {
this._runOnService('setBindingDebugInfo', [ this._runOnService('setBindingDebugInfo', [
new FnArg(renderElement, RenderStoreObject), new FnArg(propertyName, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(propertyValue, null) new FnArg(propertyName),
new FnArg(propertyValue),
]); ]);
} }
setElementClass(renderElement: any, className: string, isAdd: boolean) { setElementClass(renderElement: any, className: string, isAdd: boolean) {
this._runOnService('setElementClass', [ this._runOnService('setElementClass', [
new FnArg(renderElement, RenderStoreObject), new FnArg(className, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(isAdd, null) new FnArg(className),
new FnArg(isAdd),
]); ]);
} }
setElementStyle(renderElement: any, styleName: string, styleValue: string) { setElementStyle(renderElement: any, styleName: string, styleValue: string) {
this._runOnService('setElementStyle', [ this._runOnService('setElementStyle', [
new FnArg(renderElement, RenderStoreObject), new FnArg(styleName, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(styleValue, null) new FnArg(styleName),
new FnArg(styleValue),
]); ]);
} }
invokeElementMethod(renderElement: any, methodName: string, args?: any[]) { invokeElementMethod(renderElement: any, methodName: string, args?: any[]) {
this._runOnService('invokeElementMethod', [ this._runOnService('invokeElementMethod', [
new FnArg(renderElement, RenderStoreObject), new FnArg(methodName, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(args, null) new FnArg(methodName),
new FnArg(args),
]); ]);
} }
setText(renderNode: any, text: string) { setText(renderNode: any, text: string) {
this._runOnService( this._runOnService('setText', [
'setText', [new FnArg(renderNode, RenderStoreObject), new FnArg(text, null)]); new FnArg(renderNode, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(text),
]);
} }
listen(renderElement: WebWorkerRenderNode, name: string, callback: Function): Function { listen(renderElement: WebWorkerRenderNode, name: string, callback: Function): Function {
renderElement.events.listen(name, callback); renderElement.events.listen(name, callback);
const unlistenCallbackId = this._rootRenderer.allocateId(); const unlistenCallbackId = this._rootRenderer.allocateId();
this._runOnService('listen', [ this._runOnService('listen', [
new FnArg(renderElement, RenderStoreObject), new FnArg(name, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(unlistenCallbackId, null) new FnArg(name),
new FnArg(unlistenCallbackId),
]); ]);
return () => { return () => {
renderElement.events.unlisten(name, callback); renderElement.events.unlisten(name, callback);
this._runOnService('listenDone', [new FnArg(unlistenCallbackId, null)]); this._runOnService('listenDone', [new FnArg(unlistenCallbackId)]);
}; };
} }
listenGlobal(target: string, name: string, callback: Function): Function { listenGlobal(target: string, name: string, callback: Function): Function {
this._rootRenderer.globalEvents.listen(eventNameWithTarget(target, name), callback); globalEvents.listen(eventNameWithTarget(target, name), callback);
const unlistenCallbackId = this._rootRenderer.allocateId(); const unlistenCallbackId = this._rootRenderer.allocateId();
this._runOnService( this._runOnService('listenGlobal', [
'listenGlobal', new FnArg(target),
[new FnArg(target, null), new FnArg(name, null), new FnArg(unlistenCallbackId, null)]); new FnArg(name, null),
new FnArg(unlistenCallbackId),
]);
return () => { return () => {
this._rootRenderer.globalEvents.unlisten(eventNameWithTarget(target, name), callback); globalEvents.unlisten(eventNameWithTarget(target, name), callback);
this._runOnService('listenDone', [new FnArg(unlistenCallbackId, null)]); this._runOnService('listenDone', [new FnArg(unlistenCallbackId)]);
}; };
} }
@ -246,9 +299,14 @@ export class WebWorkerRenderer implements Renderer, RenderStoreObject {
previousPlayers.map(player => this._rootRenderer.renderStore.serialize(player)); previousPlayers.map(player => this._rootRenderer.renderStore.serialize(player));
this._runOnService('animate', [ this._runOnService('animate', [
new FnArg(renderElement, RenderStoreObject), new FnArg(startingStyles, null), new FnArg(renderElement, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(keyframes, null), new FnArg(duration, null), new FnArg(delay, null), new FnArg(startingStyles),
new FnArg(easing, null), new FnArg(previousPlayerIds, null), new FnArg(playerId, null) new FnArg(keyframes),
new FnArg(duration),
new FnArg(delay),
new FnArg(easing),
new FnArg(previousPlayerIds),
new FnArg(playerId),
]); ]);
const player = new _AnimationWorkerRendererPlayer(this._rootRenderer, renderElement); const player = new _AnimationWorkerRendererPlayer(this._rootRenderer, renderElement);
@ -262,37 +320,6 @@ function eventNameWithTarget(target: string, eventName: string): string {
return `${target}:${eventName}`; return `${target}:${eventName}`;
} }
export class NamedEventEmitter {
private _listeners: Map<string, Function[]>;
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) {
const listeners = this._getListeners(eventName);
for (let i = 0; i < listeners.length; i++) {
listeners[i](event);
}
}
private _getListeners(eventName: string): Function[] {
if (!this._listeners) {
this._listeners = new Map<string, Function[]>();
}
let listeners = this._listeners.get(eventName);
if (!listeners) {
listeners = [];
this._listeners.set(eventName, listeners);
}
return listeners;
}
}
const globalEvents = new NamedEventEmitter();
@Injectable() @Injectable()
export class WebWorkerRendererFactoryV2 implements RendererFactoryV2 { export class WebWorkerRendererFactoryV2 implements RendererFactoryV2 {
private _messageBroker: ClientMessageBroker; private _messageBroker: ClientMessageBroker;
@ -312,9 +339,9 @@ export class WebWorkerRendererFactoryV2 implements RendererFactoryV2 {
const id = this.renderStore.allocateId(); const id = this.renderStore.allocateId();
this.renderStore.store(renderer, id); this.renderStore.store(renderer, id);
this.callUI('createRenderer', [ this.callUI('createRenderer', [
new FnArg(element, RenderStoreObject), new FnArg(element, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(type, SerializerTypes.RENDERER_TYPE_V2), new FnArg(type, SerializerTypes.RENDERER_TYPE_V2),
new FnArg(renderer, RenderStoreObject), new FnArg(renderer, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return renderer; return renderer;
@ -336,7 +363,7 @@ export class WebWorkerRendererFactoryV2 implements RendererFactoryV2 {
private _dispatchEvent(message: {[key: string]: any}): void { private _dispatchEvent(message: {[key: string]: any}): void {
const element: WebWorkerRenderNode = const element: WebWorkerRenderNode =
this._serializer.deserialize(message['element'], RenderStoreObject); this._serializer.deserialize(message['element'], SerializerTypes.RENDER_STORE_OBJECT);
const eventName = message['eventName']; const eventName = message['eventName'];
const target = message['eventTarget']; const target = message['eventTarget'];
@ -355,7 +382,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
constructor(private _rendererFactory: WebWorkerRendererFactoryV2) {} constructor(private _rendererFactory: WebWorkerRendererFactoryV2) {}
destroyNode: (node: any) => void | null = null; destroyNode: (node: any) => void | null = null;
private asFnArg = new FnArg(this, RenderStoreObject); private asFnArg = new FnArg(this, SerializerTypes.RENDER_STORE_OBJECT);
// TODO(vicb): destroy the allocated nodes // TODO(vicb): destroy the allocated nodes
destroy(): void { this.callUIWithRenderer('destroy'); } destroy(): void { this.callUIWithRenderer('destroy'); }
@ -365,7 +392,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
this.callUIWithRenderer('createElement', [ this.callUIWithRenderer('createElement', [
new FnArg(name), new FnArg(name),
new FnArg(namespace), new FnArg(namespace),
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return node; return node;
} }
@ -374,7 +401,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
const node = this._rendererFactory.allocateNode(); const node = this._rendererFactory.allocateNode();
this.callUIWithRenderer('createComment', [ this.callUIWithRenderer('createComment', [
new FnArg(value), new FnArg(value),
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return node; return node;
} }
@ -383,15 +410,15 @@ export class WebWorkerRendererV2 implements RendererV2 {
const node = this._rendererFactory.allocateNode(); const node = this._rendererFactory.allocateNode();
this.callUIWithRenderer('createText', [ this.callUIWithRenderer('createText', [
new FnArg(value), new FnArg(value),
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return node; return node;
} }
appendChild(parent: any, newChild: any): void { appendChild(parent: any, newChild: any): void {
this.callUIWithRenderer('appendChild', [ this.callUIWithRenderer('appendChild', [
new FnArg(parent, RenderStoreObject), new FnArg(parent, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(newChild, RenderStoreObject), new FnArg(newChild, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
} }
@ -401,16 +428,16 @@ export class WebWorkerRendererV2 implements RendererV2 {
} }
this.callUIWithRenderer('insertBefore', [ this.callUIWithRenderer('insertBefore', [
new FnArg(parent, RenderStoreObject), new FnArg(parent, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(newChild, RenderStoreObject), new FnArg(newChild, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(refChild, RenderStoreObject), new FnArg(refChild, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
} }
removeChild(parent: any, oldChild: any): void { removeChild(parent: any, oldChild: any): void {
this.callUIWithRenderer('removeChild', [ this.callUIWithRenderer('removeChild', [
new FnArg(parent, RenderStoreObject), new FnArg(parent, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(oldChild, RenderStoreObject), new FnArg(oldChild, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
} }
@ -418,7 +445,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
const node = this._rendererFactory.allocateNode(); const node = this._rendererFactory.allocateNode();
this.callUIWithRenderer('selectRootElement', [ this.callUIWithRenderer('selectRootElement', [
new FnArg(selectorOrNode), new FnArg(selectorOrNode),
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return node; return node;
} }
@ -426,8 +453,8 @@ export class WebWorkerRendererV2 implements RendererV2 {
parentNode(node: any): any { parentNode(node: any): any {
const res = this._rendererFactory.allocateNode(); const res = this._rendererFactory.allocateNode();
this.callUIWithRenderer('parentNode', [ this.callUIWithRenderer('parentNode', [
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(res, RenderStoreObject), new FnArg(res, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return res; return res;
} }
@ -435,15 +462,15 @@ export class WebWorkerRendererV2 implements RendererV2 {
nextSibling(node: any): any { nextSibling(node: any): any {
const res = this._rendererFactory.allocateNode(); const res = this._rendererFactory.allocateNode();
this.callUIWithRenderer('nextSibling', [ this.callUIWithRenderer('nextSibling', [
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(res, RenderStoreObject), new FnArg(res, SerializerTypes.RENDER_STORE_OBJECT),
]); ]);
return res; return res;
} }
setAttribute(el: any, name: string, value: string, namespace?: string): void { setAttribute(el: any, name: string, value: string, namespace?: string): void {
this.callUIWithRenderer('setAttribute', [ this.callUIWithRenderer('setAttribute', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(name), new FnArg(name),
new FnArg(value), new FnArg(value),
new FnArg(namespace), new FnArg(namespace),
@ -452,7 +479,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
removeAttribute(el: any, name: string, namespace?: string): void { removeAttribute(el: any, name: string, namespace?: string): void {
this.callUIWithRenderer('removeAttribute', [ this.callUIWithRenderer('removeAttribute', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(name), new FnArg(name),
new FnArg(namespace), new FnArg(namespace),
]); ]);
@ -460,14 +487,14 @@ export class WebWorkerRendererV2 implements RendererV2 {
addClass(el: any, name: string): void { addClass(el: any, name: string): void {
this.callUIWithRenderer('addClass', [ this.callUIWithRenderer('addClass', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(name), new FnArg(name),
]); ]);
} }
removeClass(el: any, name: string): void { removeClass(el: any, name: string): void {
this.callUIWithRenderer('removeClass', [ this.callUIWithRenderer('removeClass', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(name), new FnArg(name),
]); ]);
} }
@ -475,7 +502,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean): setStyle(el: any, style: string, value: any, hasVendorPrefix: boolean, hasImportant: boolean):
void { void {
this.callUIWithRenderer('setStyle', [ this.callUIWithRenderer('setStyle', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(style), new FnArg(style),
new FnArg(value), new FnArg(value),
new FnArg(hasVendorPrefix), new FnArg(hasVendorPrefix),
@ -485,7 +512,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
removeStyle(el: any, style: string, hasVendorPrefix: boolean): void { removeStyle(el: any, style: string, hasVendorPrefix: boolean): void {
this.callUIWithRenderer('removeStyle', [ this.callUIWithRenderer('removeStyle', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(style), new FnArg(style),
new FnArg(hasVendorPrefix), new FnArg(hasVendorPrefix),
]); ]);
@ -493,7 +520,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
setProperty(el: any, name: string, value: any): void { setProperty(el: any, name: string, value: any): void {
this.callUIWithRenderer('setProperty', [ this.callUIWithRenderer('setProperty', [
new FnArg(el, RenderStoreObject), new FnArg(el, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(name), new FnArg(name),
new FnArg(value), new FnArg(value),
]); ]);
@ -501,7 +528,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
setValue(node: any, value: string): void { setValue(node: any, value: string): void {
this.callUIWithRenderer('setValue', [ this.callUIWithRenderer('setValue', [
new FnArg(node, RenderStoreObject), new FnArg(node, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(value), new FnArg(value),
]); ]);
} }
@ -522,7 +549,7 @@ export class WebWorkerRendererV2 implements RendererV2 {
} }
this.callUIWithRenderer('listen', [ this.callUIWithRenderer('listen', [
new FnArg(targetEl, RenderStoreObject), new FnArg(targetEl, SerializerTypes.RENDER_STORE_OBJECT),
new FnArg(targetName), new FnArg(targetName),
new FnArg(eventName), new FnArg(eventName),
new FnArg(unlistenId), new FnArg(unlistenId),
@ -581,7 +608,7 @@ export class WebWorkerRenderNode {
animationPlayerEvents = new AnimationPlayerEmitter(); animationPlayerEvents = new AnimationPlayerEmitter();
} }
class _AnimationWorkerRendererPlayer implements RenderStoreObject { class _AnimationWorkerRendererPlayer {
public parentPlayer: AnimationPlayer = null; public parentPlayer: AnimationPlayer = null;
private _destroyed: boolean = false; private _destroyed: boolean = false;
@ -592,8 +619,9 @@ class _AnimationWorkerRendererPlayer implements RenderStoreObject {
private _runOnService(fnName: string, fnArgs: FnArg[]) { private _runOnService(fnName: string, fnArgs: FnArg[]) {
if (!this._destroyed) { if (!this._destroyed) {
const fnArgsWithRenderer = [ const fnArgsWithRenderer = [
new FnArg(this, RenderStoreObject), new FnArg(this._renderElement, RenderStoreObject) new FnArg(this, SerializerTypes.RENDER_STORE_OBJECT),
].concat(fnArgs); new FnArg(this._renderElement, SerializerTypes.RENDER_STORE_OBJECT), ...fnArgs
];
this._rootRenderer.runOnService(ANIMATION_WORKER_PLAYER_PREFIX + fnName, fnArgsWithRenderer); this._rootRenderer.runOnService(ANIMATION_WORKER_PLAYER_PREFIX + fnName, fnArgsWithRenderer);
} }
} }
@ -639,7 +667,7 @@ class _AnimationWorkerRendererPlayer implements RenderStoreObject {
reset(): void { this._runOnService('reset', []); } reset(): void { this._runOnService('reset', []); }
setPosition(p: number): void { this._runOnService('setPosition', [new FnArg(p, null)]); } setPosition(p: number): void { this._runOnService('setPosition', [new FnArg(p)]); }
getPosition(): number { return 0; } getPosition(): number { return 0; }
} }

View File

@ -9,10 +9,9 @@
import {beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/testing_internal'; import {beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
import {ON_WEB_WORKER} from '@angular/platform-webworker/src/web_workers/shared/api'; import {ON_WEB_WORKER} from '@angular/platform-webworker/src/web_workers/shared/api';
import {RenderStore} from '@angular/platform-webworker/src/web_workers/shared/render_store'; import {RenderStore} from '@angular/platform-webworker/src/web_workers/shared/render_store';
import {PRIMITIVE, Serializer} from '@angular/platform-webworker/src/web_workers/shared/serializer'; import {Serializer, SerializerTypes} from '@angular/platform-webworker/src/web_workers/shared/serializer';
import {ServiceMessageBroker_} from '@angular/platform-webworker/src/web_workers/shared/service_message_broker'; import {ServiceMessageBroker_} from '@angular/platform-webworker/src/web_workers/shared/service_message_broker';
import {createPairedMessageBuses} from './web_worker_test_util'; import {createPairedMessageBuses} from './web_worker_test_util';
export function main() { export function main() {
@ -36,17 +35,20 @@ export function main() {
it('should call registered method with correct arguments', it('should call registered method with correct arguments',
inject([Serializer], (serializer: Serializer) => { inject([Serializer], (serializer: Serializer) => {
const broker = new ServiceMessageBroker_(messageBuses.ui, serializer, CHANNEL); const broker = new ServiceMessageBroker_(messageBuses.ui, serializer, CHANNEL);
broker.registerMethod(TEST_METHOD, [PRIMITIVE, PRIMITIVE], (arg1, arg2) => { broker.registerMethod(
expect(arg1).toEqual(PASSED_ARG_1); TEST_METHOD, [SerializerTypes.PRIMITIVE, SerializerTypes.PRIMITIVE], (arg1, arg2) => {
expect(arg2).toEqual(PASSED_ARG_2); expect(arg1).toEqual(PASSED_ARG_1);
expect(arg2).toEqual(PASSED_ARG_2);
});
messageBuses.worker.to(CHANNEL).emit({
'method': TEST_METHOD,
'args': [PASSED_ARG_1, PASSED_ARG_2],
}); });
messageBuses.worker.to(CHANNEL).emit(
{'method': TEST_METHOD, 'args': [PASSED_ARG_1, PASSED_ARG_2]});
})); }));
it('should return promises to the worker', inject([Serializer], (serializer: Serializer) => { it('should return promises to the worker', inject([Serializer], (serializer: Serializer) => {
const broker = new ServiceMessageBroker_(messageBuses.ui, serializer, CHANNEL); const broker = new ServiceMessageBroker_(messageBuses.ui, serializer, CHANNEL);
broker.registerMethod(TEST_METHOD, [PRIMITIVE], (arg1) => { broker.registerMethod(TEST_METHOD, [SerializerTypes.PRIMITIVE], (arg1) => {
expect(arg1).toEqual(PASSED_ARG_1); expect(arg1).toEqual(PASSED_ARG_1);
return new Promise((res, rej) => { return new Promise((res, rej) => {
try { try {

View File

@ -9,7 +9,7 @@
import {Type} from '@angular/core'; import {Type} from '@angular/core';
import {UiArguments} from '@angular/platform-webworker/src/web_workers/shared/client_message_broker'; import {UiArguments} from '@angular/platform-webworker/src/web_workers/shared/client_message_broker';
import {MessageBus} from '@angular/platform-webworker/src/web_workers/shared/message_bus'; import {MessageBus} from '@angular/platform-webworker/src/web_workers/shared/message_bus';
import {LocationType} from '@angular/platform-webworker/src/web_workers/shared/serialized_types'; import {LocationType, SerializerTypes} from '@angular/platform-webworker/src/web_workers/shared/serializer';
import {WebWorkerPlatformLocation} from '@angular/platform-webworker/src/web_workers/worker/platform_location'; import {WebWorkerPlatformLocation} from '@angular/platform-webworker/src/web_workers/worker/platform_location';
import {MockMessageBrokerFactory, createPairedMessageBuses, expectBrokerCall} from '../shared/web_worker_test_util'; import {MockMessageBrokerFactory, createPairedMessageBuses, expectBrokerCall} from '../shared/web_worker_test_util';
@ -21,17 +21,19 @@ export function main() {
let uiBus: MessageBus = null; let uiBus: MessageBus = null;
let workerBus: MessageBus = null; let workerBus: MessageBus = null;
let broker: any = null; let broker: any = null;
const TEST_LOCATION = new LocationType( const TEST_LOCATION = new LocationType(
'http://www.example.com', 'http', 'example.com', 'example.com', '80', '/', '', '', 'http://www.example.com', 'http', 'example.com', 'example.com', '80', '/', '', '',
'http://www.example.com'); 'http://www.example.com');
function createWebWorkerPlatformLocation(loc: LocationType): WebWorkerPlatformLocation { function createWebWorkerPlatformLocation(loc: LocationType): WebWorkerPlatformLocation {
broker.spy('runOnService').and.callFake((args: UiArguments, returnType: Type<any>) => { broker.spy('runOnService')
if (args.method === 'getLocation') { .and.callFake((args: UiArguments, returnType: Type<any>| SerializerTypes) => {
return Promise.resolve(loc); if (args.method === 'getLocation') {
} return Promise.resolve(loc);
}); }
});
const factory = new MockMessageBrokerFactory(broker); const factory = new MockMessageBrokerFactory(broker);
return new WebWorkerPlatformLocation(factory, workerBus, null); return new WebWorkerPlatformLocation(factory, workerBus, null);
} }

View File

@ -7,7 +7,7 @@
*/ */
import {PlatformRef} from '@angular/core'; import {PlatformRef} from '@angular/core';
import {ClientMessageBrokerFactory, FnArg, PRIMITIVE, UiArguments, bootstrapWorkerUi} from '@angular/platform-webworker'; import {ClientMessageBrokerFactory, FnArg, SerializerTypes, UiArguments, bootstrapWorkerUi} from '@angular/platform-webworker';
const ECHO_CHANNEL = 'ECHO'; const ECHO_CHANNEL = 'ECHO';
@ -23,14 +23,10 @@ function afterBootstrap(ref: PlatformRef) {
const val = (<HTMLInputElement>document.getElementById('echo_input')).value; const val = (<HTMLInputElement>document.getElementById('echo_input')).value;
// TODO(jteplitz602): Replace default constructors with real constructors // TODO(jteplitz602): Replace default constructors with real constructors
// once they're in the .d.ts file (#3926) // once they're in the .d.ts file (#3926)
const args = new UiArguments('echo'); const fnArg = new FnArg(val);
args.method = 'echo'; const args = new UiArguments('echo', [fnArg]);
const fnArg = new FnArg(val, PRIMITIVE);
fnArg.value = val;
fnArg.type = PRIMITIVE;
args.args = [fnArg];
broker.runOnService(args, PRIMITIVE).then((echo_result: string) => { broker.runOnService(args, SerializerTypes.PRIMITIVE).then((echo_result: string) => {
document.getElementById('echo_result').innerHTML = document.getElementById('echo_result').innerHTML =
`<span class='response'>${echo_result}</span>`; `<span class='response'>${echo_result}</span>`;
}); });

View File

@ -7,7 +7,7 @@
*/ */
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {PRIMITIVE, ServiceMessageBrokerFactory} from '@angular/platform-webworker'; import {SerializerTypes, ServiceMessageBrokerFactory} from '@angular/platform-webworker';
const ECHO_CHANNEL = 'ECHO'; const ECHO_CHANNEL = 'ECHO';
@ -15,16 +15,9 @@ const ECHO_CHANNEL = 'ECHO';
export class App { export class App {
constructor(private _serviceBrokerFactory: ServiceMessageBrokerFactory) { constructor(private _serviceBrokerFactory: ServiceMessageBrokerFactory) {
const broker = _serviceBrokerFactory.createMessageBroker(ECHO_CHANNEL, false); const broker = _serviceBrokerFactory.createMessageBroker(ECHO_CHANNEL, false);
broker.registerMethod('echo', [PRIMITIVE], this._echo, PRIMITIVE); broker.registerMethod(
'echo', [SerializerTypes.PRIMITIVE], this._echo, SerializerTypes.PRIMITIVE);
} }
private _echo(val: string) { private _echo(val: string) { return new Promise((res) => res(val)); }
return new Promise((res, rej) => {
try {
res(val);
} catch (e) {
rej(e);
}
});
}
} }

View File

@ -3,7 +3,7 @@ export declare function bootstrapWorkerUi(workerScriptUri: string, customProvide
/** @experimental */ /** @experimental */
export declare abstract class ClientMessageBroker { export declare abstract class ClientMessageBroker {
abstract runOnService(args: UiArguments, returnType: Type<any>): Promise<any>; abstract runOnService(args: UiArguments, returnType: Type<any> | SerializerTypes): Promise<any>;
} }
/** @experimental */ /** @experimental */
@ -50,24 +50,23 @@ export declare const platformWorkerUi: (extraProviders?: Provider[]) => Platform
export declare const PRIMITIVE: Type<any>; export declare const PRIMITIVE: Type<any>;
/** @experimental */ /** @experimental */
export declare class ReceivedMessage { export interface ReceivedMessage {
args: any[]; args: any[];
id: string; id: string;
method: string; method: string;
type: string; type: string;
constructor(data: {
[key: string]: any;
});
} }
/** @experimental */ /** @experimental */
export declare const enum SerializerTypes { export declare const enum SerializerTypes {
RENDERER_TYPE_V2 = 0, RENDERER_TYPE_V2 = 0,
PRIMITIVE = 1,
RENDER_STORE_OBJECT = 2,
} }
/** @experimental */ /** @experimental */
export declare abstract class ServiceMessageBroker { export declare abstract class ServiceMessageBroker {
abstract registerMethod(methodName: string, signature: Type<any>[], method: Function, returnType?: Type<any>): void; abstract registerMethod(methodName: string, signature: Array<Type<any> | SerializerTypes>, method: Function, returnType?: Type<any> | SerializerTypes): void;
} }
/** @experimental */ /** @experimental */