mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Specs: Implement the Dispatcher classes.
R=abarth@chromium.org Review URL: https://codereview.chromium.org/919693007
This commit is contained in:
parent
f22842f3bc
commit
aa99c2f67b
113
specs/events.md
113
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);
|
||||
}
|
||||
|
||||
@ -105,33 +105,3 @@ assumed to exist:
|
||||
ClassName = SuperclassName;
|
||||
ClassName.namedConstructor = SuperclassName.otherNamedConstructor;
|
||||
```
|
||||
|
||||
* It is assumed that the standard library includes something that
|
||||
matches this pattern:
|
||||
|
||||
```dart
|
||||
class DispatcherController<T> {
|
||||
Dispatcher<T> _dispatcher;
|
||||
Dispatcher<T> get dispatcher => _dispatcher;
|
||||
|
||||
void add(T data) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
typedef bool Filter<T>(T t);
|
||||
typedef void Handler<T>(T t);
|
||||
class Dispatcher<T> {
|
||||
Dispatcher<T> where(Filter<T> filter) { /*...*/ return this; }
|
||||
void listen(Handler<T> handler) { /* ... */ }
|
||||
}
|
||||
class ExceptionListException<T> extends Exception with IterableMixin<T> {
|
||||
List<T> _exceptions;
|
||||
void add(T exception) {
|
||||
if (_exceptions == null)
|
||||
_exceptions = new List<T>();
|
||||
_exceptions.add(exception);
|
||||
}
|
||||
int get length => _exceptions == null ? 0 : _exceptions.length;
|
||||
Iterator<T> iterator() => _exceptions.iterator();
|
||||
}
|
||||
```
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user