Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(667)

Unified Diff: sky/specs/events.md

Issue 919693007: Specs: Implement the Dispatcher classes. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: add zone support Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sky/specs/script.md » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/specs/events.md
diff --git a/sky/specs/events.md b/sky/specs/events.md
index d839c17059f205b963badcd5d981036cc334aa76..54d869603b6b8de5004d9c6f3f505afb1a40dfa2 100644
--- a/sky/specs/events.md
+++ b/sky/specs/events.md
@@ -6,6 +6,111 @@ SKY MODULE
<!-- part of sky:core -->
<script>
+import 'dart:collection';
+import 'dart:async';
+
+class ExceptionAndStackTrace<T> {
+ const ExceptionAndStackTrace(this.exception, this.stackTrace);
+ final T exception;
+ final StackTrace stackTrace;
+}
+
+class ExceptionListException<T> extends IterableMixin<ExceptionAndStackTrace<T>> implements Exception {
+ List<ExceptionAndStackTrace<T>> _exceptions;
+ void add(T exception, [StackTrace stackTrace = null]) {
+ if (_exceptions == null)
+ _exceptions = new List<ExceptionAndStackTrace<T>>();
+ _exceptions.add(new ExceptionAndStackTrace<T>(exception, stackTrace));
+ }
+ int get length => _exceptions == null ? 0 : _exceptions.length;
+ Iterator<ExceptionAndStackTrace<T>> get iterator => _exceptions.iterator;
+}
+
+typedef bool Filter<T>(T t);
+typedef void Handler<T>(T t);
+
+class DispatcherController<T> {
+ DispatcherController() : dispatcher = new Dispatcher<T>();
+ final Dispatcher<T> dispatcher;
+ void add(T data) => dispatcher._add(data);
+}
+
+class Pair<A, B> {
+ const Pair(this.a, this.b);
+ final A a;
+ final B b;
+}
+
+class Dispatcher<T> {
+ List<Pair<Handler, ZoneUnaryCallback>> _listeners;
+ void listen(Handler<T> handler) {
+ // you should not throw out of this handler
+ if (_listeners == null)
+ _listeners = new List<Pair<Handler, ZoneUnaryCallback>>();
+ _listeners.add(new Pair<Handler, ZoneUnaryCallback>(handler, Zone.current.bindUnaryCallback(handler)));
+ }
+ bool unlisten(Handler<T> handler) {
+ if (_listeners == null)
+ return false;
+ var target = _listeners.lastWhere((v) => v.a == handler, orElse: () => null);
+ if (target == null)
+ return false;
+ _listeners.remove(target);
+ return true;
+ }
+ void _add(T data) {
+ if (_listeners == null)
+ return;
+ ExceptionListException exceptions = new ExceptionListException();
+ // we make a copy of the list here so that the listeners can
+ // mutate our list without worry
+ _listeners.toList().forEach((Pair<Handler, ZoneUnaryCallback> item) {
+ try {
+ item.b(data);
+ } catch (exception, stackTrace) {
+ exceptions.add(exception, stackTrace);
+ }
+ });
+ if (exceptions.length > 0)
+ throw exceptions;
+ }
+
+ Dispatcher<T> where(Filter<T> filter) {
+ var subdispatcher = new Dispatcher<T>();
+ listen((T data) {
+ if (filter(data))
+ subdispatcher._add(data);
+ });
+ return subdispatcher;
+ }
+
+ Dispatcher<T> until(Filter<T> filter) {
+ var subdispatcher = new Dispatcher<T>();
+ Handler handler;
+ handler = (T data) {
+ if (filter(data))
+ unlisten(handler);
+ else
+ subdispatcher._add(data);
+ };
+ listen(handler);
+ return subdispatcher;
+ }
+
+ Future<T> firstWhere(Filter<T> filter) {
+ Completer completer = new Completer();
+ Handler handler;
+ handler = (T data) {
+ if (filter(data)) {
+ completer.complete(data);
+ unlisten(handler);
+ }
+ };
+ listen(handler);
+ return completer.future;
+ }
+}
+
abstract class Event<ReturnType> {
Event() { init(); }
void init() { }
@@ -29,12 +134,12 @@ abstract class Event<ReturnType> {
}
class EventTarget {
- EventTarget() : _eventsController = new DispatcherController<@nonnull Event>();
+ EventTarget() : _eventsController = new DispatcherController<Event>();
Dispatcher get events => _eventsController.dispatcher;
EventTarget parentNode;
- List<@nonnull EventTarget> getEventDispatchChain() {
+ List<EventTarget> getEventDispatchChain() {
if (this.parentNode == null) {
return [this];
} else {
@@ -46,7 +151,7 @@ class EventTarget {
final DispatcherController _eventsController;
- dynamic dispatchEvent(@nonnull Event event, { dynamic defaultResult: null }) { // O(N*M) where N is the length of the chain and M is the average number of listeners per link in the chain
+ dynamic dispatchEvent(Event event, { dynamic defaultResult: null }) { // O(N*M) where N is the length of the chain and M is the average number of listeners per link in the chain
// note: this will throw an ExceptionListException<ExceptionListException> if any of the listeners threw
assert(event != null); // event must be non-null
event.handled = false;
@@ -71,7 +176,7 @@ class EventTarget {
return event.result;
}
- void _dispatchEventLocally(@nonnull Event event) {
+ void _dispatchEventLocally(Event event) {
event._currentTarget = this;
_eventsController.add(event);
}
« no previous file with comments | « no previous file | sky/specs/script.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698