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

Side by Side Diff: tools/dom/src/EventStreamProvider.dart

Issue 21607003: Add Event delegation to Elements and groups of elements. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of html; 5 part of html;
6 6
7 /** 7 /**
8 * Adapter for exposing DOM events as Dart streams. 8 * Adapter for exposing DOM events as Dart streams.
9 */ 9 */
10 class _EventStream<T extends Event> extends Stream<T> { 10 class _EventStream<T extends Event> extends Stream<T> {
(...skipping 12 matching lines...) Expand all
23 StreamSubscription<T> listen(void onData(T event), 23 StreamSubscription<T> listen(void onData(T event),
24 { void onError(error), 24 { void onError(error),
25 void onDone(), 25 void onDone(),
26 bool cancelOnError}) { 26 bool cancelOnError}) {
27 27
28 return new _EventStreamSubscription<T>( 28 return new _EventStreamSubscription<T>(
29 this._target, this._eventType, onData, this._useCapture); 29 this._target, this._eventType, onData, this._useCapture);
30 } 30 }
31 } 31 }
32 32
33 /** A specialized Stream available to [Element]s to enable event delegation. */
34 abstract class ElementStream<T extends Event> implements Stream<T> {
35
36 /**
37 * Return a stream that only fires when the particular event fires for
38 * elements matching the specified CSS selector.
39 *
40 * This is the Dart equivalent to jQuery's
41 * [delegate](http://api.jquery.com/delegate/).
42 */
43 Stream<T> filter(String selector) =>
blois 2013/08/02 20:13:02 Filter seems a bit generic for Streams (I could ea
Emily Fortuna 2013/08/07 23:38:25 Done.
44 this.where((event) => event.target.matches(selector));
blois 2013/08/02 20:21:25 Also, see the discussion in the bug about the ance
Emily Fortuna 2013/08/07 23:38:25 Done.
45 }
46
47 /**
48 * Adapter for exposing DOM Element events as streams, while also allowing
49 * event delegation.
50 */
51 class _ElementEventStreamImpl<T extends Event> extends _EventStream<T> with
blois 2013/08/02 20:13:02 Rather than the mixin, how about just declare filt
Emily Fortuna 2013/08/07 23:38:25 True, but then we have to write the identical code
52 ElementStream<T> {
53 _ElementEventStreamImpl(target, eventType, useCapture) :
54 super(target, eventType, useCapture);
55 }
56
57 /**
58 * Adapter for exposing events on a collection of DOM Elements as streams,
59 * while also allowing event delegation.
60 */
61 class _ElementListEventStreamImpl<T extends Event> extends Stream<T> with
Jennifer Messerly 2013/08/02 19:31:59 should this be "implements Stream"? it looks like
blois 2013/08/02 20:13:02 Can this be made more generic- a Stream which comb
Emily Fortuna 2013/08/07 23:38:25 Done.
Emily Fortuna 2013/08/07 23:38:25 Done.
62 ElementStream<T> {
63
64 StreamController _controller;
65
66 _ElementListEventStreamImpl(targetList, eventType, useCapture) {
67 _controller = new StreamController(sync: true);
Jennifer Messerly 2013/08/02 19:31:59 should this be a broadcast stream?
Emily Fortuna 2013/08/07 23:38:25 yes, thank you. done.
68 for (Element target in targetList) {
69 var stream = new _EventStream(target, eventType, useCapture);
Jennifer Messerly 2013/08/02 19:31:59 hmm, it looks like these listeners are never relea
blois 2013/08/02 20:13:02 See https://codereview.chromium.org/12220003/diff/
Emily Fortuna 2013/08/07 23:38:25 Done.
70 stream.listen((event) {
71 _controller.add(event);
72 return event;
73 });
74 }
75 }
76
77 // Delegate all regular Stream behavor to our wrapped Stream.
78 StreamSubscription<T> listen(void onData(T event),
79 { void onError(error),
80 void onDone(),
81 bool cancelOnError}) =>
82 _controller.stream.listen(onData, onError: onError, onDone: onDone,
Jennifer Messerly 2013/08/02 19:31:59 it is probably worth caching "_controller.stream".
Emily Fortuna 2013/08/07 23:38:25 Done.
83 cancelOnError: cancelOnError);
84 Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription),
85 void onCancel(StreamSubscription subscription)})
86 => _controller.stream;
87 bool get isBroadcast => true;
88 Stream<T> where(bool test(T event)) => _controller.stream.where(test);
89 Stream map(convert(T event)) => _controller.stream.map(convert);
blois 2013/08/02 20:13:02 Is it necessary to override all of these? Seems li
Emily Fortuna 2013/08/07 23:38:25 Since it's not actually a Stream and just implemen
90 Stream<T> handleError(void handle( error), { bool test(error) }) =>
91 _controller.stream.handleError(handle, test: test);
92 Stream expand(Iterable convert(T value)) =>
93 _controller.stream.expand(convert);
94 Future pipe(StreamConsumer<T> streamConsumer) =>
95 _controller.stream.pipe(streamConsumer);
96 Stream transform(StreamTransformer<T, dynamic> streamTransformer) =>
97 _controller.stream.transform(streamTransformer);
98 Future<T> reduce(T combine(T previous, T element)) =>
99 _controller.stream.reduce(combine);
100 Future fold(var initialValue, combine(var previous, T element)) =>
101 _controller.stream.fold(initialValue, combine);
102 Future<String> join([String separator = ""]) =>
103 _controller.stream.join(separator);
104 Future<bool> contains(Object needle) => _controller.stream.contains(needle);
105 Future forEach(void action(T element)) => _controller.stream.forEach(action);
106 Future<bool> every(bool test(T element)) => _controller.stream.every(test);
107 Future<bool> any(bool test(T element)) => _controller.stream.any(test);
108 Future<int> get length => _controller.stream.length;
109 Future<bool> get isEmpty => _controller.stream.isEmpty;
110 Future<List<T>> toList() => _controller.stream.toList();
111 Future<Set<T>> toSet() => _controller.stream.toSet();
112 Future drain([var futureValue]) => _controller.stream.drain(futureValue);
113 Stream<T> take(int count) => _controller.stream.take(count);
114 Stream<T> takeWhile(bool test(T element)) =>
115 _controller.stream.takeWhile(test);
116 Stream<T> skip(int count) => _controller.stream.skip(count);
117 Stream<T> skipWhile(bool test(T element)) =>
118 _controller.stream.skipWhile(test);
119 Stream<T> distinct([bool equals(T previous, T next)]) =>
120 _controller.stream.distinct(equals);
121 Future<T> get first => _controller.stream.first;
122 Future<T> get last => _controller.stream.last;
123 Future<T> get single => _controller.stream.single;
124 Future<dynamic> firstWhere(bool test(T element), {Object defaultValue()}) =>
125 _controller.stream.firstWhere(test, defaultValue: defaultValue);
126 Future<dynamic> lastWhere(bool test(T element), {Object defaultValue()}) =>
127 _controller.stream.lastWhere(test, defaultValue: defaultValue);
128 Future<T> singleWhere(bool test(T element)) =>
129 _controller.stream.singleWhere(test);
130 Future<T> elementAt(int index) => _controller.stream.elementAt(index);
131 }
132
33 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { 133 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
34 int _pauseCount = 0; 134 int _pauseCount = 0;
35 EventTarget _target; 135 EventTarget _target;
36 final String _eventType; 136 final String _eventType;
37 var _onData; 137 var _onData;
38 final bool _useCapture; 138 final bool _useCapture;
39 139
40 _EventStreamSubscription(this._target, this._eventType, this._onData, 140 _EventStreamSubscription(this._target, this._eventType, this._onData,
41 this._useCapture) { 141 this._useCapture) {
42 _tryResume(); 142 _tryResume();
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 } 200 }
101 } 201 }
102 202
103 Future asFuture([var futureValue]) { 203 Future asFuture([var futureValue]) {
104 // We just need a future that will never succeed or fail. 204 // We just need a future that will never succeed or fail.
105 Completer completer = new Completer(); 205 Completer completer = new Completer();
106 return completer.future; 206 return completer.future;
107 } 207 }
108 } 208 }
109 209
110
111 /** 210 /**
112 * A factory to expose DOM events as Streams. 211 * A factory to expose DOM events as Streams.
113 */ 212 */
114 class EventStreamProvider<T extends Event> { 213 class EventStreamProvider<T extends Event> {
115 final String _eventType; 214 final String _eventType;
116 215
117 const EventStreamProvider(this._eventType); 216 const EventStreamProvider(this._eventType);
118 217
119 /** 218 /**
120 * Gets a [Stream] for this event type, on the specified target. 219 * Gets a [Stream] for this event type, on the specified target.
121 * 220 *
122 * This will always return a broadcast stream so multiple listeners can be 221 * This will always return a broadcast stream so multiple listeners can be
123 * used simultaneously. 222 * used simultaneously.
124 * 223 *
125 * This may be used to capture DOM events: 224 * This may be used to capture DOM events:
126 * 225 *
127 * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...); 226 * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
128 * 227 *
129 * Or for listening to an event which will bubble through the DOM tree: 228 * Or for listening to an event which will bubble through the DOM tree:
130 * 229 *
131 * MediaElement.pauseEvent.forTarget(document.body).listen(...); 230 * MediaElement.pauseEvent.forTarget(document.body).listen(...);
132 * 231 *
133 * See also: 232 * See also:
134 * 233 *
135 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis tener) 234 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis tener)
136 */ 235 */
137 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { 236 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
blois 2013/08/02 20:13:02 Since the signature is still returning Stream<T>,
Emily Fortuna 2013/08/07 23:38:25 But we should expect Element Event streams to alwa
138 return new _EventStream(e, _eventType, useCapture); 237 if (e is Element) {
238 return new _ElementEventStreamImpl(e, _eventType, useCapture);
239 } else {
240 return new _EventStream(e, _eventType, useCapture);
241 }
139 } 242 }
140 243
141 /** 244 /**
245 * Gets an [ElementEventStream] for this event type, on the specified element.
246 *
247 * This will always return a broadcast stream so multiple listeners can be
248 * used simultaneously.
249 *
250 * This may be used to capture DOM events:
251 *
252 * Element.keyDownEvent.forElementTarget(element, useCapture: true).listen (...);
253 *
254 * See also:
255 *
256 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis tener)
257 */
258 ElementStream<T> forElementTarget(Element e, {bool useCapture: false}) {
259 return new _ElementEventStreamImpl(e, _eventType, useCapture);
260 }
261
262 /**
263 * Gets an [ElementEventStream] for this event type, on the list of elements.
264 *
265 * This will always return a broadcast stream so multiple listeners can be
266 * used simultaneously.
267 *
268 * This may be used to capture DOM events:
269 *
270 * Element.keyDownEvent._forElementTargetList(element, useCapture: true).l isten(...);
271 *
272 * See also:
273 *
274 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis tener)
275 */
276 ElementStream<T> _forElementTargetList(ElementList e,
277 {bool useCapture: false}) {
278 return new _ElementListEventStreamImpl(e, _eventType, useCapture);
279 }
280
281 /**
142 * Gets the type of the event which this would listen for on the specified 282 * Gets the type of the event which this would listen for on the specified
143 * event target. 283 * event target.
144 * 284 *
145 * The target is necessary because some browsers may use different event names 285 * The target is necessary because some browsers may use different event names
146 * for the same purpose and the target allows differentiating browser support. 286 * for the same purpose and the target allows differentiating browser support.
147 */ 287 */
148 String getEventType(EventTarget target) { 288 String getEventType(EventTarget target) {
149 return _eventType; 289 return _eventType;
150 } 290 }
151 } 291 }
152 292
153 /** 293 /**
154 * A factory to expose DOM events as streams, where the DOM event name has to 294 * A factory to expose DOM events as streams, where the DOM event name has to
155 * be determined on the fly (for example, mouse wheel events). 295 * be determined on the fly (for example, mouse wheel events).
156 */ 296 */
157 class _CustomEventStreamProvider<T extends Event> 297 class _CustomEventStreamProvider<T extends Event>
158 implements EventStreamProvider<T> { 298 implements EventStreamProvider<T> {
159 299
160 final _eventTypeGetter; 300 final _eventTypeGetter;
161 const _CustomEventStreamProvider(this._eventTypeGetter); 301 const _CustomEventStreamProvider(this._eventTypeGetter);
162 302
163 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { 303 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) {
164 return new _EventStream(e, _eventTypeGetter(e), useCapture); 304 return new _EventStream(e, _eventTypeGetter(e), useCapture);
165 } 305 }
166 306
307 ElementStream<T> forElementTarget(Element e, {bool useCapture: false}) {
308 return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture);
309 }
310
311 ElementStream<T> _forElementTargetList(ElementList e,
312 {bool useCapture: false}) {
313 return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture);
314 }
315
167 String getEventType(EventTarget target) { 316 String getEventType(EventTarget target) {
168 return _eventTypeGetter(target); 317 return _eventTypeGetter(target);
169 } 318 }
170 } 319 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698