Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |