Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Unified Diff: tools/dom/src/EventStreamProvider.dart

Issue 2022263002: Make Dom events run through zone tasks. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Mark as experimental Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tests/html/event_zone_task_test.dart ('k') | tools/dom/src/shared_html.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/dom/src/EventStreamProvider.dart
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 474a1431b9defe83d3cc156678d63c763044a1a9..b6c32fc6c5c9f0a483166c7a23244cde40895561 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -118,6 +118,41 @@ abstract class ElementStream<T extends Event> implements Stream<T> {
StreamSubscription<T> capture(void onData(T event));
}
+/// Task specification for DOM Events.
+///
+/// *Experimental*. May disappear without notice.
+class EventSubscriptionSpecification<T extends Event>
+ implements TaskSpecification {
+ @override
+ final String name;
+ @override
+ final bool isOneShot;
+
+ final EventTarget target;
+ /// The event-type of the event. For example 'click' for click events.
+ final String eventType;
+ // TODO(floitsch): the first generic argument should be 'void'.
+ final ZoneUnaryCallback<dynamic, T> onData;
+ final bool useCapture;
+
+ EventSubscriptionSpecification({this.name, this.isOneShot, this.target,
+ this.eventType, void this.onData(T event), this.useCapture});
+
+ /// Returns a copy of this instance, with every non-null argument replaced
+ /// by the given value.
+ EventSubscriptionSpecification<T> replace(
+ {String name, bool isOneShot, EventTarget target,
+ String eventType, void onData(T event), bool useCapture}) {
+ return new EventSubscriptionSpecification<T>(
+ name: name ?? this.name,
+ isOneShot: isOneShot ?? this.isOneShot,
+ target: target ?? this.target,
+ eventType: eventType ?? this.eventType,
+ onData: onData ?? this.onData,
+ useCapture: useCapture ?? this.useCapture);
+ }
+}
+
/**
* Adapter for exposing DOM events as Dart streams.
*/
@@ -125,8 +160,16 @@ class _EventStream<T extends Event> extends Stream<T> {
final EventTarget _target;
final String _eventType;
final bool _useCapture;
+ /// The name that is used in the task specification.
+ final String _name;
+ /// Whether the stream can trigger multiple times.
+ final bool _isOneShot;
- _EventStream(this._target, this._eventType, this._useCapture);
+ _EventStream(this._target, String eventType, this._useCapture,
+ {String name, bool isOneShot: false})
+ : _eventType = eventType,
+ _isOneShot = isOneShot,
+ _name = name ?? "dart.html.event.$eventType";
// DOM events are inherently multi-subscribers.
Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
@@ -134,13 +177,31 @@ class _EventStream<T extends Event> extends Stream<T> {
=> this;
bool get isBroadcast => true;
+ StreamSubscription<T> _listen(
+ void onData(T event), {bool useCapture}) {
+
+ if (identical(Zone.current, Zone.ROOT)) {
+ return new _EventStreamSubscription<T>(
+ this._target, this._eventType, onData, this._useCapture,
+ Zone.current);
+ }
+
+ var specification = new EventSubscriptionSpecification<T>(
+ name: this._name, isOneShot: this._isOneShot,
+ target: this._target, eventType: this._eventType,
+ onData: onData, useCapture: useCapture);
+ // We need to wrap the _createStreamSubscription call, since a tear-off
+ // would not bind the generic type 'T'.
+ return Zone.current.createTask((spec, Zone zone) {
+ return _createStreamSubscription/*<T>*/(spec, zone);
+ }, specification);
+ }
+
StreamSubscription<T> listen(void onData(T event),
{ Function onError,
void onDone(),
bool cancelOnError}) {
-
- return new _EventStreamSubscription<T>(
- this._target, this._eventType, onData, this._useCapture);
+ return _listen(onData, useCapture: this._useCapture);
}
}
@@ -155,8 +216,9 @@ bool _matchesWithAncestors(Event event, String selector) {
*/
class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
implements ElementStream<T> {
- _ElementEventStreamImpl(target, eventType, useCapture) :
- super(target, eventType, useCapture);
+ _ElementEventStreamImpl(target, eventType, useCapture,
+ {String name, bool isOneShot: false}) :
+ super(target, eventType, useCapture, name: name, isOneShot: isOneShot);
Stream<T> matches(String selector) => this.where(
(event) => _matchesWithAncestors(event, selector)).map((e) {
@@ -164,9 +226,9 @@ class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
return e;
});
- StreamSubscription<T> capture(void onData(T event)) =>
- new _EventStreamSubscription<T>(
- this._target, this._eventType, onData, true);
+ StreamSubscription<T> capture(void onData(T event)) {
+ return _listen(onData, useCapture: true);
+ }
}
/**
@@ -215,7 +277,13 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
bool get isBroadcast => true;
}
-// We would like this to just be EventListener<T> but that typdef cannot
+StreamSubscription/*<T>*/ _createStreamSubscription/*<T>*/(
+ EventSubscriptionSpecification/*<T>*/ spec, Zone zone) {
+ return new _EventStreamSubscription/*<T>*/(spec.target, spec.eventType,
+ spec.onData, spec.useCapture, zone);
+}
+
+// We would like this to just be EventListener<T> but that typedef cannot
// use generics until dartbug/26276 is fixed.
typedef _EventListener<T extends Event>(T event);
@@ -224,15 +292,19 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
EventTarget _target;
final String _eventType;
EventListener _onData;
+ EventListener _domCallback;
final bool _useCapture;
+ final Zone _zone;
// TODO(jacobr): for full strong mode correctness we should write
- // _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((e) => onData(e as T))
+ // _onData = onData == null ? null : _wrapZone/*<dynamic, Event>*/((e) => onData(e as T))
// but that breaks 114 co19 tests as well as multiple html tests as it is reasonable
// to pass the wrong type of event object to an event listener as part of a
// test.
_EventStreamSubscription(this._target, this._eventType, void onData(T event),
- this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
+ this._useCapture, Zone zone)
+ : _zone = zone,
+ _onData = _registerZone/*<dynamic, Event>*/(zone, onData) {
_tryResume();
}
@@ -254,7 +326,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
// Remove current event listener.
_unlisten();
- _onData = _wrapZone/*<Event, dynamic>*/(handleData);
+ _onData = _registerZone/*<dynamic, Event>*/(_zone, handleData);
_tryResume();
}
@@ -283,14 +355,25 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
void _tryResume() {
- if (_onData != null && !isPaused) {
- _target.addEventListener(_eventType, _onData, _useCapture);
+ if (_onData == null || isPaused) return;
+ if (identical(_zone, Zone.ROOT)) {
+ _domCallback = _onData;
+ } else {
+ _domCallback = (event) {
+ _zone.runTask(_runEventNotification, this, event);
+ };
}
+ _target.addEventListener(_eventType, _domCallback, _useCapture);
+ }
+
+ static void _runEventNotification/*<T>*/(
+ _EventStreamSubscription/*<T>*/ subscription, /*=T*/ event) {
+ subscription._onData(event);
}
void _unlisten() {
if (_onData != null) {
- _target.removeEventListener(_eventType, _onData, _useCapture);
+ _target.removeEventListener(_eventType, _domCallback, _useCapture);
}
}
« no previous file with comments | « tests/html/event_zone_task_test.dart ('k') | tools/dom/src/shared_html.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698