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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « no previous file | sky/specs/script.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 Sky Event Model 1 Sky Event Model
2 =============== 2 ===============
3 3
4 ```dart 4 ```dart
5 SKY MODULE 5 SKY MODULE
6 <!-- part of sky:core --> 6 <!-- part of sky:core -->
7 7
8 <script> 8 <script>
9 import 'dart:collection';
10 import 'dart:async';
11
12 class ExceptionAndStackTrace<T> {
13 const ExceptionAndStackTrace(this.exception, this.stackTrace);
14 final T exception;
15 final StackTrace stackTrace;
16 }
17
18 class ExceptionListException<T> extends IterableMixin<ExceptionAndStackTrace<T>> implements Exception {
19 List<ExceptionAndStackTrace<T>> _exceptions;
20 void add(T exception, [StackTrace stackTrace = null]) {
21 if (_exceptions == null)
22 _exceptions = new List<ExceptionAndStackTrace<T>>();
23 _exceptions.add(new ExceptionAndStackTrace<T>(exception, stackTrace));
24 }
25 int get length => _exceptions == null ? 0 : _exceptions.length;
26 Iterator<ExceptionAndStackTrace<T>> get iterator => _exceptions.iterator;
27 }
28
29 typedef bool Filter<T>(T t);
30 typedef void Handler<T>(T t);
31
32 class DispatcherController<T> {
33 DispatcherController() : dispatcher = new Dispatcher<T>();
34 final Dispatcher<T> dispatcher;
35 void add(T data) => dispatcher._add(data);
36 }
37
38 class Pair<A, B> {
39 const Pair(this.a, this.b);
40 final A a;
41 final B b;
42 }
43
44 class Dispatcher<T> {
45 List<Pair<Handler, ZoneUnaryCallback>> _listeners;
46 void listen(Handler<T> handler) {
47 // you should not throw out of this handler
48 if (_listeners == null)
49 _listeners = new List<Pair<Handler, ZoneUnaryCallback>>();
50 _listeners.add(new Pair<Handler, ZoneUnaryCallback>(handler, Zone.current.bi ndUnaryCallback(handler)));
51 }
52 bool unlisten(Handler<T> handler) {
53 if (_listeners == null)
54 return false;
55 var target = _listeners.lastWhere((v) => v.a == handler, orElse: () => null) ;
56 if (target == null)
57 return false;
58 _listeners.remove(target);
59 return true;
60 }
61 void _add(T data) {
62 if (_listeners == null)
63 return;
64 ExceptionListException exceptions = new ExceptionListException();
65 // we make a copy of the list here so that the listeners can
66 // mutate our list without worry
67 _listeners.toList().forEach((Pair<Handler, ZoneUnaryCallback> item) {
68 try {
69 item.b(data);
70 } catch (exception, stackTrace) {
71 exceptions.add(exception, stackTrace);
72 }
73 });
74 if (exceptions.length > 0)
75 throw exceptions;
76 }
77
78 Dispatcher<T> where(Filter<T> filter) {
79 var subdispatcher = new Dispatcher<T>();
80 listen((T data) {
81 if (filter(data))
82 subdispatcher._add(data);
83 });
84 return subdispatcher;
85 }
86
87 Dispatcher<T> until(Filter<T> filter) {
88 var subdispatcher = new Dispatcher<T>();
89 Handler handler;
90 handler = (T data) {
91 if (filter(data))
92 unlisten(handler);
93 else
94 subdispatcher._add(data);
95 };
96 listen(handler);
97 return subdispatcher;
98 }
99
100 Future<T> firstWhere(Filter<T> filter) {
101 Completer completer = new Completer();
102 Handler handler;
103 handler = (T data) {
104 if (filter(data)) {
105 completer.complete(data);
106 unlisten(handler);
107 }
108 };
109 listen(handler);
110 return completer.future;
111 }
112 }
113
9 abstract class Event<ReturnType> { 114 abstract class Event<ReturnType> {
10 Event() { init(); } 115 Event() { init(); }
11 void init() { } 116 void init() { }
12 117
13 bool get bubbles; 118 bool get bubbles;
14 119
15 EventTarget _target; 120 EventTarget _target;
16 EventTarget get target => _target; 121 EventTarget get target => _target;
17 122
18 EventTarget _currentTarget; 123 EventTarget _currentTarget;
19 EventTarget get currentTarget => _currentTarget; 124 EventTarget get currentTarget => _currentTarget;
20 125
21 bool handled; // precise semantics depend on the event type, but in general, s et this when you set result 126 bool handled; // precise semantics depend on the event type, but in general, s et this when you set result
22 ReturnType result; 127 ReturnType result;
23 128
24 bool resultIsCompatible(dynamic candidate) => candidate is ReturnType; 129 bool resultIsCompatible(dynamic candidate) => candidate is ReturnType;
25 130
26 // TODO(ianh): abstract API for doing things at shadow tree boundaries 131 // TODO(ianh): abstract API for doing things at shadow tree boundaries
27 // TODO(ianh): do events get blocked at scope boundaries, e.g. focus events wh en both sides are in the scope? 132 // TODO(ianh): do events get blocked at scope boundaries, e.g. focus events wh en both sides are in the scope?
28 // TODO(ianh): do events get retargetted, e.g. focus when leaving a custom ele ment? 133 // TODO(ianh): do events get retargetted, e.g. focus when leaving a custom ele ment?
29 } 134 }
30 135
31 class EventTarget { 136 class EventTarget {
32 EventTarget() : _eventsController = new DispatcherController<@nonnull Event>() ; 137 EventTarget() : _eventsController = new DispatcherController<Event>();
33 138
34 Dispatcher get events => _eventsController.dispatcher; 139 Dispatcher get events => _eventsController.dispatcher;
35 EventTarget parentNode; 140 EventTarget parentNode;
36 141
37 List<@nonnull EventTarget> getEventDispatchChain() { 142 List<EventTarget> getEventDispatchChain() {
38 if (this.parentNode == null) { 143 if (this.parentNode == null) {
39 return [this]; 144 return [this];
40 } else { 145 } else {
41 var result = this.parentNode.getEventDispatchChain(); 146 var result = this.parentNode.getEventDispatchChain();
42 result.insert(0, this); 147 result.insert(0, this);
43 return result; 148 return result;
44 } 149 }
45 } 150 }
46 151
47 final DispatcherController _eventsController; 152 final DispatcherController _eventsController;
48 153
49 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 lis teners per link in the chain 154 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 pe r link in the chain
50 // note: this will throw an ExceptionListException<ExceptionListException> i f any of the listeners threw 155 // note: this will throw an ExceptionListException<ExceptionListException> i f any of the listeners threw
51 assert(event != null); // event must be non-null 156 assert(event != null); // event must be non-null
52 event.handled = false; 157 event.handled = false;
53 assert(event.resultIsCompatible(defaultResult)); 158 assert(event.resultIsCompatible(defaultResult));
54 event.result = defaultResult; 159 event.result = defaultResult;
55 event._target = this; 160 event._target = this;
56 var chain; 161 var chain;
57 if (event.bubbles) 162 if (event.bubbles)
58 chain = this.getEventDispatchChain(); 163 chain = this.getEventDispatchChain();
59 else 164 else
60 chain = [this]; 165 chain = [this];
61 var exceptions = new ExceptionListException<ExceptionListException>(); 166 var exceptions = new ExceptionListException<ExceptionListException>();
62 for (var link in chain) { 167 for (var link in chain) {
63 try { 168 try {
64 link._dispatchEventLocally(event); 169 link._dispatchEventLocally(event);
65 } on ExceptionListException catch (e) { 170 } on ExceptionListException catch (e) {
66 exceptions.add(e); 171 exceptions.add(e);
67 } 172 }
68 } 173 }
69 if (exceptions.length > 0) 174 if (exceptions.length > 0)
70 throw exceptions; 175 throw exceptions;
71 return event.result; 176 return event.result;
72 } 177 }
73 178
74 void _dispatchEventLocally(@nonnull Event event) { 179 void _dispatchEventLocally(Event event) {
75 event._currentTarget = this; 180 event._currentTarget = this;
76 _eventsController.add(event); 181 _eventsController.add(event);
77 } 182 }
78 } 183 }
79 </script> 184 </script>
80 ``` 185 ```
OLDNEW
« 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