| 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 /** | |
| 8 * Adapter for exposing DOM events as Dart streams. | |
| 9 */ | |
| 10 class _EventStream<T extends Event> extends Stream<T> { | |
| 11 final EventTarget _target; | |
| 12 final String _eventType; | |
| 13 final bool _useCapture; | |
| 14 | |
| 15 _EventStream(this._target, this._eventType, this._useCapture); | |
| 16 | |
| 17 // DOM events are inherently multi-subscribers. | |
| 18 Stream<T> asBroadcastStream() => this; | |
| 19 bool get isBroadcast => true; | |
| 20 | |
| 21 StreamSubscription<T> listen(void onData(T event), | |
| 22 { void onError(error), | |
| 23 void onDone(), | |
| 24 bool cancelOnError}) { | |
| 25 | |
| 26 return new _EventStreamSubscription<T>( | |
| 27 this._target, this._eventType, onData, this._useCapture); | |
| 28 } | |
| 29 } | |
| 30 | |
| 31 class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { | |
| 32 int _pauseCount = 0; | |
| 33 EventTarget _target; | |
| 34 final String _eventType; | |
| 35 var _onData; | |
| 36 final bool _useCapture; | |
| 37 | |
| 38 _EventStreamSubscription(this._target, this._eventType, this._onData, | |
| 39 this._useCapture) { | |
| 40 _tryResume(); | |
| 41 } | |
| 42 | |
| 43 void cancel() { | |
| 44 if (_canceled) return; | |
| 45 | |
| 46 _unlisten(); | |
| 47 // Clear out the target to indicate this is complete. | |
| 48 _target = null; | |
| 49 _onData = null; | |
| 50 } | |
| 51 | |
| 52 bool get _canceled => _target == null; | |
| 53 | |
| 54 void onData(void handleData(T event)) { | |
| 55 if (_canceled) { | |
| 56 throw new StateError("Subscription has been canceled."); | |
| 57 } | |
| 58 // Remove current event listener. | |
| 59 _unlisten(); | |
| 60 | |
| 61 _onData = handleData; | |
| 62 _tryResume(); | |
| 63 } | |
| 64 | |
| 65 /// Has no effect. | |
| 66 void onError(void handleError(error)) {} | |
| 67 | |
| 68 /// Has no effect. | |
| 69 void onDone(void handleDone()) {} | |
| 70 | |
| 71 void pause([Future resumeSignal]) { | |
| 72 if (_canceled) return; | |
| 73 ++_pauseCount; | |
| 74 _unlisten(); | |
| 75 | |
| 76 if (resumeSignal != null) { | |
| 77 resumeSignal.whenComplete(resume); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 bool get isPaused => _pauseCount > 0; | |
| 82 | |
| 83 void resume() { | |
| 84 if (_canceled || !isPaused) return; | |
| 85 --_pauseCount; | |
| 86 _tryResume(); | |
| 87 } | |
| 88 | |
| 89 void _tryResume() { | |
| 90 if (_onData != null && !isPaused) { | |
| 91 _target.$dom_addEventListener(_eventType, _onData, _useCapture); | |
| 92 } | |
| 93 } | |
| 94 | |
| 95 void _unlisten() { | |
| 96 if (_onData != null) { | |
| 97 _target.$dom_removeEventListener(_eventType, _onData, _useCapture); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 Future asFuture([var futureValue]) { | |
| 102 // We just need a future that will never succeed or fail. | |
| 103 Completer completer = new Completer(); | |
| 104 return completer.future; | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 | 7 |
| 109 /** | 8 /** |
| 110 * A factory to expose DOM events as Streams. | 9 * A factory to expose DOM events as Streams. |
| 111 */ | 10 */ |
| 112 class EventStreamProvider<T extends Event> { | 11 class EventStreamProvider<T extends Event> { |
| 113 final String _eventType; | 12 final String _eventType; |
| 114 | 13 |
| 115 const EventStreamProvider(this._eventType); | 14 const EventStreamProvider(this._eventType); |
| 116 | 15 |
| 117 /** | 16 /** |
| 118 * Gets a [Stream] for this event type, on the specified target. | 17 * Gets a [Stream] for this event type, on the specified target. |
| 119 * | 18 * |
| 120 * This will always return a broadcast stream so multiple listeners can be | 19 * This will always return a broadcast stream so multiple listeners can be |
| 121 * used simultaneously. | 20 * used simultaneously. |
| 122 * | 21 * |
| 123 * This may be used to capture DOM events: | 22 * This may be used to capture DOM events: |
| 124 * | 23 * |
| 125 * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...); | 24 * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...); |
| 126 * | 25 * |
| 127 * Or for listening to an event which will bubble through the DOM tree: | 26 * Or for listening to an event which will bubble through the DOM tree: |
| 128 * | 27 * |
| 129 * MediaElement.pauseEvent.forTarget(document.body).listen(...); | 28 * MediaElement.pauseEvent.forTarget(document.body).listen(...); |
| 130 * | 29 * |
| 131 * See also: | 30 * See also: |
| 132 * | 31 * |
| 133 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) | 32 * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventLis
tener) |
| 134 */ | 33 */ |
| 135 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { | 34 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { |
| 136 return new _EventStream(e, _eventType, useCapture); | 35 var controller; |
| 36 |
| 37 void onData(data) { |
| 38 controller.add(data); |
| 39 } |
| 40 |
| 41 controller = new StreamController<T>( |
| 42 onListen: () { |
| 43 e.$dom_addEventListener(_eventType, onData, useCapture); |
| 44 }, |
| 45 onCancel: () { |
| 46 e.$dom_removeEventListener(_eventType, onData, useCapture); |
| 47 }, |
| 48 sync: true); |
| 49 |
| 50 return controller.stream; |
| 137 } | 51 } |
| 138 | 52 |
| 139 /** | 53 /** |
| 140 * Gets the type of the event which this would listen for on the specified | 54 * Gets the type of the event which this would listen for on the specified |
| 141 * event target. | 55 * event target. |
| 142 * | 56 * |
| 143 * The target is necessary because some browsers may use different event names | 57 * The target is necessary because some browsers may use different event names |
| 144 * for the same purpose and the target allows differentiating browser support. | 58 * for the same purpose and the target allows differentiating browser support. |
| 145 */ | 59 */ |
| 146 String getEventType(EventTarget target) { | 60 String getEventType(EventTarget target) { |
| 147 return _eventType; | 61 return _eventType; |
| 148 } | 62 } |
| 149 } | 63 } |
| 150 | 64 |
| 151 /** | 65 /** |
| 152 * A factory to expose DOM events as streams, where the DOM event name has to | 66 * A factory to expose DOM events as streams, where the DOM event name has to |
| 153 * be determined on the fly (for example, mouse wheel events). | 67 * be determined on the fly (for example, mouse wheel events). |
| 154 */ | 68 */ |
| 155 class _CustomEventStreamProvider<T extends Event> | 69 class _CustomEventStreamProvider<T extends Event> |
| 156 implements EventStreamProvider<T> { | 70 implements EventStreamProvider<T> { |
| 157 | 71 |
| 158 final _eventTypeGetter; | 72 final _eventTypeGetter; |
| 159 const _CustomEventStreamProvider(this._eventTypeGetter); | 73 const _CustomEventStreamProvider(this._eventTypeGetter); |
| 160 | 74 |
| 161 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { | 75 Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { |
| 162 return new _EventStream(e, _eventTypeGetter(e), useCapture); | 76 var controller; |
| 77 |
| 78 var eventType = _eventTypeGetter(e); |
| 79 |
| 80 void onData(data) { |
| 81 controller.add(data); |
| 82 } |
| 83 |
| 84 controller = new StreamController<T>( |
| 85 onListen: () { |
| 86 e.$dom_addEventListener(eventType, onData, useCapture); |
| 87 }, |
| 88 onCancel: () { |
| 89 e.$dom_removeEventListener(eventType, onData, useCapture); |
| 90 }, |
| 91 sync: true); |
| 92 |
| 93 return controller.stream; |
| 163 } | 94 } |
| 164 | 95 |
| 165 String getEventType(EventTarget target) { | 96 String getEventType(EventTarget target) { |
| 166 return _eventTypeGetter(target); | 97 return _eventTypeGetter(target); |
| 167 } | 98 } |
| 168 } | 99 } |
| OLD | NEW |