Chromium Code Reviews| Index: tools/dom/src/EventStreamProvider.dart |
| diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c4e845b2788d7c33ef55c6ede1eddde654e3423e |
| --- /dev/null |
| +++ b/tools/dom/src/EventStreamProvider.dart |
| @@ -0,0 +1,144 @@ |
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +part of html; |
| + |
| +/** |
| + * Adapter for exposing DOM events as Dart streams. |
| + */ |
| +class _EventStream<T extends Event> extends Stream<T> { |
| + final EventTarget _target; |
| + final String _eventType; |
| + final bool _useCapture; |
| + |
| + _EventStream(this._target, this._eventType, this._useCapture); |
| + |
| + StreamSubscription<T> listen(void onData(T event), |
| + { void onError(AsyncError error), |
| + void onDone(), |
| + bool unsubscribeOnError}) { |
| + |
| + if (onError != null) { |
| + throw new ArgumentError('onError is not supported by DOM events'); |
|
floitsch
2013/01/12 00:49:33
I would just discard it. It is supported, but the
blois
2013/01/12 01:42:52
Done.
Old compatibility habits- always throw exce
|
| + } |
| + if (onDone != null) { |
|
floitsch
2013/01/12 00:49:33
ditto.
blois
2013/01/12 01:42:52
Done.
|
| + throw new ArgumentError('onError is not supported by DOM events'); |
| + } |
| + if (unsubscribeOnError != null) { |
|
floitsch
2013/01/12 00:49:33
ditto.
blois
2013/01/12 01:42:52
Done.
|
| + throw new ArgumentError( |
| + 'unsubscribeOnError is not supported by DOM events'); |
| + } |
| + |
| + return new _EventStreamSubscription<T>( |
| + this._target, this._eventType, onData, this._useCapture); |
| + } |
| +} |
| + |
| +class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> { |
|
floitsch
2013/01/12 00:49:33
This is pretty much what I was looking for.
I don
Jennifer Messerly
2013/01/12 01:11:25
+1, this is so nice
|
| + int _pauseCount = 0; |
| + EventTarget _target; |
| + final String _eventType; |
| + var _onData; |
| + final bool _useCapture; |
| + |
| + _EventStreamSubscription(this._target, this._eventType, this._onData, |
| + this._useCapture) { |
| + _tryResume(); |
| + } |
| + |
| + void cancel() { |
| + if (_canceled) { |
| + throw new StateError("Subscription has been canceled."); |
| + } |
| + |
| + _unlisten(); |
| + // Clear out the target to indicate this is complete. |
|
Jennifer Messerly
2013/01/12 01:11:25
also has the nice side effect of releasing memory
blois
2013/01/12 01:42:52
Done.
|
| + _target = null; |
| + } |
| + |
| + bool get _canceled => _target == null; |
| + |
| + void onData(void handleData(T event)) { |
| + if (_canceled) { |
| + throw new StateError("Subscription has been canceled."); |
| + } |
| + // Remove current event listener. |
| + _unlisten(); |
| + |
| + _onData = handleData; |
|
Jennifer Messerly
2013/01/12 01:11:25
is this allowed to be null? I see some checks for
blois
2013/01/12 01:42:52
onData can be null from the listen call and I beli
|
| + _tryResume(); |
| + } |
| + |
| + void onError(void handleError(AsyncError error)) { |
| + throw new UnsupportedError('Not supported by DOM events'); |
|
floitsch
2013/01/12 00:49:33
ditto: just ignore it.
blois
2013/01/12 01:42:52
Done.
|
| + } |
| + |
| + void onDone(void handleDone()) { |
| + throw new UnsupportedError('Not supported by DOM events'); |
| + } |
| + |
| + void pause([Future resumeSignal]) { |
| + if (_canceled) { |
| + throw new StateError("Subscription has been canceled."); |
| + } |
| + ++_pauseCount; |
| + _unlisten(); |
| + |
| + if (resumeSignal != null) { |
| + resumeSignal.whenComplete(resume); |
| + } |
| + } |
| + |
| + void resume() { |
|
Jennifer Messerly
2013/01/12 01:11:25
this should probably check if paused. The _StreamS
blois
2013/01/12 01:42:52
Done.
|
| + if (_canceled) { |
| + throw new StateError("Subscription has been canceled."); |
| + } |
| + if (_pauseCount == 0) { |
| + throw new StateError("Subscription is not paused."); |
| + } |
| + --_pauseCount; |
| + _tryResume(); |
| + } |
| + |
| + void _tryResume() { |
| + if (_onData != null && _pauseCount == 0) { |
| + _target.$dom_addEventListener(_eventType, _onData, _useCapture); |
| + } |
| + } |
| + |
| + void _unlisten() { |
| + if (_onData != null) { |
| + _target.$dom_removeEventListener(_eventType, _onData, _useCapture); |
|
Jennifer Messerly
2013/01/12 01:11:25
should this set _onData to null after unregisterin
blois
2013/01/12 01:42:52
We unlisten when it's paused, but can resume later
|
| + } |
| + } |
| +} |
| + |
| + |
| +/** |
| + * A factory to expose DOM events as Streams. |
| + */ |
| +class EventStreamProvider<T extends Event> { |
| + final String _eventType; |
| + |
| + const EventStreamProvider(this._eventType); |
| + |
| + /** |
| + * Gets a [Stream] for this event type, on the specified target. |
| + * |
| + * This may be used to capture DOM events: |
| + * |
| + * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...); |
| + * |
| + * Or for listening to an event which will bubble through the DOM tree: |
| + * |
| + * MediaElement.pauseEvent.forTarget(document.body).listen(...); |
| + * |
| + * See also: |
| + * |
| + * [addEventListener](http://docs.webplatform.org/wiki/dom/methods/addEventListener) |
| + */ |
| + Stream<T> forTarget(EventTarget e, {bool useCapture: false}) { |
| + return new _EventStream(e, _eventType, useCapture); |
| + } |
| +} |