| 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 * Return a stream that only fires when the particular event fires for |
| 37 * elements matching the specified CSS selector. |
| 38 * |
| 39 * This is the Dart equivalent to jQuery's |
| 40 * [delegate](http://api.jquery.com/delegate/). |
| 41 */ |
| 42 Stream<T> matches(String selector); |
| 43 } |
| 44 |
| 45 /** |
| 46 * Adapter for exposing DOM Element events as streams, while also allowing |
| 47 * event delegation. |
| 48 */ |
| 49 class _ElementEventStreamImpl<T extends Event> extends _EventStream<T> |
| 50 implements ElementStream<T> { |
| 51 _ElementEventStreamImpl(target, eventType, useCapture) : |
| 52 super(target, eventType, useCapture); |
| 53 |
| 54 Stream<T> matches(String selector) => |
| 55 this.where((event) => event.target.matches(selector, true)); |
| 56 } |
| 57 |
| 58 /** |
| 59 * Adapter for exposing events on a collection of DOM Elements as streams, |
| 60 * while also allowing event delegation. |
| 61 */ |
| 62 class _ElementListEventStreamImpl<T extends Event> extends Stream<T> |
| 63 implements ElementStream<T> { |
| 64 final _StreamPool _pool; |
| 65 Stream<T> _stream; |
| 66 |
| 67 _ElementListEventStreamImpl(targetList, eventType, useCapture) : |
| 68 _pool = new _StreamPool.broadcast() { |
| 69 for (Element target in targetList) { |
| 70 var stream = new _EventStream(target, eventType, useCapture); |
| 71 _pool.add(stream); |
| 72 } |
| 73 _stream = _pool.stream; |
| 74 } |
| 75 |
| 76 Stream<T> matches(String selector) => |
| 77 this.where((event) => event.target.matches(selector, true)); |
| 78 |
| 79 // Delegate all regular Stream behavor to our wrapped Stream. |
| 80 StreamSubscription<T> listen(void onData(T event), |
| 81 { void onError(error), |
| 82 void onDone(), |
| 83 bool cancelOnError}) => |
| 84 _stream.listen(onData, onError: onError, onDone: onDone, |
| 85 cancelOnError: cancelOnError); |
| 86 Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription), |
| 87 void onCancel(StreamSubscription subscription)}) |
| 88 => _stream; |
| 89 bool get isBroadcast => true; |
| 90 } |
| 91 |
| 92 /** |
| 93 * A pool of streams whose events are unified and emitted through a central |
| 94 * stream. |
| 95 */ |
| 96 // TODO (efortuna): Remove this when Issue 12218 is addressed. |
| 97 class _StreamPool<T> { |
| 98 StreamController<T> _controller; |
| 99 |
| 100 /// Subscriptions to the streams that make up the pool. |
| 101 var _subscriptions = new Map<Stream<T>, StreamSubscription<T>>(); |
| 102 |
| 103 /** |
| 104 * Creates a new stream pool where [stream] can be listened to more than |
| 105 * once. |
| 106 * |
| 107 * Any events from buffered streams in the pool will be emitted immediately, |
| 108 * regardless of whether [stream] has any subscribers. |
| 109 */ |
| 110 _StreamPool.broadcast() { |
| 111 _controller = new StreamController<T>.broadcast(sync: true, |
| 112 onCancel: close); |
| 113 } |
| 114 |
| 115 /** |
| 116 * The stream through which all events from streams in the pool are emitted. |
| 117 */ |
| 118 Stream<T> get stream => _controller.stream; |
| 119 |
| 120 /** |
| 121 * Adds [stream] as a member of this pool. |
| 122 * |
| 123 * Any events from [stream] will be emitted through [this.stream]. If |
| 124 * [stream] is sync, they'll be emitted synchronously; if [stream] is async, |
| 125 * they'll be emitted asynchronously. |
| 126 */ |
| 127 void add(Stream<T> stream) { |
| 128 if (_subscriptions.containsKey(stream)) return; |
| 129 _subscriptions[stream] = stream.listen(_controller.add, |
| 130 onError: _controller.addError, |
| 131 onDone: () => remove(stream)); |
| 132 } |
| 133 |
| 134 /** Removes [stream] as a member of this pool. */ |
| 135 void remove(Stream<T> stream) { |
| 136 var subscription = _subscriptions.remove(stream); |
| 137 if (subscription != null) subscription.cancel(); |
| 138 } |
| 139 |
| 140 /** Removes all streams from this pool and closes [stream]. */ |
| 141 void close() { |
| 142 for (var subscription in _subscriptions.values) { |
| 143 subscription.cancel(); |
| 144 } |
| 145 _subscriptions.clear(); |
| 146 _controller.close(); |
| 147 } |
| 148 } |
| 149 |
| 33 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { | 150 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { |
| 34 int _pauseCount = 0; | 151 int _pauseCount = 0; |
| 35 EventTarget _target; | 152 EventTarget _target; |
| 36 final String _eventType; | 153 final String _eventType; |
| 37 var _onData; | 154 var _onData; |
| 38 final bool _useCapture; | 155 final bool _useCapture; |
| 39 | 156 |
| 40 _EventStreamSubscription(this._target, this._eventType, this._onData, | 157 _EventStreamSubscription(this._target, this._eventType, this._onData, |
| 41 this._useCapture) { | 158 this._useCapture) { |
| 42 _tryResume(); | 159 _tryResume(); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 } | 217 } |
| 101 } | 218 } |
| 102 | 219 |
| 103 Future asFuture([var futureValue]) { | 220 Future asFuture([var futureValue]) { |
| 104 // We just need a future that will never succeed or fail. | 221 // We just need a future that will never succeed or fail. |
| 105 Completer completer = new Completer(); | 222 Completer completer = new Completer(); |
| 106 return completer.future; | 223 return completer.future; |
| 107 } | 224 } |
| 108 } | 225 } |
| 109 | 226 |
| 110 | |
| 111 /** | 227 /** |
| 112 * A factory to expose DOM events as Streams. | 228 * A factory to expose DOM events as Streams. |
| 113 */ | 229 */ |
| 114 class EventStreamProvider<T extends Event> { | 230 class EventStreamProvider<T extends Event> { |
| 115 final String _eventType; | 231 final String _eventType; |
| 116 | 232 |
| 117 const EventStreamProvider(this._eventType); | 233 const EventStreamProvider(this._eventType); |
| 118 | 234 |
| 119 /** | 235 /** |
| 120 * Gets a [Stream] for this event type, on the specified target. | 236 * Gets a [Stream] for this event type, on the specified target. |
| 121 * | 237 * |
| 122 * This will always return a broadcast stream so multiple listeners can be | 238 * This will always return a broadcast stream so multiple listeners can be |
| 123 * used simultaneously. | 239 * used simultaneously. |
| 124 * | 240 * |
| 125 * This may be used to capture DOM events: | 241 * This may be used to capture DOM events: |
| 126 * | 242 * |
| 127 * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...); | 243 * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...); |
| 128 * | 244 * |
| 129 * Or for listening to an event which will bubble through the DOM tree: | 245 * Or for listening to an event which will bubble through the DOM tree: |
| 130 * | 246 * |
| 131 * MediaElement.pauseEvent.forTarget(document.body).listen(...); | 247 * MediaElement.pauseEvent.forTarget(document.body).listen(...); |
| 132 * | 248 * |
| 133 * See also: | 249 * See also: |
| 134 * | 250 * |
| 135 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) | 251 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) |
| 136 */ | 252 */ |
| 137 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { | 253 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) => |
| 138 return new _EventStream(e, _eventType, useCapture); | 254 new _EventStream(e, _eventType, useCapture); |
| 255 |
| 256 /** |
| 257 * Gets an [ElementEventStream] for this event type, on the specified element. |
| 258 * |
| 259 * This will always return a broadcast stream so multiple listeners can be |
| 260 * used simultaneously. |
| 261 * |
| 262 * This may be used to capture DOM events: |
| 263 * |
| 264 * Element.keyDownEvent.forElement(element, useCapture: true).listen(...); |
| 265 * |
| 266 * See also: |
| 267 * |
| 268 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) |
| 269 */ |
| 270 ElementStream<T> forElement(Element e, {bool useCapture: false}) { |
| 271 return new _ElementEventStreamImpl(e, _eventType, useCapture); |
| 139 } | 272 } |
| 140 | 273 |
| 141 /** | 274 /** |
| 275 * Gets an [ElementEventStream] for this event type, on the list of elements. |
| 276 * |
| 277 * This will always return a broadcast stream so multiple listeners can be |
| 278 * used simultaneously. |
| 279 * |
| 280 * This may be used to capture DOM events: |
| 281 * |
| 282 * Element.keyDownEvent._forElementList(element, useCapture: true).listen(
...); |
| 283 * |
| 284 * See also: |
| 285 * |
| 286 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) |
| 287 */ |
| 288 ElementStream<T> _forElementList(ElementList e, {bool useCapture: false}) { |
| 289 return new _ElementListEventStreamImpl(e, _eventType, useCapture); |
| 290 } |
| 291 |
| 292 /** |
| 142 * Gets the type of the event which this would listen for on the specified | 293 * Gets the type of the event which this would listen for on the specified |
| 143 * event target. | 294 * event target. |
| 144 * | 295 * |
| 145 * The target is necessary because some browsers may use different event names | 296 * The target is necessary because some browsers may use different event names |
| 146 * for the same purpose and the target allows differentiating browser support. | 297 * for the same purpose and the target allows differentiating browser support. |
| 147 */ | 298 */ |
| 148 String getEventType(EventTarget target) { | 299 String getEventType(EventTarget target) { |
| 149 return _eventType; | 300 return _eventType; |
| 150 } | 301 } |
| 151 } | 302 } |
| 152 | 303 |
| 153 /** | 304 /** |
| 154 * A factory to expose DOM events as streams, where the DOM event name has to | 305 * 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). | 306 * be determined on the fly (for example, mouse wheel events). |
| 156 */ | 307 */ |
| 157 class _CustomEventStreamProvider<T extends Event> | 308 class _CustomEventStreamProvider<T extends Event> |
| 158 implements EventStreamProvider<T> { | 309 implements EventStreamProvider<T> { |
| 159 | 310 |
| 160 final _eventTypeGetter; | 311 final _eventTypeGetter; |
| 161 const _CustomEventStreamProvider(this._eventTypeGetter); | 312 const _CustomEventStreamProvider(this._eventTypeGetter); |
| 162 | 313 |
| 163 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { | 314 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { |
| 164 return new _EventStream(e, _eventTypeGetter(e), useCapture); | 315 return new _EventStream(e, _eventTypeGetter(e), useCapture); |
| 165 } | 316 } |
| 166 | 317 |
| 318 ElementStream<T> forElement(Element e, {bool useCapture: false}) { |
| 319 return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture); |
| 320 } |
| 321 |
| 322 ElementStream<T> _forElementList(ElementList e, |
| 323 {bool useCapture: false}) { |
| 324 return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture); |
| 325 } |
| 326 |
| 167 String getEventType(EventTarget target) { | 327 String getEventType(EventTarget target) { |
| 168 return _eventTypeGetter(target); | 328 return _eventTypeGetter(target); |
| 169 } | 329 } |
| 170 } | 330 } |
| OLD | NEW |