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;
|
||||
|
||||
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: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.
|
||||
// Taken from: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
||||
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) {
|
||||
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
|
||||
// adding value #3374
|
||||
Map<String, dynamic> serializeEventWithTarget(dynamic e) {
|
||||
var serializedEvent = serializeEvent(e, EVENT_PROPERTIES);
|
||||
var serializedEvent = serializeGenericEvent(e);
|
||||
return addTarget(e, serializedEvent);
|
||||
}
|
||||
|
||||
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) {
|
||||
var serializedEvent = serializeEvent(e, KEYBOARD_EVENT_PROPERTIES);
|
||||
return addTarget(e, serializedEvent);
|
||||
var serialized = new Map<String, dynamic>();
|
||||
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.
|
||||
|
@ -105,24 +98,3 @@ Map<String, dynamic> addTarget(
|
|||
}
|
||||
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)
|
||||
.toFactory(
|
||||
(dynamicComponentLoader, injector) => {
|
||||
|
||||
// TODO(rado): investigate whether to support bindings on root component.
|
||||
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
|
||||
.then((componentRef) => { return componentRef; });
|
||||
|
@ -150,19 +149,16 @@ export function bootstrapWebWorkerCommon(
|
|||
// index.html and main.js are possible.
|
||||
//
|
||||
|
||||
|
||||
var subscription: any;
|
||||
var emitter = bus.from(SETUP_CHANNEL);
|
||||
subscription = ObservableWrapper.subscribe(emitter, (message: StringMap<string, any>) => {
|
||||
var exceptionHandler;
|
||||
try {
|
||||
var appInjector =
|
||||
_createAppInjector(appComponentType, componentInjectableBindings, zone, bus, message);
|
||||
var compRefToken = PromiseWrapper.wrap(() => {
|
||||
try {
|
||||
return appInjector.get(APP_COMPONENT_REF_PROMISE);
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
exceptionHandler = appInjector.get(ExceptionHandler);
|
||||
zone.overrideOnErrorHandler((e, s) => exceptionHandler.call(e, s));
|
||||
var compRefToken: Promise<any> = appInjector.get(APP_COMPONENT_REF_PROMISE);
|
||||
var tick = (componentRef) => {
|
||||
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
|
||||
// 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));
|
||||
};
|
||||
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);
|
||||
} catch (e) {
|
||||
if (isPresent(exceptionHandler)) {
|
||||
exceptionHandler.call(e, e.stack);
|
||||
}
|
||||
bootstrapProcess.reject(e, e.stack);
|
||||
}
|
||||
});
|
||||
|
||||
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";
|
||||
|
||||
class MockEventEmitter extends EventEmitter {
|
||||
List<Function> _nextFns = new List();
|
||||
final controller = new StreamController.broadcast(sync: true);
|
||||
|
||||
@override
|
||||
StreamSubscription listen(void onData(dynamic line),
|
||||
{void onError(Error error), void onDone(), bool cancelOnError}) {
|
||||
_nextFns.add(onData);
|
||||
return null;
|
||||
return controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||
}
|
||||
|
||||
@override
|
||||
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 {
|
||||
this._nextFns.push(generator.next);
|
||||
return null;
|
||||
return new MockDisposable();
|
||||
}
|
||||
|
||||
next(value: any) {
|
||||
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/person_management/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)
|
||||
# - web/src/material/button/index.dart
|
||||
# - web/src/material/checkbox/index.dart
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import {NgFor} from 'angular2/src/core/directives/ng_for';
|
||||
import {View, Component} from 'angular2/src/core/metadata';
|
||||
import {FORM_DIRECTIVES} from 'angular2/src/forms/directives';
|
||||
import {NgFor, View, Component, FORM_DIRECTIVES} from 'angular2/web_worker/worker';
|
||||
import {Store, Todo, TodoFactory} from './services/TodoStore';
|
||||
|
||||
@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';
|
||||
|
||||
// base model for RecordStore
|
||||
|
|
|
@ -15,6 +15,7 @@ const INJECTABLES = const [
|
|||
const ClassDescriptor('Injectable', 'package:angular2/di.dart'),
|
||||
const ClassDescriptor('Injectable', 'package:angular2/angular2.dart'),
|
||||
const ClassDescriptor('Injectable', 'package:angular2/bootstrap_static.dart'),
|
||||
const ClassDescriptor('Injectable', 'package:angular2/web_worker/worker.dart'),
|
||||
];
|
||||
|
||||
const DIRECTIVES = const [
|
||||
|
@ -30,6 +31,8 @@ const DIRECTIVES = const [
|
|||
superClass: 'Injectable'),
|
||||
const ClassDescriptor('Directive', 'package:angular2/bootstrap_static.dart',
|
||||
superClass: 'Injectable'),
|
||||
const ClassDescriptor('Directive', 'package:angular2/web_worker/worker.dart',
|
||||
superClass: 'Injectable'),
|
||||
];
|
||||
|
||||
const COMPONENTS = const [
|
||||
|
@ -45,10 +48,13 @@ const COMPONENTS = const [
|
|||
superClass: 'Directive'),
|
||||
const ClassDescriptor('Component', 'package:angular2/core.dart',
|
||||
superClass: '`Directive'),
|
||||
const ClassDescriptor('Component', 'package:angular2/web_worker/worker.dart',
|
||||
superClass: '`Directive'),
|
||||
];
|
||||
|
||||
const VIEWS = const [
|
||||
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/core.dart'),
|
||||
const ClassDescriptor('View', 'package:angular2/src/core/metadata/view.dart'),
|
||||
|
|
Loading…
Reference in New Issue