fix(WebWorker): Fix Todo Server demo and add test to ensure the demo can bootstrap.
Closes #3970
This commit is contained in:
parent
3ff321475d
commit
696edde17c
|
@ -1,66 +1,8 @@
|
||||||
library angular2.src.web_workers.event_serializer;
|
library angular2.src.web_workers.event_serializer;
|
||||||
|
|
||||||
import 'package:angular2/src/core/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:core';
|
||||||
import 'dart:html';
|
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
|
|
||||||
};
|
|
||||||
|
|
||||||
final Map EVENT_PROPERTIES = {
|
|
||||||
#bubbles: bool,
|
|
||||||
#cancelable: bool,
|
|
||||||
#defaultPrevented: bool,
|
|
||||||
#eventPhase: int,
|
|
||||||
#timeStamp: int,
|
|
||||||
#type: String
|
|
||||||
};
|
|
||||||
|
|
||||||
// List of all elements with HTML value attribute.
|
// List of all elements with HTML value attribute.
|
||||||
// Taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
// Taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
||||||
final Set<String> NODES_WITH_VALUE = new Set<String>.from([
|
final Set<String> NODES_WITH_VALUE = new Set<String>.from([
|
||||||
|
@ -75,23 +17,74 @@ final Set<String> NODES_WITH_VALUE = new Set<String>.from([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Map<String, dynamic> serializeGenericEvent(dynamic e) {
|
Map<String, dynamic> serializeGenericEvent(dynamic e) {
|
||||||
return serializeEvent(e, EVENT_PROPERTIES);
|
var serialized = new Map<String, dynamic>();
|
||||||
|
serialized['bubbles'] = e.bubbles;
|
||||||
|
serialized['cancelable'] = e.cancelable;
|
||||||
|
serialized['defaultPrevented'] = e.defaultPrevented;
|
||||||
|
serialized['eventPhase'] = e.eventPhase;
|
||||||
|
serialized['timeStamp'] = e.timeStamp;
|
||||||
|
serialized['type'] = e.type;
|
||||||
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
|
// TODO(jteplitz602): Allow users to specify the properties they need rather than always
|
||||||
// adding value #3374
|
// adding value #3374
|
||||||
Map<String, dynamic> serializeEventWithTarget(dynamic e) {
|
Map<String, dynamic> serializeEventWithTarget(dynamic e) {
|
||||||
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
var serializedEvent = serializeGenericEvent(e);
|
||||||
return addTarget(e, serializedEvent);
|
return addTarget(e, serializedEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
Map<String, dynamic> serializeMouseEvent(dynamic e) {
|
||||||
return serializeEvent(e, MOUSE_EVENT_PROPERTIES);
|
var serialized = new Map<String, dynamic>();
|
||||||
|
serialized['altKey'] = e.altKey;
|
||||||
|
serialized['bubbles'] = e.bubbles;
|
||||||
|
serialized['button'] = e.button;
|
||||||
|
serialized['cancelable'] = e.cancelable;
|
||||||
|
serialized['client'] = serializePoint(e.client);
|
||||||
|
serialized['ctrlKey'] = e.ctrlKey;
|
||||||
|
serialized['defaultPrevented'] = e.defaultPrevented;
|
||||||
|
serialized['detail'] = e.detail;
|
||||||
|
serialized['eventPhase'] = e.eventPhase;
|
||||||
|
serialized['layer'] = serializePoint(e.layer);
|
||||||
|
serialized['metaKey'] = e.metaKey;
|
||||||
|
serialized['offset'] = serializePoint(e.offset);
|
||||||
|
serialized['page'] = serializePoint(e.page);
|
||||||
|
serialized['region'] = e.region;
|
||||||
|
serialized['screen'] = serializePoint(e.screen);
|
||||||
|
serialized['shiftKey'] = e.shiftKey;
|
||||||
|
serialized['timeStamp'] = e.timeStamp;
|
||||||
|
serialized['type'] = e.type;
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> serializePoint(Point point) {
|
||||||
|
var serialized = new Map<String, dynamic>();
|
||||||
|
serialized['magnitude'] = point.magnitude;
|
||||||
|
serialized['x'] = point.x;
|
||||||
|
serialized['y'] = point.y;
|
||||||
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
Map<String, dynamic> serializeKeyboardEvent(dynamic e) {
|
||||||
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
var serialized = new Map<String, dynamic>();
|
||||||
return addTarget(e, serializedEvent);
|
serialized['altKey'] = e.altKey;
|
||||||
|
serialized['bubbles'] = e.bubbles;
|
||||||
|
serialized['cancelable'] = e.cancelable;
|
||||||
|
serialized['charCode'] = e.charCode;
|
||||||
|
serialized['ctrlKey'] = e.ctrlKey;
|
||||||
|
serialized['defaultPrevented'] = e.defaultPrevented;
|
||||||
|
serialized['detail'] = e.detail;
|
||||||
|
serialized['eventPhase'] = e.eventPhase;
|
||||||
|
serialized['keyCode'] = e.keyCode;
|
||||||
|
serialized['keyLocation'] = e.keyLocation;
|
||||||
|
serialized['layer'] = serializePoint(e.layer);
|
||||||
|
serialized['location'] = e.location;
|
||||||
|
serialized['repeat'] = e.repeat;
|
||||||
|
serialized['shiftKey'] = e.shiftKey;
|
||||||
|
serialized['timeStamp'] = e.timeStamp;
|
||||||
|
serialized['type'] = e.type;
|
||||||
|
//return addTarget(e, serialized);
|
||||||
|
return serialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): #3374. See above.
|
// TODO(jteplitz602): #3374. See above.
|
||||||
|
@ -105,24 +98,3 @@ Map<String, dynamic> addTarget(
|
||||||
}
|
}
|
||||||
return serializedEvent;
|
return serializedEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -90,7 +90,6 @@ function _injectorBindings(appComponentType, bus: MessageBus, initData: StringMa
|
||||||
bind(APP_COMPONENT_REF_PROMISE)
|
bind(APP_COMPONENT_REF_PROMISE)
|
||||||
.toFactory(
|
.toFactory(
|
||||||
(dynamicComponentLoader, injector) => {
|
(dynamicComponentLoader, injector) => {
|
||||||
|
|
||||||
// TODO(rado): investigate whether to support bindings on root component.
|
// TODO(rado): investigate whether to support bindings on root component.
|
||||||
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
|
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
|
||||||
.then((componentRef) => { return componentRef; });
|
.then((componentRef) => { return componentRef; });
|
||||||
|
@ -150,19 +149,16 @@ export function bootstrapWebWorkerCommon(
|
||||||
// index.html and main.js are possible.
|
// index.html and main.js are possible.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
var subscription: any;
|
var subscription: any;
|
||||||
var emitter = bus.from(SETUP_CHANNEL);
|
var emitter = bus.from(SETUP_CHANNEL);
|
||||||
subscription = ObservableWrapper.subscribe(emitter, (message: StringMap<string, any>) => {
|
subscription = ObservableWrapper.subscribe(emitter, (message: StringMap<string, any>) => {
|
||||||
|
var exceptionHandler;
|
||||||
|
try {
|
||||||
var appInjector =
|
var appInjector =
|
||||||
_createAppInjector(appComponentType, componentInjectableBindings, zone, bus, message);
|
_createAppInjector(appComponentType, componentInjectableBindings, zone, bus, message);
|
||||||
var compRefToken = PromiseWrapper.wrap(() => {
|
exceptionHandler = appInjector.get(ExceptionHandler);
|
||||||
try {
|
zone.overrideOnErrorHandler((e, s) => exceptionHandler.call(e, s));
|
||||||
return appInjector.get(APP_COMPONENT_REF_PROMISE);
|
var compRefToken: Promise<any> = appInjector.get(APP_COMPONENT_REF_PROMISE);
|
||||||
} catch (e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var tick = (componentRef) => {
|
var tick = (componentRef) => {
|
||||||
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
|
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
|
||||||
// retrieve life cycle: may have already been created if injected in root component
|
// retrieve life cycle: may have already been created if injected in root component
|
||||||
|
@ -172,10 +168,20 @@ export function bootstrapWebWorkerCommon(
|
||||||
|
|
||||||
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
|
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
|
||||||
};
|
};
|
||||||
PromiseWrapper.then(compRefToken, tick,
|
|
||||||
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
|
|
||||||
|
|
||||||
|
var tickResult = PromiseWrapper.then(compRefToken, tick);
|
||||||
|
|
||||||
|
PromiseWrapper.then(tickResult,
|
||||||
|
(_) => {}); // required for Dart to trigger the default error handler
|
||||||
|
PromiseWrapper.then(tickResult, null,
|
||||||
|
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
|
||||||
ObservableWrapper.dispose(subscription);
|
ObservableWrapper.dispose(subscription);
|
||||||
|
} catch (e) {
|
||||||
|
if (isPresent(exceptionHandler)) {
|
||||||
|
exceptionHandler.call(e, e.stack);
|
||||||
|
}
|
||||||
|
bootstrapProcess.reject(e, e.stack);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ObservableWrapper.callNext(bus.to(SETUP_CHANNEL), "ready");
|
ObservableWrapper.callNext(bus.to(SETUP_CHANNEL), "ready");
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
library angular2.test.web_workers.debug_tools.bootstrap;
|
||||||
|
|
||||||
|
import "package:angular2/test_lib.dart";
|
||||||
|
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
|
||||||
|
import "package:angular2/src/core/reflection/reflection.dart";
|
||||||
|
import "package:angular2/web_worker/worker.dart";
|
||||||
|
import "package:angular2/src/web_workers/worker/application_common.dart";
|
||||||
|
import "../shared/web_worker_test_util.dart";
|
||||||
|
import "dart:convert";
|
||||||
|
|
||||||
|
main() {
|
||||||
|
describe("bootstrapWebWorkerCommon", () {
|
||||||
|
it ("should bootstrap on a Dart VM", () {
|
||||||
|
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||||
|
var buses = createPairedMessageBuses();
|
||||||
|
bootstrapWebWorkerCommon(App, buses.worker);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(selector: "app")
|
||||||
|
@View(template: "<p>Hello {{name}}</p>")
|
||||||
|
class App {
|
||||||
|
String name = "Tester";
|
||||||
|
}
|
|
@ -5,17 +5,16 @@ import 'dart:async';
|
||||||
import "package:angular2/src/core/facade/async.dart";
|
import "package:angular2/src/core/facade/async.dart";
|
||||||
|
|
||||||
class MockEventEmitter extends EventEmitter {
|
class MockEventEmitter extends EventEmitter {
|
||||||
List<Function> _nextFns = new List();
|
final controller = new StreamController.broadcast(sync: true);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
StreamSubscription listen(void onData(dynamic line),
|
StreamSubscription listen(void onData(dynamic line),
|
||||||
{void onError(Error error), void onDone(), bool cancelOnError}) {
|
{void onError(Error error), void onDone(), bool cancelOnError}) {
|
||||||
_nextFns.add(onData);
|
return controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void add(value) {
|
void add(value) {
|
||||||
_nextFns.forEach((fn) => fn(value));
|
controller.add(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,14 @@ export class MockEventEmitter extends EventEmitter {
|
||||||
|
|
||||||
observer(generator: any): Rx.IDisposable {
|
observer(generator: any): Rx.IDisposable {
|
||||||
this._nextFns.push(generator.next);
|
this._nextFns.push(generator.next);
|
||||||
return null;
|
return new MockDisposable();
|
||||||
}
|
}
|
||||||
|
|
||||||
next(value: any) {
|
next(value: any) {
|
||||||
ListWrapper.forEach(this._nextFns, (fn) => { fn(value); });
|
ListWrapper.forEach(this._nextFns, (fn) => { fn(value); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockDisposable implements Rx.IDisposable {
|
||||||
|
dispose(): void {}
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,15 @@ transformers:
|
||||||
- web/src/observable_models/index.dart
|
- web/src/observable_models/index.dart
|
||||||
- web/src/person_management/index.dart
|
- web/src/person_management/index.dart
|
||||||
- web/src/template_driven_forms/index.dart
|
- web/src/template_driven_forms/index.dart
|
||||||
|
- web/src/web_workers/todo/server_index.dart
|
||||||
|
- web/src/web_workers/todo/background_index.dart
|
||||||
|
- web/src/web_workers/message_broker/background_index.dart
|
||||||
|
- web/src/web_workers/kitchen_sink/background_index.dart
|
||||||
|
|
||||||
|
# These entrypoints are disabled untl the transformer supports UI bootstrap (issue #3971)
|
||||||
|
# - web/src/web_workers/message_broker/index.dart
|
||||||
|
# - web/src/web_workers/kitchen_sink/index.dart
|
||||||
|
# - web/src/web_workers/todo/index.dart
|
||||||
# These entrypoints are disabled until cross-package urls are working (issue #2982)
|
# These entrypoints are disabled until cross-package urls are working (issue #2982)
|
||||||
# - web/src/material/button/index.dart
|
# - web/src/material/button/index.dart
|
||||||
# - web/src/material/checkbox/index.dart
|
# - web/src/material/checkbox/index.dart
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import {NgFor} from 'angular2/src/core/directives/ng_for';
|
import {NgFor, View, Component, FORM_DIRECTIVES} from 'angular2/web_worker/worker';
|
||||||
import {View, Component} from 'angular2/src/core/metadata';
|
|
||||||
import {FORM_DIRECTIVES} from 'angular2/src/forms/directives';
|
|
||||||
import {Store, Todo, TodoFactory} from './services/TodoStore';
|
import {Store, Todo, TodoFactory} from './services/TodoStore';
|
||||||
|
|
||||||
@Component({selector: 'todo-app', viewBindings: [Store, TodoFactory]})
|
@Component({selector: 'todo-app', viewBindings: [Store, TodoFactory]})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Injectable} from 'angular2/angular2';
|
import {Injectable} from 'angular2/web_worker/worker';
|
||||||
import {ListWrapper, Predicate} from 'angular2/src/core/facade/collection';
|
import {ListWrapper, Predicate} from 'angular2/src/core/facade/collection';
|
||||||
|
|
||||||
// base model for RecordStore
|
// base model for RecordStore
|
||||||
|
|
|
@ -15,6 +15,7 @@ const INJECTABLES = const [
|
||||||
const ClassDescriptor('Injectable', 'package:angular2/di.dart'),
|
const ClassDescriptor('Injectable', 'package:angular2/di.dart'),
|
||||||
const ClassDescriptor('Injectable', 'package:angular2/angular2.dart'),
|
const ClassDescriptor('Injectable', 'package:angular2/angular2.dart'),
|
||||||
const ClassDescriptor('Injectable', 'package:angular2/bootstrap_static.dart'),
|
const ClassDescriptor('Injectable', 'package:angular2/bootstrap_static.dart'),
|
||||||
|
const ClassDescriptor('Injectable', 'package:angular2/web_worker/worker.dart'),
|
||||||
];
|
];
|
||||||
|
|
||||||
const DIRECTIVES = const [
|
const DIRECTIVES = const [
|
||||||
|
@ -30,6 +31,8 @@ const DIRECTIVES = const [
|
||||||
superClass: 'Injectable'),
|
superClass: 'Injectable'),
|
||||||
const ClassDescriptor('Directive', 'package:angular2/bootstrap_static.dart',
|
const ClassDescriptor('Directive', 'package:angular2/bootstrap_static.dart',
|
||||||
superClass: 'Injectable'),
|
superClass: 'Injectable'),
|
||||||
|
const ClassDescriptor('Directive', 'package:angular2/web_worker/worker.dart',
|
||||||
|
superClass: 'Injectable'),
|
||||||
];
|
];
|
||||||
|
|
||||||
const COMPONENTS = const [
|
const COMPONENTS = const [
|
||||||
|
@ -45,10 +48,13 @@ const COMPONENTS = const [
|
||||||
superClass: 'Directive'),
|
superClass: 'Directive'),
|
||||||
const ClassDescriptor('Component', 'package:angular2/core.dart',
|
const ClassDescriptor('Component', 'package:angular2/core.dart',
|
||||||
superClass: '`Directive'),
|
superClass: '`Directive'),
|
||||||
|
const ClassDescriptor('Component', 'package:angular2/web_worker/worker.dart',
|
||||||
|
superClass: '`Directive'),
|
||||||
];
|
];
|
||||||
|
|
||||||
const VIEWS = const [
|
const VIEWS = const [
|
||||||
const ClassDescriptor('View', 'package:angular2/angular2.dart'),
|
const ClassDescriptor('View', 'package:angular2/angular2.dart'),
|
||||||
|
const ClassDescriptor('View', 'package:angular2/web_worker/worker.dart'),
|
||||||
const ClassDescriptor('View', 'package:angular2/bootstrap_static.dart'),
|
const ClassDescriptor('View', 'package:angular2/bootstrap_static.dart'),
|
||||||
const ClassDescriptor('View', 'package:angular2/core.dart'),
|
const ClassDescriptor('View', 'package:angular2/core.dart'),
|
||||||
const ClassDescriptor('View', 'package:angular2/src/core/metadata/view.dart'),
|
const ClassDescriptor('View', 'package:angular2/src/core/metadata/view.dart'),
|
||||||
|
|
Loading…
Reference in New Issue