| 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 * A factory to expose DOM events as Streams. | 8 * A factory to expose DOM events as Streams. |
| 9 */ | 9 */ |
| 10 class EventStreamProvider<T extends Event> { | 10 class EventStreamProvider<T extends Event> { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 * | 27 * |
| 28 * Or for listening to an event which will bubble through the DOM tree: | 28 * Or for listening to an event which will bubble through the DOM tree: |
| 29 * | 29 * |
| 30 * MediaElement.pauseEvent.forTarget(document.body).listen(...); | 30 * MediaElement.pauseEvent.forTarget(document.body).listen(...); |
| 31 * | 31 * |
| 32 * See also: | 32 * See also: |
| 33 * | 33 * |
| 34 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) | 34 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) |
| 35 */ | 35 */ |
| 36 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) => | 36 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) => |
| 37 new _EventStream(e, _eventType, useCapture); | 37 new _EventStream<T>(e, _eventType, useCapture); |
| 38 | 38 |
| 39 /** | 39 /** |
| 40 * Gets an [ElementEventStream] for this event type, on the specified element. | 40 * Gets an [ElementEventStream] for this event type, on the specified element. |
| 41 * | 41 * |
| 42 * This will always return a broadcast stream so multiple listeners can be | 42 * This will always return a broadcast stream so multiple listeners can be |
| 43 * used simultaneously. | 43 * used simultaneously. |
| 44 * | 44 * |
| 45 * This may be used to capture DOM events: | 45 * This may be used to capture DOM events: |
| 46 * | 46 * |
| 47 * Element.keyDownEvent.forElement(element, useCapture: true).listen(...); | 47 * Element.keyDownEvent.forElement(element, useCapture: true).listen(...); |
| 48 * | 48 * |
| 49 * // Alternate method: | 49 * // Alternate method: |
| 50 * Element.keyDownEvent.forElement(element).capture(...); | 50 * Element.keyDownEvent.forElement(element).capture(...); |
| 51 * | 51 * |
| 52 * Or for listening to an event which will bubble through the DOM tree: | 52 * Or for listening to an event which will bubble through the DOM tree: |
| 53 * | 53 * |
| 54 * MediaElement.pauseEvent.forElement(document.body).listen(...); | 54 * MediaElement.pauseEvent.forElement(document.body).listen(...); |
| 55 * | 55 * |
| 56 * See also: | 56 * See also: |
| 57 * | 57 * |
| 58 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) | 58 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) |
| 59 */ | 59 */ |
| 60 ElementStream<T> forElement(Element e, {bool useCapture: false}) { | 60 ElementStream<T> forElement(Element e, {bool useCapture: false}) { |
| 61 return new _ElementEventStreamImpl(e, _eventType, useCapture); | 61 return new _ElementEventStreamImpl<T>(e, _eventType, useCapture); |
| 62 } | 62 } |
| 63 | 63 |
| 64 /** | 64 /** |
| 65 * Gets an [ElementEventStream] for this event type, on the list of elements. | 65 * Gets an [ElementEventStream] for this event type, on the list of elements. |
| 66 * | 66 * |
| 67 * This will always return a broadcast stream so multiple listeners can be | 67 * This will always return a broadcast stream so multiple listeners can be |
| 68 * used simultaneously. | 68 * used simultaneously. |
| 69 * | 69 * |
| 70 * This may be used to capture DOM events: | 70 * This may be used to capture DOM events: |
| 71 * | 71 * |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 * Adapter for exposing DOM events as Dart streams. | 122 * Adapter for exposing DOM events as Dart streams. |
| 123 */ | 123 */ |
| 124 class _EventStream<T extends Event> extends Stream<T> { | 124 class _EventStream<T extends Event> extends Stream<T> { |
| 125 final EventTarget _target; | 125 final EventTarget _target; |
| 126 final String _eventType; | 126 final String _eventType; |
| 127 final bool _useCapture; | 127 final bool _useCapture; |
| 128 | 128 |
| 129 _EventStream(this._target, this._eventType, this._useCapture); | 129 _EventStream(this._target, this._eventType, this._useCapture); |
| 130 | 130 |
| 131 // DOM events are inherently multi-subscribers. | 131 // DOM events are inherently multi-subscribers. |
| 132 Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription), | 132 Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription)
, |
| 133 void onCancel(StreamSubscription subscription)}) | 133 void onCancel(StreamSubscription<T> subscription)
}) |
| 134 => this; | 134 => this; |
| 135 bool get isBroadcast => true; | 135 bool get isBroadcast => true; |
| 136 | 136 |
| 137 StreamSubscription<T> listen(void onData(T event), | 137 StreamSubscription<T> listen(void onData(T event), |
| 138 { Function onError, | 138 { Function onError, |
| 139 void onDone(), | 139 void onDone(), |
| 140 bool cancelOnError}) { | 140 bool cancelOnError}) { |
| 141 | 141 |
| 142 return new _EventStreamSubscription<T>( | 142 return new _EventStreamSubscription<T>( |
| 143 this._target, this._eventType, onData, this._useCapture); | 143 this._target, this._eventType, onData, this._useCapture); |
| 144 } | 144 } |
| 145 } | 145 } |
| 146 | 146 |
| 147 bool _matchesWithAncestors(Event event, String selector) { |
| 148 var target = event.target; |
| 149 return target is Element ? target.matchesWithAncestors(selector) : false; |
| 150 } |
| 151 |
| 147 /** | 152 /** |
| 148 * Adapter for exposing DOM Element events as streams, while also allowing | 153 * Adapter for exposing DOM Element events as streams, while also allowing |
| 149 * event delegation. | 154 * event delegation. |
| 150 */ | 155 */ |
| 151 class _ElementEventStreamImpl<T extends Event> extends _EventStream<T> | 156 class _ElementEventStreamImpl<T extends Event> extends _EventStream<T> |
| 152 implements ElementStream<T> { | 157 implements ElementStream<T> { |
| 153 _ElementEventStreamImpl(target, eventType, useCapture) : | 158 _ElementEventStreamImpl(target, eventType, useCapture) : |
| 154 super(target, eventType, useCapture); | 159 super(target, eventType, useCapture); |
| 155 | 160 |
| 156 Stream<T> matches(String selector) => this.where( | 161 Stream<T> matches(String selector) => this.where( |
| 157 (event) => event.target.matchesWithAncestors(selector)).map((e) { | 162 (event) => _matchesWithAncestors(event, selector)).map((e) { |
| 158 e._selector = selector; | 163 e._selector = selector; |
| 159 return e; | 164 return e; |
| 160 }); | 165 }); |
| 161 | 166 |
| 162 StreamSubscription<T> capture(void onData(T event)) => | 167 StreamSubscription<T> capture(void onData(T event)) => |
| 163 new _EventStreamSubscription<T>( | 168 new _EventStreamSubscription<T>( |
| 164 this._target, this._eventType, onData, true); | 169 this._target, this._eventType, onData, true); |
| 165 } | 170 } |
| 166 | 171 |
| 167 /** | 172 /** |
| 168 * Adapter for exposing events on a collection of DOM Elements as streams, | 173 * Adapter for exposing events on a collection of DOM Elements as streams, |
| 169 * while also allowing event delegation. | 174 * while also allowing event delegation. |
| 170 */ | 175 */ |
| 171 class _ElementListEventStreamImpl<T extends Event> extends Stream<T> | 176 class _ElementListEventStreamImpl<T extends Event> extends Stream<T> |
| 172 implements ElementStream<T> { | 177 implements ElementStream<T> { |
| 173 final Iterable<Element> _targetList; | 178 final Iterable<Element> _targetList; |
| 174 final bool _useCapture; | 179 final bool _useCapture; |
| 175 final String _eventType; | 180 final String _eventType; |
| 176 | 181 |
| 177 _ElementListEventStreamImpl( | 182 _ElementListEventStreamImpl( |
| 178 this._targetList, this._eventType, this._useCapture); | 183 this._targetList, this._eventType, this._useCapture); |
| 179 | 184 |
| 180 Stream<T> matches(String selector) => this.where( | 185 Stream<T> matches(String selector) => this.where( |
| 181 (event) => event.target.matchesWithAncestors(selector)).map((e) { | 186 (event) => _matchesWithAncestors(event, selector)).map((e) { |
| 182 e._selector = selector; | 187 e._selector = selector; |
| 183 return e; | 188 return e; |
| 184 }); | 189 }); |
| 185 | 190 |
| 186 // Delegate all regular Stream behavior to a wrapped Stream. | 191 // Delegate all regular Stream behavior to a wrapped Stream. |
| 187 StreamSubscription<T> listen(void onData(T event), | 192 StreamSubscription<T> listen(void onData(T event), |
| 188 { Function onError, | 193 { Function onError, |
| 189 void onDone(), | 194 void onDone(), |
| 190 bool cancelOnError}) { | 195 bool cancelOnError}) { |
| 191 var pool = new _StreamPool.broadcast(); | 196 var pool = new _StreamPool<T>.broadcast(); |
| 192 for (var target in _targetList) { | 197 for (var target in _targetList) { |
| 193 pool.add(new _EventStream(target, _eventType, _useCapture)); | 198 pool.add(new _EventStream<T>(target, _eventType, _useCapture)); |
| 194 } | 199 } |
| 195 return pool.stream.listen(onData, onError: onError, onDone: onDone, | 200 return pool.stream.listen(onData, onError: onError, onDone: onDone, |
| 196 cancelOnError: cancelOnError); | 201 cancelOnError: cancelOnError); |
| 197 } | 202 } |
| 198 | 203 |
| 199 StreamSubscription<T> capture(void onData(T event)) { | 204 StreamSubscription<T> capture(void onData(T event)) { |
| 200 var pool = new _StreamPool.broadcast(); | 205 var pool = new _StreamPool<T>.broadcast(); |
| 201 for (var target in _targetList) { | 206 for (var target in _targetList) { |
| 202 pool.add(new _EventStream(target, _eventType, true)); | 207 pool.add(new _EventStream<T>(target, _eventType, true)); |
| 203 } | 208 } |
| 204 return pool.stream.listen(onData); | 209 return pool.stream.listen(onData); |
| 205 } | 210 } |
| 206 | 211 |
| 207 Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription), | 212 Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription)
, |
| 208 void onCancel(StreamSubscription subscription)}) | 213 void onCancel(StreamSubscription<T> subscription)
}) |
| 209 => this; | 214 => this; |
| 210 bool get isBroadcast => true; | 215 bool get isBroadcast => true; |
| 211 } | 216 } |
| 212 | 217 |
| 218 // We would like this to just be EventListener<T> but that typdef cannot |
| 219 // use generics until dartbug/26276 is fixed. |
| 220 typedef _EventListener<T extends Event>(T event); |
| 221 |
| 213 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { | 222 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { |
| 214 int _pauseCount = 0; | 223 int _pauseCount = 0; |
| 215 EventTarget _target; | 224 EventTarget _target; |
| 216 final String _eventType; | 225 final String _eventType; |
| 217 var _onData; | 226 EventListener _onData; |
| 218 final bool _useCapture; | 227 final bool _useCapture; |
| 219 | 228 |
| 220 _EventStreamSubscription(this._target, this._eventType, onData, | 229 // TODO(jacobr): for full strong mode correctness we should write |
| 221 this._useCapture) : _onData = _wrapZone(onData) { | 230 // _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((e) => onDa
ta(e as T)) |
| 231 // but that breaks 114 co19 tests as well as multiple html tests as it is reas
onable |
| 232 // to pass the wrong type of event object to an event listener as part of a |
| 233 // test. |
| 234 _EventStreamSubscription(this._target, this._eventType, void onData(T event), |
| 235 this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) { |
| 222 _tryResume(); | 236 _tryResume(); |
| 223 } | 237 } |
| 224 | 238 |
| 225 Future cancel() { | 239 Future cancel() { |
| 226 if (_canceled) return null; | 240 if (_canceled) return null; |
| 227 | 241 |
| 228 _unlisten(); | 242 _unlisten(); |
| 229 // Clear out the target to indicate this is complete. | 243 // Clear out the target to indicate this is complete. |
| 230 _target = null; | 244 _target = null; |
| 231 _onData = null; | 245 _onData = null; |
| 232 return null; | 246 return null; |
| 233 } | 247 } |
| 234 | 248 |
| 235 bool get _canceled => _target == null; | 249 bool get _canceled => _target == null; |
| 236 | 250 |
| 237 void onData(void handleData(T event)) { | 251 void onData(void handleData(T event)) { |
| 238 if (_canceled) { | 252 if (_canceled) { |
| 239 throw new StateError("Subscription has been canceled."); | 253 throw new StateError("Subscription has been canceled."); |
| 240 } | 254 } |
| 241 // Remove current event listener. | 255 // Remove current event listener. |
| 242 _unlisten(); | 256 _unlisten(); |
| 243 | 257 _onData = _wrapZone/*<Event, dynamic>*/(handleData); |
| 244 _onData = _wrapZone(handleData); | |
| 245 _tryResume(); | 258 _tryResume(); |
| 246 } | 259 } |
| 247 | 260 |
| 248 /// Has no effect. | 261 /// Has no effect. |
| 249 void onError(Function handleError) {} | 262 void onError(Function handleError) {} |
| 250 | 263 |
| 251 /// Has no effect. | 264 /// Has no effect. |
| 252 void onDone(void handleDone()) {} | 265 void onDone(void handleDone()) {} |
| 253 | 266 |
| 254 void pause([Future resumeSignal]) { | 267 void pause([Future resumeSignal]) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 | 326 |
| 314 // Delegate all regular Stream behavior to our wrapped Stream. | 327 // Delegate all regular Stream behavior to our wrapped Stream. |
| 315 StreamSubscription<T> listen(void onData(T event), | 328 StreamSubscription<T> listen(void onData(T event), |
| 316 { Function onError, | 329 { Function onError, |
| 317 void onDone(), | 330 void onDone(), |
| 318 bool cancelOnError}) { | 331 bool cancelOnError}) { |
| 319 return _streamController.stream.listen(onData, onError: onError, | 332 return _streamController.stream.listen(onData, onError: onError, |
| 320 onDone: onDone, cancelOnError: cancelOnError); | 333 onDone: onDone, cancelOnError: cancelOnError); |
| 321 } | 334 } |
| 322 | 335 |
| 323 Stream<T> asBroadcastStream({void onListen(StreamSubscription subscription), | 336 Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription)
, |
| 324 void onCancel(StreamSubscription subscription)}) | 337 void onCancel(StreamSubscription<T> subscription)
}) |
| 325 => _streamController.stream; | 338 => _streamController.stream; |
| 326 | 339 |
| 327 bool get isBroadcast => true; | 340 bool get isBroadcast => true; |
| 328 | 341 |
| 329 void add(T event) { | 342 void add(T event) { |
| 330 if (event.type == _type) _streamController.add(event); | 343 if (event.type == _type) _streamController.add(event); |
| 331 } | 344 } |
| 332 } | 345 } |
| 333 | 346 |
| 334 class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent> | 347 class _CustomKeyEventStreamImpl extends _CustomEventStreamImpl<KeyEvent> |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 * A factory to expose DOM events as streams, where the DOM event name has to | 418 * A factory to expose DOM events as streams, where the DOM event name has to |
| 406 * be determined on the fly (for example, mouse wheel events). | 419 * be determined on the fly (for example, mouse wheel events). |
| 407 */ | 420 */ |
| 408 class _CustomEventStreamProvider<T extends Event> | 421 class _CustomEventStreamProvider<T extends Event> |
| 409 implements EventStreamProvider<T> { | 422 implements EventStreamProvider<T> { |
| 410 | 423 |
| 411 final _eventTypeGetter; | 424 final _eventTypeGetter; |
| 412 const _CustomEventStreamProvider(this._eventTypeGetter); | 425 const _CustomEventStreamProvider(this._eventTypeGetter); |
| 413 | 426 |
| 414 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { | 427 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { |
| 415 return new _EventStream(e, _eventTypeGetter(e), useCapture); | 428 return new _EventStream<T>(e, _eventTypeGetter(e), useCapture); |
| 416 } | 429 } |
| 417 | 430 |
| 418 ElementStream<T> forElement(Element e, {bool useCapture: false}) { | 431 ElementStream<T> forElement(Element e, {bool useCapture: false}) { |
| 419 return new _ElementEventStreamImpl(e, _eventTypeGetter(e), useCapture); | 432 return new _ElementEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture); |
| 420 } | 433 } |
| 421 | 434 |
| 422 ElementStream<T> _forElementList(ElementList e, | 435 ElementStream<T> _forElementList(ElementList e, |
| 423 {bool useCapture: false}) { | 436 {bool useCapture: false}) { |
| 424 return new _ElementListEventStreamImpl(e, _eventTypeGetter(e), useCapture); | 437 return new _ElementListEventStreamImpl<T>(e, _eventTypeGetter(e), useCapture
); |
| 425 } | 438 } |
| 426 | 439 |
| 427 String getEventType(EventTarget target) { | 440 String getEventType(EventTarget target) { |
| 428 return _eventTypeGetter(target); | 441 return _eventTypeGetter(target); |
| 429 } | 442 } |
| 430 | 443 |
| 431 String get _eventType => | 444 String get _eventType => |
| 432 throw new UnsupportedError('Access type through getEventType method.'); | 445 throw new UnsupportedError('Access type through getEventType method.'); |
| 433 } | 446 } |
| OLD | NEW |