Skip to content

Commit c5cb700

Browse files
committed
feat(WebWorkers): Add WebWorker Todo Example. Add support for more DOM events.
Fixed breakage caused by previous DI commit in WebWorker Todo example
1 parent adc2739 commit c5cb700

33 files changed

+919
-27
lines changed

modules/angular2/src/web-workers/shared/serializer.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import {
2828
RenderFragmentRef,
2929
RenderElementRef,
3030
ViewType,
31-
ViewEncapsulation
31+
ViewEncapsulation,
32+
PropertyBindingType
3233
} from "angular2/src/render/api";
3334
import {WorkerElementRef} from 'angular2/src/web-workers/shared/api';
3435
import {AST, ASTWithSource} from 'angular2/src/change_detection/change_detection';
@@ -57,6 +58,13 @@ export class Serializer {
5758
viewEncapsulationMap[1] = ViewEncapsulation.NATIVE;
5859
viewEncapsulationMap[2] = ViewEncapsulation.NONE;
5960
this._enumRegistry.set(ViewEncapsulation, viewEncapsulationMap);
61+
62+
var propertyBindingTypeMap = new Map<int, any>();
63+
propertyBindingTypeMap[0] = PropertyBindingType.PROPERTY;
64+
propertyBindingTypeMap[1] = PropertyBindingType.ATTRIBUTE;
65+
propertyBindingTypeMap[2] = PropertyBindingType.CLASS;
66+
propertyBindingTypeMap[3] = PropertyBindingType.STYLE;
67+
this._enumRegistry.set(PropertyBindingType, propertyBindingTypeMap);
6068
}
6169

6270
serialize(obj: any, type: Type): Object {
@@ -93,6 +101,8 @@ export class Serializer {
93101
return this._renderViewStore.serializeRenderFragmentRef(obj);
94102
} else if (type == WorkerElementRef) {
95103
return this._serializeWorkerElementRef(obj);
104+
} else if (type == ElementPropertyBinding) {
105+
return this._serializeElementPropertyBinding(obj);
96106
} else if (type == EventBinding) {
97107
return this._serializeEventBinding(obj);
98108
} else {
@@ -137,6 +147,8 @@ export class Serializer {
137147
return this._deserializeWorkerElementRef(map);
138148
} else if (type == EventBinding) {
139149
return this._deserializeEventBinding(map);
150+
} else if (type == ElementPropertyBinding) {
151+
return this._deserializeElementPropertyBinding(map);
140152
} else {
141153
throw new BaseException("No deserializer for " + type.toString());
142154
}
@@ -165,7 +177,7 @@ export class Serializer {
165177
if (isPresent(type)) {
166178
var map: Map<string, any> = new Map();
167179
StringMapWrapper.forEach(obj,
168-
(key, val) => { map.set(key, this.deserialize(val, type, data)); });
180+
(val, key) => { map.set(key, this.deserialize(val, type, data)); });
169181
return map;
170182
} else {
171183
return MapWrapper.createFromStringMap(obj);
@@ -174,13 +186,29 @@ export class Serializer {
174186

175187
allocateRenderViews(fragmentCount: number) { this._renderViewStore.allocate(fragmentCount); }
176188

189+
private _serializeElementPropertyBinding(binding:
190+
ElementPropertyBinding): StringMap<string, any> {
191+
return {
192+
'type': serializeEnum(binding.type),
193+
'astWithSource': this.serialize(binding.astWithSource, ASTWithSource),
194+
'property': binding.property,
195+
'unit': binding.unit
196+
};
197+
}
198+
199+
private _deserializeElementPropertyBinding(map: StringMap<string, any>): ElementPropertyBinding {
200+
var type = deserializeEnum(map['type'], this._enumRegistry.get(PropertyBindingType));
201+
var ast = this.deserialize(map['astWithSource'], ASTWithSource, "binding");
202+
return new ElementPropertyBinding(type, ast, map['property'], map['unit']);
203+
}
204+
177205
private _serializeEventBinding(binding: EventBinding): StringMap<string, any> {
178206
return {'fullName': binding.fullName, 'source': this.serialize(binding.source, ASTWithSource)};
179207
}
180208

181209
private _deserializeEventBinding(map: StringMap<string, any>): EventBinding {
182210
return new EventBinding(map['fullName'],
183-
this.deserialize(map['source'], ASTWithSource, "binding"));
211+
this.deserialize(map['source'], ASTWithSource, "action"));
184212
}
185213

186214
private _serializeWorkerElementRef(elementRef: RenderElementRef): StringMap<string, any> {
@@ -223,15 +251,12 @@ export class Serializer {
223251
// TODO: make ASTs serializable
224252
var ast: AST;
225253
switch (data) {
226-
case "interpolation":
227-
ast = this._parser.parseInterpolation(obj['input'], obj['location']);
254+
case "action":
255+
ast = this._parser.parseAction(obj['input'], obj['location']);
228256
break;
229257
case "binding":
230258
ast = this._parser.parseBinding(obj['input'], obj['location']);
231259
break;
232-
case "simpleBinding":
233-
ast = this._parser.parseSimpleBinding(obj['input'], obj['location']);
234-
break;
235260
case "interpolation":
236261
ast = this._parser.parseInterpolation(obj['input'], obj['location']);
237262
break;

modules/angular2/src/web-workers/ui/event_serializer.dart

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,45 @@ final Map KEYBOARD_EVENT_PROPERTIES = {
5252
#type: String
5353
};
5454

55+
final Map EVENT_PROPERTIES = {
56+
#bubbles: bool,
57+
#cancelable: bool,
58+
#defaultPrevented: bool,
59+
#eventPhase: int,
60+
#timeStamp: int,
61+
#type: String
62+
};
63+
64+
// List of all elements with HTML value attribute.
65+
// Taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
66+
final Set<String> NODES_WITH_VALUE =
67+
new Set<String>.from(["input", "select", "option", "button", "li", "meter", "progress", "param"]);
68+
69+
Map<String, dynamic> serializeGenericEvent(dynamic e) {
70+
return serializeEvent(e, EVENT_PROPERTIES);
71+
}
72+
73+
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
74+
// adding value #3374
75+
Map<String, dynamic> serializeEventWithValue(dynamic e) {
76+
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
77+
return addValue(e, serializedEvent);
78+
}
5579
Map<String, dynamic> serializeMouseEvent(dynamic e) {
5680
return serializeEvent(e, MOUSE_EVENT_PROPERTIES);
5781
}
5882

5983
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
60-
return serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
84+
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
85+
return addValue(e, serializedEvent);
86+
}
87+
88+
// TODO(jteplitz602): #3374. See above.
89+
Map<String, dynamic> addValue(dynamic e, Map<String, dynamic> serializedEvent) {
90+
if (NODES_WITH_VALUE.contains(e.target.tagName.toLowerCase())){
91+
serializedEvent['target'] = {'value': e.target.value};
92+
}
93+
return serializedEvent;
6194
}
6295

6396
Map<String, dynamic> serializeEvent(dynamic e, Map<Symbol, Type> PROPERTIES) {

modules/angular2/src/web-workers/ui/event_serializer.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {StringMap} from 'angular2/src/facade/collection';
1+
import {StringMap, Set} from 'angular2/src/facade/collection';
22

33
const MOUSE_EVENT_PROPERTIES = [
44
"altKey",
@@ -31,12 +31,37 @@ const KEYBOARD_EVENT_PROPERTIES = [
3131
'which'
3232
];
3333

34+
const EVENT_PROPERTIES = ['type', 'bubbles', 'cancelable'];
35+
36+
const NODES_WITH_VALUE =
37+
new Set(["input", "select", "option", "button", "li", "meter", "progress", "param"]);
38+
39+
export function serializeGenericEvent(e: Event): StringMap<string, any> {
40+
return serializeEvent(e, EVENT_PROPERTIES);
41+
}
42+
43+
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
44+
// adding value #3374
45+
export function serializeEventWithValue(e: Event): StringMap<string, any> {
46+
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
47+
return addValue(e, serializedEvent);
48+
}
49+
3450
export function serializeMouseEvent(e: MouseEvent): StringMap<string, any> {
3551
return serializeEvent(e, MOUSE_EVENT_PROPERTIES);
3652
}
3753

3854
export function serializeKeyboardEvent(e: KeyboardEvent): StringMap<string, any> {
39-
return serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
55+
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
56+
return addValue(e, serializedEvent);
57+
}
58+
59+
// TODO(jteplitz602): #3374. See above.
60+
function addValue(e: Event, serializedEvent: StringMap<string, any>): StringMap<string, any> {
61+
if (NODES_WITH_VALUE.has((<HTMLElement>e.target).tagName.toLowerCase())) {
62+
serializedEvent['target'] = {'value': (<HTMLInputElement>e.target).value};
63+
}
64+
return serializedEvent;
4065
}
4166

4267
function serializeEvent(e: any, properties: List<string>): StringMap<string, any> {

modules/angular2/src/web-workers/ui/impl.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
3535
import {DOM} from 'angular2/src/dom/dom_adapter';
3636
import {
3737
serializeMouseEvent,
38-
serializeKeyboardEvent
38+
serializeKeyboardEvent,
39+
serializeGenericEvent,
40+
serializeEventWithValue
3941
} from 'angular2/src/web-workers/ui/event_serializer';
4042

4143
/**
@@ -236,7 +238,8 @@ class EventDispatcher implements RenderEventDispatcher {
236238
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
237239
var e = locals.get('$event');
238240
var serializedEvent;
239-
switch (eventName) {
241+
// TODO (jteplitz602): support custom events #3350
242+
switch (e.type) {
240243
case "click":
241244
case "mouseup":
242245
case "mousedown":
@@ -255,6 +258,60 @@ class EventDispatcher implements RenderEventDispatcher {
255258
case "keyup":
256259
serializedEvent = serializeKeyboardEvent(e);
257260
break;
261+
case "input":
262+
case "change":
263+
case "blur":
264+
serializedEvent = serializeEventWithValue(e);
265+
break;
266+
case "abort":
267+
case "afterprint":
268+
case "beforeprint":
269+
case "cached":
270+
case "canplay":
271+
case "canplaythrough":
272+
case "chargingchange":
273+
case "chargingtimechange":
274+
case "close":
275+
case "dischargingtimechange":
276+
case "DOMContentLoaded":
277+
case "downloading":
278+
case "durationchange":
279+
case "emptied":
280+
case "ended":
281+
case "error":
282+
case "fullscreenchange":
283+
case "fullscreenerror":
284+
case "invalid":
285+
case "languagechange":
286+
case "levelfchange":
287+
case "loadeddata":
288+
case "loadedmetadata":
289+
case "obsolete":
290+
case "offline":
291+
case "online":
292+
case "open":
293+
case "orientatoinchange":
294+
case "pause":
295+
case "pointerlockchange":
296+
case "pointerlockerror":
297+
case "play":
298+
case "playing":
299+
case "ratechange":
300+
case "readystatechange":
301+
case "reset":
302+
case "seeked":
303+
case "seeking":
304+
case "stalled":
305+
case "submit":
306+
case "success":
307+
case "suspend":
308+
case "timeupdate":
309+
case "updateready":
310+
case "visibilitychange":
311+
case "volumechange":
312+
case "waiting":
313+
serializedEvent = serializeGenericEvent(e);
314+
break;
258315
default:
259316
throw new BaseException(eventName + " not supported on WebWorkers");
260317
}

modules/angular2/src/web-workers/worker/broker.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {Injectable} from "angular2/di";
88
import {Type} from "angular2/src/facade/lang";
99
import {RenderViewRef, RenderEventDispatcher} from 'angular2/src/render/api';
1010
import {NgZone} from 'angular2/src/core/zone/ng_zone';
11+
import {deserializeGenericEvent} from './event_deserializer';
1112

1213
@Injectable()
1314
export class MessageBroker {
@@ -96,6 +97,7 @@ export class MessageBroker {
9697
private _dispatchEvent(eventData: RenderEventData): void {
9798
var dispatcher = this._eventDispatchRegistry.get(eventData.viewRef);
9899
this._zone.run(() => {
100+
eventData.locals['$event'] = deserializeGenericEvent(eventData.locals['$event']);
99101
dispatcher.dispatchRenderEvent(eventData.elementIndex, eventData.eventName, eventData.locals);
100102
});
101103
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
library angular2.src.web_workers.worker.event_deserializer;
2+
3+
class GenericEvent {
4+
Map<String, dynamic> properties;
5+
EventTarget _target = null;
6+
7+
GenericEvent(this.properties);
8+
9+
bool get bubbles => properties['bubbles'];
10+
bool get cancelable => properties['cancelable'];
11+
bool get defaultPrevented => properties['defaultPrevented'];
12+
int get eventPhase => properties['eventPhase'];
13+
int get timeStamp => properties['timeStamp'];
14+
String get type => properties['type'];
15+
bool get altKey => properties['altKey'];
16+
17+
int get charCode => properties['charCode'];
18+
bool get ctrlKey => properties['ctrlKey'];
19+
int get detail => properties['detail'];
20+
int get keyCode => properties['keyCode'];
21+
int get keyLocation => properties['keyLocation'];
22+
Point get layer => _getPoint('layer');
23+
int get location => properties['location'];
24+
bool get repeat => properties['repeat'];
25+
bool get shiftKey => properties['shiftKey'];
26+
27+
int get button => properties['button'];
28+
Point get client => _getPoint('client');
29+
bool get metaKey => properties['metaKey'];
30+
Point get offset => _getPoint('offset');
31+
Point get page => _getPoint('page');
32+
Point get screen => _getPoint('screen');
33+
34+
EventTarget get target{
35+
if (_target != null){
36+
return _target;
37+
} else if (properties.containsKey("target")){
38+
_target = new EventTarget(properties['target']);
39+
return _target;
40+
} else {
41+
return null;
42+
}
43+
}
44+
45+
dynamic _getPoint(name) {
46+
Map<String, dynamic> point = properties[name];
47+
return new Point(point['x'], point['y'], point['magnitude']);
48+
}
49+
}
50+
51+
class EventTarget {
52+
dynamic value;
53+
54+
EventTarget(Map<String, dynamic> properties) {
55+
value = properties['value'];
56+
}
57+
}
58+
59+
class Point {
60+
int x;
61+
int y;
62+
double magnitude;
63+
64+
Point(this.x, this.y, this.magnitude);
65+
}
66+
67+
GenericEvent deserializeGenericEvent(Map<String, dynamic> serializedEvent) {
68+
return new GenericEvent(serializedEvent);
69+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import {StringMap} from "angular2/src/facade/collection";
2+
3+
// no deserialization is necessary in TS.
4+
// This is only here to match dart interface
5+
export function deserializeGenericEvent(serializedEvent: StringMap<string, any>):
6+
StringMap<string, any> {
7+
return serializedEvent;
8+
}

modules/angular2/src/web-workers/worker/renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ export class WorkerRenderer implements Renderer {
171171
*/
172172
dehydrateView(viewRef: RenderViewRef) {
173173
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
174-
var args = new UiArguments("renderer", "deyhdrateView", fnArgs);
174+
var args = new UiArguments("renderer", "dehydrateView", fnArgs);
175175
this._messageBroker.runOnUiThread(args, null);
176176
}
177177

modules/angular2/test/web-workers/worker/broker_spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ export function main() {
5353
'value': {
5454
'viewRef': viewRef.serialize(),
5555
'elementIndex': elementIndex,
56-
'eventName': eventName
56+
'eventName': eventName,
57+
'locals': {'$event': {'target': {value: null}}}
5758
}
5859
}
5960
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
library examples.e2e_test.web_workers.kitchen_sink_spec;
2+
3+
main() {
4+
5+
}

0 commit comments

Comments
 (0)