Revert "Reapply zone tasks."

This reverts commit f746f8f77e.

Review URL: https://codereview.chromium.org/2123593002 .
This commit is contained in:
Florian Loitsch 2016-07-04 21:58:15 +02:00
parent f746f8f77e
commit dae3922915
19 changed files with 221 additions and 3902 deletions

View file

@ -4,84 +4,6 @@
part of dart.async;
abstract class _TimerTask implements Timer {
final Zone _zone;
final Timer _nativeTimer;
_TimerTask(this._nativeTimer, this._zone);
void cancel() {
_nativeTimer.cancel();
}
bool get isActive => _nativeTimer.isActive;
}
class _SingleShotTimerTask extends _TimerTask {
// TODO(floitsch): the generic argument should be 'void'.
final ZoneCallback<dynamic> _callback;
_SingleShotTimerTask(Timer timer, this._callback, Zone zone)
: super(timer, zone);
}
class _PeriodicTimerTask extends _TimerTask {
// TODO(floitsch): the first generic argument should be 'void'.
final ZoneUnaryCallback<dynamic, Timer> _callback;
_PeriodicTimerTask(Timer timer, this._callback, Zone zone)
: super(timer, zone);
}
/**
* A task specification for a single-shot timer.
*
* *Experimental*. Might disappear without notice.
*/
class SingleShotTimerTaskSpecification implements TaskSpecification {
static const String specificationName = "dart.async.timer";
/** The duration after which the timer should invoke the [callback]. */
final Duration duration;
/** The callback that should be run when the timer triggers. */
// TODO(floitsch): the generic argument should be void.
final ZoneCallback<dynamic> callback;
SingleShotTimerTaskSpecification(this.duration, void this.callback());
@override
String get name => specificationName;
@override
bool get isOneShot => true;
}
/**
* A task specification for a periodic timer.
*
* *Experimental*. Might disappear without notice.
*/
class PeriodicTimerTaskSpecification implements TaskSpecification {
static const String specificationName = "dart.async.periodic-timer";
/** The interval at which the periodic timer should invoke the [callback]. */
final Duration duration;
/** The callback that should be run when the timer triggers. */
// TODO(floitsch): the first generic argument should be void.
final ZoneUnaryCallback<dynamic, Timer> callback;
PeriodicTimerTaskSpecification(
this.duration, void this.callback(Timer timer));
@override
String get name => specificationName;
@override
bool get isOneShot => false;
}
/**
* A count-down timer that can be configured to fire once or repeatedly.
*
@ -125,15 +47,10 @@ abstract class Timer {
if (Zone.current == Zone.ROOT) {
// No need to bind the callback. We know that the root's timer will
// be invoked in the root zone.
return Timer._createTimer(duration, callback);
return Zone.current.createTimer(duration, callback);
}
return Zone.current.createTimer(duration, callback);
}
factory Timer._task(Zone zone, Duration duration, void callback()) {
SingleShotTimerTaskSpecification specification =
new SingleShotTimerTaskSpecification(duration, callback);
return zone.createTask(_createSingleShotTimerTask, specification);
return Zone.current.createTimer(
duration, Zone.current.bindCallback(callback, runGuarded: true));
}
/**
@ -153,65 +70,17 @@ abstract class Timer {
* scheduled for - even if the actual callback was delayed.
*/
factory Timer.periodic(Duration duration,
void callback(Timer timer)) {
void callback(Timer timer)) {
if (Zone.current == Zone.ROOT) {
// No need to bind the callback. We know that the root's timer will
// be invoked in the root zone.
return Timer._createPeriodicTimer(duration, callback);
return Zone.current.createPeriodicTimer(duration, callback);
}
return Zone.current.createPeriodicTimer(duration, callback);
}
factory Timer._periodicTask(Zone zone, Duration duration,
void callback(Timer timer)) {
PeriodicTimerTaskSpecification specification =
new PeriodicTimerTaskSpecification(duration, callback);
return zone.createTask(_createPeriodicTimerTask, specification);
}
static Timer _createSingleShotTimerTask(
SingleShotTimerTaskSpecification specification, Zone zone) {
ZoneCallback registeredCallback = identical(_ROOT_ZONE, zone)
? specification.callback
: zone.registerCallback(specification.callback);
_TimerTask timerTask;
Timer nativeTimer = Timer._createTimer(specification.duration, () {
timerTask._zone.runTask(_runSingleShotCallback, timerTask, null);
});
timerTask = new _SingleShotTimerTask(nativeTimer, registeredCallback, zone);
return timerTask;
}
static void _runSingleShotCallback(_SingleShotTimerTask timerTask, Object _) {
timerTask._callback();
}
static Timer _createPeriodicTimerTask(
PeriodicTimerTaskSpecification specification, Zone zone) {
// TODO(floitsch): the return type should be 'void', and the type
// should be inferred.
ZoneUnaryCallback<dynamic, Timer> registeredCallback =
identical(_ROOT_ZONE, zone)
? specification.callback
: zone.registerUnaryCallback/*<dynamic, Timer>*/(
specification.callback);
_TimerTask timerTask;
Timer nativeTimer =
Timer._createPeriodicTimer(specification.duration, (Timer _) {
timerTask._zone.runTask(_runPeriodicCallback, timerTask, null);
});
timerTask = new _PeriodicTimerTask(nativeTimer, registeredCallback, zone);
return timerTask;
}
static void _runPeriodicCallback(_PeriodicTimerTask timerTask, Object _) {
timerTask._callback(timerTask);
var boundCallback = Zone.current.bindUnaryCallback/*<dynamic, Timer>*/(
callback, runGuarded: true);
return Zone.current.createPeriodicTimer(duration, boundCallback);
}
/**

View file

@ -8,13 +8,6 @@ typedef R ZoneCallback<R>();
typedef R ZoneUnaryCallback<R, T>(T arg);
typedef R ZoneBinaryCallback<R, T1, T2>(T1 arg1, T2 arg2);
/// *Experimental*. Might disappear without warning.
typedef T TaskCreate<T, S extends TaskSpecification>(
S specification, Zone zone);
/// *Experimental*. Might disappear without warning.
typedef void TaskRun<T, A>(T task, A arg);
// TODO(floitsch): we are abusing generic typedefs as typedefs for generic
// functions.
/*ABUSE*/
@ -40,30 +33,18 @@ typedef ZoneBinaryCallback<R, T1, T2> RegisterBinaryCallbackHandler<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R f(T1 arg1, T2 arg2));
typedef AsyncError ErrorCallbackHandler(Zone self, ZoneDelegate parent,
Zone zone, Object error, StackTrace stackTrace);
/// *Experimental*. Might disappear without warning.
/*ABUSE*/
typedef T CreateTaskHandler<T, S extends TaskSpecification>(
Zone self, ZoneDelegate parent, Zone zone,
TaskCreate<T, S> create, S taskSpecification);
/// *Experimental*. Might disappear without warning.
/*ABUSE*/
typedef void RunTaskHandler<T, A>(Zone self, ZoneDelegate parent, Zone zone,
TaskRun<T, A> run, T task, A arg);
typedef void ScheduleMicrotaskHandler(
Zone self, ZoneDelegate parent, Zone zone, void f());
typedef void PrintHandler(
Zone self, ZoneDelegate parent, Zone zone, String line);
typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
ZoneSpecification specification,
Map zoneValues);
// The following typedef declarations are used by functionality which
// will be removed and replaced by tasksif the task experiment is successful.
typedef Timer CreateTimerHandler(
Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f());
typedef Timer CreatePeriodicTimerHandler(
Zone self, ZoneDelegate parent, Zone zone,
Duration period, void f(Timer timer));
typedef void PrintHandler(
Zone self, ZoneDelegate parent, Zone zone, String line);
typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
ZoneSpecification specification,
Map zoneValues);
/** Pair of error and stack trace. Returned by [Zone.errorCallback]. */
class AsyncError implements Error {
@ -75,41 +56,10 @@ class AsyncError implements Error {
String toString() => '$error';
}
/**
* A task specification contains the necessary information to create a task.
*
* See [Zone.createTask] for how a specification is used to create a task.
*
* Task specifications should be public and it should be possible to create
* new instances as a user. That is, custom zones should be able to replace
* an existing specification with a modified one.
*
* *Experimental*. This class might disappear without warning.
*/
abstract class TaskSpecification {
/**
* Description of the task.
*
* This string is unused by the root-zone, but might be used for debugging,
* and testing. As such, it should be relatively unique in its category.
*
* As a general guideline we recommend: "package-name.library.action".
*/
String get name;
/**
* Whether the scheduled task triggers at most once.
*
* If the task is not a one-shot task, it may need to be canceled to prevent
* further iterations of the task.
*/
bool get isOneShot;
}
class _ZoneFunction<T extends Function> {
final _Zone zone;
final T function;
const _ZoneFunction(this.zone, this.function);
}
@ -135,9 +85,6 @@ class _ZoneFunction<T extends Function> {
abstract class ZoneSpecification {
/**
* Creates a specification with the provided handlers.
*
* The task-related parameters ([createTask] and [runTask]) are experimental
* and might be removed without warning.
*/
const factory ZoneSpecification({
HandleUncaughtErrorHandler handleUncaughtError,
@ -149,11 +96,7 @@ abstract class ZoneSpecification {
RegisterBinaryCallbackHandler registerBinaryCallback,
ErrorCallbackHandler errorCallback,
ScheduleMicrotaskHandler scheduleMicrotask,
CreateTaskHandler createTask,
RunTaskHandler runTask,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreateTimerHandler createTimer,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreatePeriodicTimerHandler createPeriodicTimer,
PrintHandler print,
ForkHandler fork
@ -162,9 +105,6 @@ abstract class ZoneSpecification {
/**
* Creates a specification from [other] with the provided handlers overriding
* the ones in [other].
*
* The task-related parameters ([createTask] and [runTask]) are experimental
* and might be removed without warning.
*/
factory ZoneSpecification.from(ZoneSpecification other, {
HandleUncaughtErrorHandler handleUncaughtError: null,
@ -176,11 +116,7 @@ abstract class ZoneSpecification {
RegisterBinaryCallbackHandler registerBinaryCallback: null,
ErrorCallbackHandler errorCallback: null,
ScheduleMicrotaskHandler scheduleMicrotask: null,
CreateTaskHandler createTask: null,
RunTaskHandler runTask: null,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreateTimerHandler createTimer: null,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreatePeriodicTimerHandler createPeriodicTimer: null,
PrintHandler print: null,
ForkHandler fork: null
@ -196,14 +132,11 @@ abstract class ZoneSpecification {
registerBinaryCallback: registerBinaryCallback ??
other.registerBinaryCallback,
errorCallback: errorCallback ?? other.errorCallback,
createTask: createTask ?? other.createTask,
runTask: runTask ?? other.runTask,
print : print ?? other.print,
fork: fork ?? other.fork,
scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
createTimer : createTimer ?? other.createTimer,
createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer);
createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer,
print : print ?? other.print,
fork: fork ?? other.fork);
}
HandleUncaughtErrorHandler get handleUncaughtError;
@ -215,17 +148,10 @@ abstract class ZoneSpecification {
RegisterBinaryCallbackHandler get registerBinaryCallback;
ErrorCallbackHandler get errorCallback;
ScheduleMicrotaskHandler get scheduleMicrotask;
/// *Experimental*. Might disappear without warning.
CreateTaskHandler get createTask;
/// *Experimental*. Might disappear without warning.
RunTaskHandler get runTask;
CreateTimerHandler get createTimer;
CreatePeriodicTimerHandler get createPeriodicTimer;
PrintHandler get print;
ForkHandler get fork;
// TODO(floitsch): deprecate once tasks are non-experimental.
CreateTimerHandler get createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
CreatePeriodicTimerHandler get createPeriodicTimer;
}
/**
@ -246,14 +172,10 @@ class _ZoneSpecification implements ZoneSpecification {
this.registerBinaryCallback: null,
this.errorCallback: null,
this.scheduleMicrotask: null,
this.createTask: null,
this.runTask: null,
this.print: null,
this.fork: null,
// TODO(floitsch): deprecate once tasks are non-experimental.
this.createTimer: null,
// TODO(floitsch): deprecate once tasks are non-experimental.
this.createPeriodicTimer: null
this.createPeriodicTimer: null,
this.print: null,
this.fork: null
});
final HandleUncaughtErrorHandler handleUncaughtError;
@ -265,15 +187,10 @@ class _ZoneSpecification implements ZoneSpecification {
final RegisterBinaryCallbackHandler registerBinaryCallback;
final ErrorCallbackHandler errorCallback;
final ScheduleMicrotaskHandler scheduleMicrotask;
final CreateTaskHandler createTask;
final RunTaskHandler runTask;
final CreateTimerHandler createTimer;
final CreatePeriodicTimerHandler createPeriodicTimer;
final PrintHandler print;
final ForkHandler fork;
// TODO(floitsch): deprecate once tasks are non-experimental.
final CreateTimerHandler createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
final CreatePeriodicTimerHandler createPeriodicTimer;
}
/**
@ -300,23 +217,10 @@ abstract class ZoneDelegate {
Zone zone, /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2));
AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace);
void scheduleMicrotask(Zone zone, void f());
/// *Experimental*. Might disappear without notice.
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
Zone zone, TaskCreate/*<T, S>*/ create,
TaskSpecification/*=S*/ specification);
/// *Experimental*. Might disappear without notice.
void runTask/*<T, A>*/(
Zone zone, TaskRun/*<T, A>*/ run, Object/*=T*/ task,
Object/*=A*/ argument);
Timer createTimer(Zone zone, Duration duration, void f());
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
void print(Zone zone, String line);
Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues);
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Zone zone, Duration duration, void f());
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
}
/**
@ -506,103 +410,14 @@ abstract class Zone {
*/
void scheduleMicrotask(void f());
/**
* Creates a task in the current zone.
*
* A task represents an asynchronous operation or process that reports back
* through the event loop.
*
* This function allows the zone to intercept the initialization of the
* task while the [runTask] function is invoked when the task reports back.
*
* By default, in the root zone, the [create] function is invoked with the
* [specification] as argument. It returns a task object which is used for all
* future interactions between the zone and the task. The object is
* a unique instance representing the task. It is generally returned to
* whoever initiated the task.
* For example, the HTML library uses the returned [StreamSubscription] as
* task object when users register an event listener.
*
* Tasks are created when the program starts an operation that reports back
* through the event loop. For example, a timer or an HTTP request both
* return through the event loop and are therefore tasks.
*
* If the [create] function is not invoked (because a custom zone has
* replaced or intercepted it), then the operation is *not* started. This
* means that a custom zone can intercept tasks, like HTTP requests.
*
* A task goes through the following steps:
* - a user invokes a library function that should eventually return through
* the event loop.
* - the library function creates a [TaskSpecification] that contains the
* necessary information to start the operation, and invokes
* `Zone.current.createTask` with the specification and a [create] closure.
* The closure, when invoked, uses the specification to start the operation
* (usually by interacting with the underlying system, or as a native
* extension), and returns a task object that identifies the running task.
* - custom zones handle the request and (unless completely intercepted and
* aborted), end up calling the root zone's [createTask] which runs the
* provided `create` closure, which may have been replaced at this point.
* - later, the asynchronous operation returns through the event loop.
* It invokes [Zone.runTask] on the zone in which the task should run
* (and which was originally passed to the `create` function by
* `createTask`). The [runTask] function receives the
* task object, a `run` function and an argument. As before, custom zones
* may intercept this call. Eventually (unless aborted), the `run` function
* is invoked. This last step may happen multiple times for tasks that are
* not oneshot tasks (see [ZoneSpecification.isOneShot]).
*
* Custom zones may replace the [specification] with a different one, thus
* modifying the task parameters. An operation that wishes to be an
* interceptable task must publicly specify the types that intercepting code
* sees:
* - The specification type (extending [TaskSpecification]) which holds the
* information available when intercepting the `createTask` call.
* - The task object type, returned by `createTask` and [create]. This object
* may simply be typed as [Object].
* - The argument type, if [runTask] takes a meaningful argument.
*
* *Experimental*. Might disappear without notice.
*/
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
/*=T*/ create(TaskSpecification/*=S*/ specification, Zone zone),
TaskSpecification/*=S*/ specification);
/**
* Runs a task callback.
*
* This function is invoked when an operation, started through [createTask],
* generates an event.
*
* Generally, tasks schedule Dart code in the global event loop when the
* [createTask] function is invoked. Since the
* event loop does not expect any return value from the code it runs, the
* [runTask] function is a void function.
*
* The [task] object must be the same as the one created with [createTask].
*
* It is good practice that task operations provide a meaningful [argument],
* so that custom zones can interact with it. They might want to log or
* replace the argument before calling the [run] function.
*
* See [createTask].
*
* *Experimental*. Might disappear without notice.
*/
void runTask/*<T, A>*/(
/*=T*/ run(/*=T*/ task, /*=A*/ argument), Object/*=T*/ task,
Object/*=A*/ argument);
/**
* Creates a Timer where the callback is executed in this zone.
*/
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Duration duration, void callback());
/**
* Creates a periodic Timer where the callback is executed in this zone.
*/
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Duration period, void callback(Timer timer));
/**
@ -708,7 +523,7 @@ class _ZoneDelegate implements ZoneDelegate {
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as dynamic/*=ZoneCallback<R>*/;
as Object/*=ZoneCallback<R>*/;
}
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
@ -719,7 +534,7 @@ class _ZoneDelegate implements ZoneDelegate {
// TODO(floitsch): make this a generic method call on '<R, T>' once it's
// supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as dynamic/*=ZoneUnaryCallback<R, T>*/;
as Object/*=ZoneUnaryCallback<R, T>*/;
}
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
@ -730,7 +545,7 @@ class _ZoneDelegate implements ZoneDelegate {
// TODO(floitsch): make this a generic method call on '<R, T1, T2>' once
// it's supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as dynamic/*=ZoneBinaryCallback<R, T1, T2>*/;
as Object/*=ZoneBinaryCallback<R, T1, T2>*/;
}
AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace) {
@ -749,25 +564,18 @@ class _ZoneDelegate implements ZoneDelegate {
handler(implZone, _parentDelegate(implZone), zone, f);
}
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
Zone zone, TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
var implementation = _delegationTarget._createTask;
Timer createTimer(Zone zone, Duration duration, void f()) {
var implementation = _delegationTarget._createTimer;
_Zone implZone = implementation.zone;
// TODO(floitsch): make the handler call a generic method call on '<T, S>'
// once it's supported. Remove the unnecessary cast.
var handler =
implementation.function as CreateTaskHandler/*<T, S>*/;
return handler(
implZone, _parentDelegate(implZone), zone, create, specification);
CreateTimerHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone, duration, f);
}
void runTask/*<T, A>*/(Zone zone, TaskRun run, Object /*=T*/ task,
Object /*=A*/ argument) {
var implementation = _delegationTarget._runTask;
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) {
var implementation = _delegationTarget._createPeriodicTimer;
_Zone implZone = implementation.zone;
RunTaskHandler handler = implementation.function;
// TODO(floitsch): make this a generic call on '<T, A>'.
handler(implZone, _parentDelegate(implZone), zone, run, task, argument);
CreatePeriodicTimerHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone, period, f);
}
void print(Zone zone, String line) {
@ -785,22 +593,6 @@ class _ZoneDelegate implements ZoneDelegate {
return handler(
implZone, _parentDelegate(implZone), zone, specification, zoneValues);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Zone zone, Duration duration, void f()) {
var implementation = _delegationTarget._createTimer;
_Zone implZone = implementation.zone;
CreateTimerHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone, duration, f);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) {
var implementation = _delegationTarget._createPeriodicTimer;
_Zone implZone = implementation.zone;
CreatePeriodicTimerHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone, period, f);
}
}
@ -818,17 +610,11 @@ abstract class _Zone implements Zone {
_ZoneFunction<RegisterBinaryCallbackHandler> get _registerBinaryCallback;
_ZoneFunction<ErrorCallbackHandler> get _errorCallback;
_ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask;
_ZoneFunction<CreateTaskHandler> get _createTask;
_ZoneFunction<RunTaskHandler> get _runTask;
_ZoneFunction<CreateTimerHandler> get _createTimer;
_ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer;
_ZoneFunction<PrintHandler> get _print;
_ZoneFunction<ForkHandler> get _fork;
_ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreateTimerHandler> get _createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer;
_Zone get parent;
ZoneDelegate get _delegate;
Map get _map;
@ -850,17 +636,12 @@ class _CustomZone extends _Zone {
_ZoneFunction<RegisterBinaryCallbackHandler> _registerBinaryCallback;
_ZoneFunction<ErrorCallbackHandler> _errorCallback;
_ZoneFunction<ScheduleMicrotaskHandler> _scheduleMicrotask;
_ZoneFunction<CreateTaskHandler> _createTask;
_ZoneFunction<RunTaskHandler> _runTask;
_ZoneFunction<CreateTimerHandler> _createTimer;
_ZoneFunction<CreatePeriodicTimerHandler> _createPeriodicTimer;
_ZoneFunction<PrintHandler> _print;
_ZoneFunction<ForkHandler> _fork;
_ZoneFunction<HandleUncaughtErrorHandler> _handleUncaughtError;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreateTimerHandler> _createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreatePeriodicTimerHandler> _createPeriodicTimer;
// A cached delegate to this zone.
ZoneDelegate _delegateCache;
@ -911,14 +692,13 @@ class _CustomZone extends _Zone {
? new _ZoneFunction<ScheduleMicrotaskHandler>(
this, specification.scheduleMicrotask)
: parent._scheduleMicrotask;
_createTask = (specification.createTask != null)
? new _ZoneFunction<CreateTaskHandler>(
this, specification.createTask)
: parent._createTask;
_runTask = (specification.runTask != null)
? new _ZoneFunction<RunTaskHandler>(
this, specification.runTask)
: parent._runTask;
_createTimer = (specification.createTimer != null)
? new _ZoneFunction<CreateTimerHandler>(this, specification.createTimer)
: parent._createTimer;
_createPeriodicTimer = (specification.createPeriodicTimer != null)
? new _ZoneFunction<CreatePeriodicTimerHandler>(
this, specification.createPeriodicTimer)
: parent._createPeriodicTimer;
_print = (specification.print != null)
? new _ZoneFunction<PrintHandler>(this, specification.print)
: parent._print;
@ -929,16 +709,6 @@ class _CustomZone extends _Zone {
? new _ZoneFunction<HandleUncaughtErrorHandler>(
this, specification.handleUncaughtError)
: parent._handleUncaughtError;
// Deprecated fields, once tasks are non-experimental.
_createTimer = (specification.createTimer != null)
? new _ZoneFunction<CreateTimerHandler>(
this, specification.createTimer)
: parent._createTimer;
_createPeriodicTimer = (specification.createPeriodicTimer != null)
? new _ZoneFunction<CreatePeriodicTimerHandler>(
this, specification.createPeriodicTimer)
: parent._createPeriodicTimer;
}
/**
@ -1089,7 +859,7 @@ class _CustomZone extends _Zone {
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, callback)
as dynamic/*=ZoneCallback<R>*/;
as Object/*=ZoneCallback<R>*/;
}
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
@ -1101,7 +871,7 @@ class _CustomZone extends _Zone {
// TODO(floitsch): make this a generic method call on '<R, T>' once it's
// supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, callback)
as dynamic/*=ZoneUnaryCallback<R, T>*/;
as Object/*=ZoneUnaryCallback<R, T>*/;
}
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
@ -1113,7 +883,7 @@ class _CustomZone extends _Zone {
// TODO(floitsch): make this a generic method call on '<R, T1, T2>' once
// it's supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, callback)
as dynamic/*=ZoneBinaryCallback<R, T1, T2>*/;
as Object/*=ZoneBinaryCallback<R, T1, T2>*/;
}
AsyncError errorCallback(Object error, StackTrace stackTrace) {
@ -1132,40 +902,9 @@ class _CustomZone extends _Zone {
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
ScheduleMicrotaskHandler handler = implementation.function;
handler(implementation.zone, parentDelegate, this, f);
return handler(implementation.zone, parentDelegate, this, f);
}
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
var implementation = this._createTask;
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
// TODO(floitsch): make the handler call a generic method call on '<T, S>'
// once it's supported. Remove the unnecessary cast.
var handler =
implementation.function as CreateTaskHandler/*<T, S>*/;
return handler(
implementation.zone, parentDelegate, this, create, specification);
}
void runTask/*<T, A>*/(
TaskRun/*<T, A>*/ run, Object/*=T*/ task, Object/*=A*/ arg1) {
var implementation = this._runTask;
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RunTaskHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<T, A>' once it's
// supported.
handler(implementation.zone, parentDelegate, this, run, task, arg1);
}
void print(String line) {
var implementation = this._print;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
PrintHandler handler = implementation.function;
return handler(implementation.zone, parentDelegate, this, line);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Duration duration, void f()) {
var implementation = this._createTimer;
assert(implementation != null);
@ -1174,7 +913,6 @@ class _CustomZone extends _Zone {
return handler(implementation.zone, parentDelegate, this, duration, f);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
var implementation = this._createPeriodicTimer;
assert(implementation != null);
@ -1183,6 +921,14 @@ class _CustomZone extends _Zone {
return handler(
implementation.zone, parentDelegate, this, duration, f);
}
void print(String line) {
var implementation = this._print;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
PrintHandler handler = implementation.function;
return handler(implementation.zone, parentDelegate, this, line);
}
}
/*=R*/ _rootHandleUncaughtError/*<R>*/(
@ -1260,39 +1006,22 @@ void _rootScheduleMicrotask(Zone self, ZoneDelegate parent, Zone zone, f()) {
_scheduleAsyncCallback(f);
}
Object/*=T*/ _rootCreateTask/*<T, S extends TaskSpecification>*/(
Zone self, ZoneDelegate parent, Zone zone,
TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
return create(specification, zone);
}
void _rootRunTask/*<T, A>*/(
Zone self, ZoneDelegate parent, Zone zone, TaskRun run/*<T, A>*/,
Object/*=T*/ task, Object/*=A*/ arg) {
if (Zone._current == zone) {
run(task, arg);
return;
}
Zone old = Zone._enter(zone);
try {
run(task, arg);
} catch (e, s) {
zone.handleUncaughtError/*<dynamic>*/(e, s);
} finally {
Zone._leave(old);
}
}
Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
Duration duration, void callback()) {
return new Timer._task(zone, duration, callback);
if (!identical(_ROOT_ZONE, zone)) {
callback = zone.bindCallback(callback);
}
return Timer._createTimer(duration, callback);
}
Timer _rootCreatePeriodicTimer(
Zone self, ZoneDelegate parent, Zone zone,
Duration duration, void callback(Timer timer)) {
return new Timer._periodicTask(zone, duration, callback);
if (!identical(_ROOT_ZONE, zone)) {
// TODO(floitsch): the return type should be 'void'.
callback = zone.bindUnaryCallback/*<dynamic, Timer>*/(callback);
}
return Timer._createPeriodicTimer(duration, callback);
}
void _rootPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
@ -1353,10 +1082,10 @@ class _RootZone extends _Zone {
_ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask =>
const _ZoneFunction<ScheduleMicrotaskHandler>(
_ROOT_ZONE, _rootScheduleMicrotask);
_ZoneFunction<CreateTaskHandler> get _createTask =>
const _ZoneFunction<CreateTaskHandler>(_ROOT_ZONE, _rootCreateTask);
_ZoneFunction<RunTaskHandler> get _runTask =>
const _ZoneFunction<RunTaskHandler>(_ROOT_ZONE, _rootRunTask);
_ZoneFunction<CreateTimerHandler> get _createTimer =>
const _ZoneFunction<CreateTimerHandler>(_ROOT_ZONE, _rootCreateTimer);
_ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer =>
const _ZoneFunction<CreatePeriodicTimerHandler>(_ROOT_ZONE, _rootCreatePeriodicTimer);
_ZoneFunction<PrintHandler> get _print =>
const _ZoneFunction<PrintHandler>(_ROOT_ZONE, _rootPrint);
_ZoneFunction<ForkHandler> get _fork =>
@ -1365,14 +1094,6 @@ class _RootZone extends _Zone {
const _ZoneFunction<HandleUncaughtErrorHandler>(
_ROOT_ZONE, _rootHandleUncaughtError);
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreateTimerHandler> get _createTimer =>
const _ZoneFunction<CreateTimerHandler>(_ROOT_ZONE, _rootCreateTimer);
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer =>
const _ZoneFunction<CreatePeriodicTimerHandler>(
_ROOT_ZONE, _rootCreatePeriodicTimer);
// The parent zone.
_Zone get parent => null;
@ -1504,16 +1225,6 @@ class _RootZone extends _Zone {
_rootScheduleMicrotask(null, null, this, f);
}
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
return _rootCreateTask/*<T, S>*/(null, null, this, create, specification);
}
void runTask/*<T, A>*/(
TaskRun/*<T, A>*/ run, Object/*=T*/ task, Object/*=A*/ arg) {
_rootRunTask/*<T, A>*/(null, null, this, run, task, arg);
}
Timer createTimer(Duration duration, void f()) {
return Timer._createTimer(duration, f);
}

View file

@ -19240,109 +19240,6 @@ class HtmlOptionsCollection extends HtmlCollection {
// BSD-style license that can be found in the LICENSE file.
/**
* A task specification for HTTP requests.
*
* This specification is not available when an HTTP request is sent through
* direct use of [HttpRequest.send]. See [HttpRequestSendTaskSpecification].
*
* A task created from this specification is a `Future<HttpRequest>`.
*
* *Experimental*. This class may disappear without notice.
*/
class HttpRequestTaskSpecification extends TaskSpecification {
/// The URL of the request.
final String url;
/// The HTTP request method.
///
/// By default (when `null`) this is a `"GET"` request. Alternatively, the
/// method can be `"POST"`, `"PUT"`, `"DELETE"`, etc.
final String method;
/// Whether the request should send credentials. Credentials are only useful
/// for cross-origin requests.
///
/// See [HttpRequest.request] for more information.
final bool withCredentials;
/// The desired response format.
///
/// Supported types are:
/// - `""`: (same as `"text"`),
/// - `"arraybuffer"`,
/// - `"blob"`,
/// - `"document"`,
/// - `"json"`,
/// - `"text"`
///
/// When no value is provided (when equal to `null`) defaults to `""`.
final String responseType;
/// The desired MIME type.
///
/// This overrides the default MIME type which is set up to transfer textual
/// data.
final String mimeType;
/// The request headers that should be sent with the request.
final Map<String, String> requestHeaders;
/// The data that is sent with the request.
///
/// When data is provided (the value is not `null`), it must be a
/// [ByteBuffer], [Blob], [Document], [String], or [FormData].
final dynamic sendData;
/// The function that is invoked on progress updates. This function is
/// registered as an event listener on the created [HttpRequest] object, and
/// thus has its own task. Further invocations of the progress function do
/// *not* use the HTTP request task as task object.
///
/// Creating an HTTP request automatically registers the on-progress listener.
final ZoneUnaryCallback<dynamic, ProgressEvent> onProgress;
HttpRequestTaskSpecification(this.url,
{String this.method, bool this.withCredentials, String this.responseType,
String this.mimeType, Map<String, String> this.requestHeaders,
this.sendData,
void this.onProgress(ProgressEvent e)});
String get name => "dart.html.http-request";
bool get isOneShot => true;
}
/**
* A task specification for HTTP requests that are initiated through a direct
* invocation of [HttpRequest.send].
*
* This specification serves as signal to zones that an HTTP request has been
* initiated. The created task is the [request] object itself, and
* no callback is ever executed in this task.
*
* Note that event listeners on the HTTP request are also registered in the
* zone (although with their own task creations), and that a zone can thus
* detect when the HTTP request returns.
*
* HTTP requests that are initiated through `request` methods don't use
* this class but use [HttpRequestTaskSpecification].
*
* *Experimental*. This class may disappear without notice.
*/
class HttpRequestSendTaskSpecification extends TaskSpecification {
final HttpRequest request;
final dynamic sendData;
HttpRequestSendTaskSpecification(this.request, this.sendData);
String get name => "dart.html.http-request-send";
/**
* No callback is ever executed in an HTTP request send task.
*/
bool get isOneShot => false;
}
/**
* A client-side XHR request for getting data from a URL,
* formally known as XMLHttpRequest.
@ -19531,34 +19428,7 @@ class HttpRequest extends HttpRequestEventTarget {
{String method, bool withCredentials, String responseType,
String mimeType, Map<String, String> requestHeaders, sendData,
void onProgress(ProgressEvent e)}) {
var spec = new HttpRequestTaskSpecification(
url, method: method,
withCredentials: withCredentials,
responseType: responseType,
mimeType: mimeType,
requestHeaders: requestHeaders,
sendData: sendData,
onProgress: onProgress);
if (identical(Zone.current, Zone.ROOT)) {
return _createHttpRequestTask(spec, null);
}
return Zone.current.createTask(_createHttpRequestTask, spec);
}
static Future<HttpRequest> _createHttpRequestTask(
HttpRequestTaskSpecification spec, Zone zone) {
String url = spec.url;
String method = spec.method;
bool withCredentials = spec.withCredentials;
String responseType = spec.responseType;
String mimeType = spec.mimeType;
Map<String, String> requestHeaders = spec.requestHeaders;
var sendData = spec.sendData;
var onProgress = spec.onProgress;
var completer = new Completer<HttpRequest>();
var task = completer.future;
var xhr = new HttpRequest();
if (method == null) {
@ -19598,42 +19468,23 @@ class HttpRequest extends HttpRequestEventTarget {
// redirect case will be handled by the browser before it gets to us,
// so if we see it we should pass it through to the user.
var unknownRedirect = xhr.status > 307 && xhr.status < 400;
var isSuccessful = accepted || fileUri || notModified || unknownRedirect;
if (zone == null && isSuccessful) {
if (accepted || fileUri || notModified || unknownRedirect) {
completer.complete(xhr);
} else if (zone == null) {
completer.completeError(e);
} else if (isSuccessful) {
zone.runTask((task, value) {
completer.complete(value);
}, task, xhr);
} else {
zone.runTask((task, error) {
completer.completeError(error);
}, task, e);
completer.completeError(e);
}
});
if (zone == null) {
xhr.onError.listen(completer.completeError);
} else {
xhr.onError.listen((error) {
zone.runTask((task, error) {
completer.completeError(error);
}, task, error);
});
}
xhr.onError.listen(completer.completeError);
if (sendData != null) {
// TODO(floitsch): should we go through 'send()' and have nested tasks?
xhr._send(sendData);
xhr.send(sendData);
} else {
xhr._send();
xhr.send();
}
return task;
return completer.future;
}
/**
@ -19687,9 +19538,6 @@ class HttpRequest extends HttpRequestEventTarget {
return xhr.responseText;
});
}
// TODO(floitsch): the following code doesn't go through task zones.
// Since 'XDomainRequest' is an IE9 feature we should probably just remove
// it.
var completer = new Completer<String>();
if (method == null) {
method = 'GET';
@ -19768,43 +19616,13 @@ class HttpRequest extends HttpRequestEventTarget {
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `open` method is intended only for more complex HTTP requests where
* `open` method is intended only for more complext HTTP requests where
* finer-grained control is needed.
*/
@DomName('XMLHttpRequest.open')
@DocsEditable()
void open(String method, String url, {bool async, String user, String password}) native;
/**
* Sends the request with any given `data`.
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `send` method is intended only for more complex HTTP requests where
* finer-grained control is needed.
*
* ## Other resources
*
* * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#send%28%29)
* from MDN.
*/
@DomName('XMLHttpRequest.send')
@DocsEditable()
void send([body_OR_data]) {
if (identical(Zone.current, Zone.ROOT)) {
_send(body_OR_data);
} else {
Zone.current.createTask(_createHttpRequestSendTask,
new HttpRequestSendTaskSpecification(this, body_OR_data));
}
}
static HttpRequest _createHttpRequestSendTask(
HttpRequestSendTaskSpecification spec, Zone zone) {
spec.request._send(spec.sendData);
return spec.request;
}
// To suppress missing implicit constructor warnings.
factory HttpRequest._() { throw new UnsupportedError("Not supported"); }
@ -20075,13 +19893,12 @@ class HttpRequest extends HttpRequestEventTarget {
@SupportedBrowser(SupportedBrowser.SAFARI)
void overrideMimeType(String mime) native;
@JSName('send')
/**
* Send the request with any given `data`.
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `send` method is intended only for more complex HTTP requests where
* `send` method is intended only for more complext HTTP requests where
* finer-grained control is needed.
*
* ## Other resources
@ -20091,7 +19908,7 @@ class HttpRequest extends HttpRequestEventTarget {
*/
@DomName('XMLHttpRequest.send')
@DocsEditable()
void _send([body_OR_data]) native;
void send([body_OR_data]) native;
/**
* Sets the value of an HTTP requst header.
@ -34668,99 +34485,6 @@ class WheelEvent extends MouseEvent {
// BSD-style license that can be found in the LICENSE file.
typedef void RemoveFrameRequestMapping(int id);
/**
* The task object representing animation-frame requests.
*
* For historical reasons, [Window.requestAnimationFrame] returns an integer
* to users. However, zone tasks must be unique objects, and an integer can
* therefore not be used as task object. The [Window] class thus keeps a mapping
* from the integer ID to the corresponding task object. All zone related
* operations work on this task object, whereas users of
* [Window.requestAnimationFrame] only see the integer ID.
*
* Since this mapping takes up space, it must be removed when the
* animation-frame task has triggered. The default implementation does this
* automatically, but intercepting implementations of `requestAnimationFrame`
* must make sure to call the [AnimationFrameTask.removeMapping]
* function that is provided in the task specification.
*
* *Experimental*. This class may disappear without notice.
*/
abstract class AnimationFrameTask {
/** The ID that is returned to users. */
int get id;
/** The zone in which the task will run. */
Zone get zone;
/**
* Cancels the animation-frame request.
*
* A call to [Window.cancelAnimationFrame] with an `id` argument equal to [id]
* forwards the request to this function.
*
* Zones that intercept animation-frame requests implement this method so
* that they can react to cancelation requests.
*/
void cancel(Window window);
/**
* Maps animation-frame request IDs to their task objects.
*/
static final Map<int, _AnimationFrameTask> _tasks = {};
/**
* Removes the mapping from [id] to [AnimationFrameTask].
*
* This function must be invoked by user-implemented animation-frame
* tasks, before running [callback].
*
* See [AnimationFrameTask].
*/
static void removeMapping(int id) {
_tasks.remove(id);
}
}
class _AnimationFrameTask implements AnimationFrameTask {
final int id;
final Zone zone;
final FrameRequestCallback _callback;
_AnimationFrameTask(this.id, this.zone, this._callback);
void cancel(Window window) {
window._cancelAnimationFrame(this.id);
}
}
/**
* The task specification for an animation-frame request.
*
* *Experimental*. This class may disappear without notice.
*/
class AnimationFrameRequestSpecification implements TaskSpecification {
/**
* The window on which [Window.requestAnimationFrame] was invoked.
*/
final Window window;
/**
* The callback that is executed when the animation-frame is ready.
*
* Note that the callback hasn't been registered in any zone when the `create`
* function (passed to [Zone.createTask]) is invoked.
*/
final FrameRequestCallback callback;
AnimationFrameRequestSpecification(this.window, this.callback);
String get name => "dart.html.request-animation-frame";
bool get isOneShot => true;
}
@DocsEditable()
/**
* Top-level container for the current browser tab or window.
@ -34816,7 +34540,9 @@ class Window extends EventTarget implements WindowEventHandlers, WindowBase, Glo
*/
Future<num> get animationFrame {
var completer = new Completer<num>.sync();
requestAnimationFrame(completer.complete);
requestAnimationFrame((time) {
completer.complete(time);
});
return completer.future;
}
@ -34899,30 +34625,7 @@ class Window extends EventTarget implements WindowEventHandlers, WindowBase, Glo
@DomName('Window.requestAnimationFrame')
int requestAnimationFrame(FrameRequestCallback callback) {
_ensureRequestAnimationFrame();
if (identical(Zone.current, Zone.ROOT)) {
return _requestAnimationFrame(callback);
}
var spec = new AnimationFrameRequestSpecification(this, callback);
var task = Zone.current.createTask/*<AnimationFrameTask>*/(
_createAnimationFrameTask, spec);
AnimationFrameTask._tasks[task.id] = task;
return task.id;
}
static _AnimationFrameTask _createAnimationFrameTask(
AnimationFrameRequestSpecification spec, Zone zone) {
var task;
var id = spec.window._requestAnimationFrame((num time) {
AnimationFrameTask.removeMapping(task.id);
zone.runTask(_runAnimationFrame, task, time);
});
var callback = zone.registerUnaryCallback(spec.callback);
task = new _AnimationFrameTask(id, zone, callback);
return task;
}
static void _runAnimationFrame(_AnimationFrameTask task, num time) {
task._callback(time);
return _requestAnimationFrame(_wrapZone/*<num, dynamic>*/(callback));
}
/**
@ -34935,13 +34638,7 @@ class Window extends EventTarget implements WindowEventHandlers, WindowBase, Glo
*/
void cancelAnimationFrame(int id) {
_ensureRequestAnimationFrame();
var task = AnimationFrameTask._tasks.remove(id);
if (task == null) {
// Assume that the animation frame request wasn't intercepted by a zone.
_cancelAnimationFrame(id);
return;
}
task.cancel(this);
_cancelAnimationFrame(id);
}
@JSName('requestAnimationFrame')
@ -40267,41 +39964,6 @@ 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.
*/
@ -40309,16 +39971,8 @@ 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, String eventType, this._useCapture,
{String name, bool isOneShot: false})
: _eventType = eventType,
_isOneShot = isOneShot,
_name = name ?? "dart.html.event.$eventType";
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
@ -40326,31 +39980,13 @@ 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 _listen(onData, useCapture: this._useCapture);
return new _EventStreamSubscription<T>(
this._target, this._eventType, onData, this._useCapture);
}
}
@ -40365,9 +40001,8 @@ bool _matchesWithAncestors(Event event, String selector) {
*/
class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
implements ElementStream<T> {
_ElementEventStreamImpl(target, eventType, useCapture,
{String name, bool isOneShot: false}) :
super(target, eventType, useCapture, name: name, isOneShot: isOneShot);
_ElementEventStreamImpl(target, eventType, useCapture) :
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
(event) => _matchesWithAncestors(event, selector)).map((e) {
@ -40375,9 +40010,9 @@ class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
return e;
});
StreamSubscription<T> capture(void onData(T event)) {
return _listen(onData, useCapture: true);
}
StreamSubscription<T> capture(void onData(T event)) =>
new _EventStreamSubscription<T>(
this._target, this._eventType, onData, true);
}
/**
@ -40426,13 +40061,7 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
bool get isBroadcast => true;
}
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
// We would like this to just be EventListener<T> but that typdef cannot
// use generics until dartbug/26276 is fixed.
typedef _EventListener<T extends Event>(T event);
@ -40441,19 +40070,15 @@ 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/*<dynamic, Event>*/((e) => onData(e as T))
// _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((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, Zone zone)
: _zone = zone,
_onData = _registerZone/*<dynamic, Event>*/(zone, onData) {
this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@ -40475,7 +40100,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
// Remove current event listener.
_unlisten();
_onData = _registerZone/*<dynamic, Event>*/(_zone, handleData);
_onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@ -40504,25 +40129,14 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
void _tryResume() {
if (_onData == null || isPaused) return;
if (identical(_zone, Zone.ROOT)) {
_domCallback = _onData;
} else {
_domCallback = (event) {
_zone.runTask(_runEventNotification, this, event);
};
if (_onData != null && !isPaused) {
_target.addEventListener(_eventType, _onData, _useCapture);
}
_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, _domCallback, _useCapture);
_target.removeEventListener(_eventType, _onData, _useCapture);
}
}
@ -43756,26 +43370,31 @@ class _WrappedEvent implements Event {
// BSD-style license that can be found in the LICENSE file.
ZoneUnaryCallback/*<R, T>*/ _registerZone/*<R, T>*/(Zone zone,
ZoneUnaryCallback/*<R, T>*/ callback) {
// For performance reasons avoid registering if we are in the root zone.
if (identical(zone, Zone.ROOT)) return callback;
if (callback == null) return null;
return zone.registerUnaryCallback(callback);
}
// TODO(jacobr): remove these typedefs when dart:async supports generic types.
typedef R _wrapZoneCallback<A, R>(A a);
typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
ZoneUnaryCallback/*<R, T>*/ _wrapZone/*<R, T>*/(ZoneUnaryCallback/*<R, T>*/ callback) {
_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ callback) {
// For performance reasons avoid wrapping if we are in the root zone.
if (identical(Zone.current, Zone.ROOT)) return callback;
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
return Zone.current.bindUnaryCallback(callback, runGuarded: true);
// TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
// generic method support in zones.
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
_wrapZoneCallback/*<A, R>*/ wrapped =
Zone.current.bindUnaryCallback(callback, runGuarded: true);
return wrapped;
}
ZoneBinaryCallback/*<R, A, B>*/ _wrapBinaryZone/*<R, A, B>*/(
ZoneBinaryCallback/*<R, A, B>*/ callback) {
if (identical(Zone.current, Zone.ROOT)) return callback;
_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
return Zone.current.bindBinaryCallback(callback, runGuarded: true);
// We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
// generic method support in zones.
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
_wrapZoneBinaryCallback/*<A, B, R>*/ wrapped =
Zone.current.bindBinaryCallback(callback, runGuarded: true);
return wrapped;
}
/**

View file

@ -20997,109 +20997,6 @@ class HtmlOptionsCollection extends HtmlCollection {
// BSD-style license that can be found in the LICENSE file.
/**
* A task specification for HTTP requests.
*
* This specification is not available when an HTTP request is sent through
* direct use of [HttpRequest.send]. See [HttpRequestSendTaskSpecification].
*
* A task created from this specification is a `Future<HttpRequest>`.
*
* *Experimental*. This class may disappear without notice.
*/
class HttpRequestTaskSpecification extends TaskSpecification {
/// The URL of the request.
final String url;
/// The HTTP request method.
///
/// By default (when `null`) this is a `"GET"` request. Alternatively, the
/// method can be `"POST"`, `"PUT"`, `"DELETE"`, etc.
final String method;
/// Whether the request should send credentials. Credentials are only useful
/// for cross-origin requests.
///
/// See [HttpRequest.request] for more information.
final bool withCredentials;
/// The desired response format.
///
/// Supported types are:
/// - `""`: (same as `"text"`),
/// - `"arraybuffer"`,
/// - `"blob"`,
/// - `"document"`,
/// - `"json"`,
/// - `"text"`
///
/// When no value is provided (when equal to `null`) defaults to `""`.
final String responseType;
/// The desired MIME type.
///
/// This overrides the default MIME type which is set up to transfer textual
/// data.
final String mimeType;
/// The request headers that should be sent with the request.
final Map<String, String> requestHeaders;
/// The data that is sent with the request.
///
/// When data is provided (the value is not `null`), it must be a
/// [ByteBuffer], [Blob], [Document], [String], or [FormData].
final dynamic sendData;
/// The function that is invoked on progress updates. This function is
/// registered as an event listener on the created [HttpRequest] object, and
/// thus has its own task. Further invocations of the progress function do
/// *not* use the HTTP request task as task object.
///
/// Creating an HTTP request automatically registers the on-progress listener.
final ZoneUnaryCallback<dynamic, ProgressEvent> onProgress;
HttpRequestTaskSpecification(this.url,
{String this.method, bool this.withCredentials, String this.responseType,
String this.mimeType, Map<String, String> this.requestHeaders,
this.sendData,
void this.onProgress(ProgressEvent e)});
String get name => "dart.html.http-request";
bool get isOneShot => true;
}
/**
* A task specification for HTTP requests that are initiated through a direct
* invocation of [HttpRequest.send].
*
* This specification serves as signal to zones that an HTTP request has been
* initiated. The created task is the [request] object itself, and
* no callback is ever executed in this task.
*
* Note that event listeners on the HTTP request are also registered in the
* zone (although with their own task creations), and that a zone can thus
* detect when the HTTP request returns.
*
* HTTP requests that are initiated through `request` methods don't use
* this class but use [HttpRequestTaskSpecification].
*
* *Experimental*. This class may disappear without notice.
*/
class HttpRequestSendTaskSpecification extends TaskSpecification {
final HttpRequest request;
final dynamic sendData;
HttpRequestSendTaskSpecification(this.request, this.sendData);
String get name => "dart.html.http-request-send";
/**
* No callback is ever executed in an HTTP request send task.
*/
bool get isOneShot => false;
}
/**
* A client-side XHR request for getting data from a URL,
* formally known as XMLHttpRequest.
@ -21287,34 +21184,7 @@ class HttpRequest extends HttpRequestEventTarget {
{String method, bool withCredentials, String responseType,
String mimeType, Map<String, String> requestHeaders, sendData,
void onProgress(ProgressEvent e)}) {
var spec = new HttpRequestTaskSpecification(
url, method: method,
withCredentials: withCredentials,
responseType: responseType,
mimeType: mimeType,
requestHeaders: requestHeaders,
sendData: sendData,
onProgress: onProgress);
if (identical(Zone.current, Zone.ROOT)) {
return _createHttpRequestTask(spec, null);
}
return Zone.current.createTask(_createHttpRequestTask, spec);
}
static Future<HttpRequest> _createHttpRequestTask(
HttpRequestTaskSpecification spec, Zone zone) {
String url = spec.url;
String method = spec.method;
bool withCredentials = spec.withCredentials;
String responseType = spec.responseType;
String mimeType = spec.mimeType;
Map<String, String> requestHeaders = spec.requestHeaders;
var sendData = spec.sendData;
var onProgress = spec.onProgress;
var completer = new Completer<HttpRequest>();
var task = completer.future;
var xhr = new HttpRequest();
if (method == null) {
@ -21354,42 +21224,23 @@ class HttpRequest extends HttpRequestEventTarget {
// redirect case will be handled by the browser before it gets to us,
// so if we see it we should pass it through to the user.
var unknownRedirect = xhr.status > 307 && xhr.status < 400;
var isSuccessful = accepted || fileUri || notModified || unknownRedirect;
if (zone == null && isSuccessful) {
if (accepted || fileUri || notModified || unknownRedirect) {
completer.complete(xhr);
} else if (zone == null) {
completer.completeError(e);
} else if (isSuccessful) {
zone.runTask((task, value) {
completer.complete(value);
}, task, xhr);
} else {
zone.runTask((task, error) {
completer.completeError(error);
}, task, e);
completer.completeError(e);
}
});
if (zone == null) {
xhr.onError.listen(completer.completeError);
} else {
xhr.onError.listen((error) {
zone.runTask((task, error) {
completer.completeError(error);
}, task, error);
});
}
xhr.onError.listen(completer.completeError);
if (sendData != null) {
// TODO(floitsch): should we go through 'send()' and have nested tasks?
xhr._send(sendData);
xhr.send(sendData);
} else {
xhr._send();
xhr.send();
}
return task;
return completer.future;
}
/**
@ -21439,9 +21290,6 @@ class HttpRequest extends HttpRequestEventTarget {
return xhr.responseText;
});
}
// TODO(floitsch): the following code doesn't go through task zones.
// Since 'XDomainRequest' is an IE9 feature we should probably just remove
// it.
}
/**
@ -21492,7 +21340,7 @@ class HttpRequest extends HttpRequestEventTarget {
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `open` method is intended only for more complex HTTP requests where
* `open` method is intended only for more complext HTTP requests where
* finer-grained control is needed.
*/
@DomName('XMLHttpRequest.open')
@ -21505,36 +21353,6 @@ class HttpRequest extends HttpRequestEventTarget {
}
}
/**
* Sends the request with any given `data`.
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `send` method is intended only for more complex HTTP requests where
* finer-grained control is needed.
*
* ## Other resources
*
* * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#send%28%29)
* from MDN.
*/
@DomName('XMLHttpRequest.send')
@DocsEditable()
void send([body_OR_data]) {
if (identical(Zone.current, Zone.ROOT)) {
_send(body_OR_data);
} else {
Zone.current.createTask(_createHttpRequestSendTask,
new HttpRequestSendTaskSpecification(this, body_OR_data));
}
}
static HttpRequest _createHttpRequestSendTask(
HttpRequestSendTaskSpecification spec, Zone zone) {
spec.request._send(spec.sendData);
return spec.request;
}
// To suppress missing implicit constructor warnings.
factory HttpRequest._() { throw new UnsupportedError("Not supported"); }
@ -21838,7 +21656,7 @@ class HttpRequest extends HttpRequestEventTarget {
@SupportedBrowser(SupportedBrowser.SAFARI)
void overrideMimeType(String mime) => _blink.BlinkXMLHttpRequest.instance.overrideMimeType_Callback_1_(this, mime);
void _send([body_OR_data]) {
void send([body_OR_data]) {
if (body_OR_data != null) {
_blink.BlinkXMLHttpRequest.instance.send_Callback_1_(this, body_OR_data);
return;
@ -37844,10 +37662,10 @@ class Url extends DartHtmlDomObject implements UrlUtils {
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
if ((blob_OR_source_OR_stream is MediaSource)) {
if ((blob_OR_source_OR_stream is MediaStream)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
if ((blob_OR_source_OR_stream is MediaStream)) {
if ((blob_OR_source_OR_stream is MediaSource)) {
return _blink.BlinkURL.instance.createObjectURL_Callback_1_(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@ -39313,99 +39131,6 @@ class WheelEvent extends MouseEvent {
// BSD-style license that can be found in the LICENSE file.
typedef void RemoveFrameRequestMapping(int id);
/**
* The task object representing animation-frame requests.
*
* For historical reasons, [Window.requestAnimationFrame] returns an integer
* to users. However, zone tasks must be unique objects, and an integer can
* therefore not be used as task object. The [Window] class thus keeps a mapping
* from the integer ID to the corresponding task object. All zone related
* operations work on this task object, whereas users of
* [Window.requestAnimationFrame] only see the integer ID.
*
* Since this mapping takes up space, it must be removed when the
* animation-frame task has triggered. The default implementation does this
* automatically, but intercepting implementations of `requestAnimationFrame`
* must make sure to call the [AnimationFrameTask.removeMapping]
* function that is provided in the task specification.
*
* *Experimental*. This class may disappear without notice.
*/
abstract class AnimationFrameTask {
/** The ID that is returned to users. */
int get id;
/** The zone in which the task will run. */
Zone get zone;
/**
* Cancels the animation-frame request.
*
* A call to [Window.cancelAnimationFrame] with an `id` argument equal to [id]
* forwards the request to this function.
*
* Zones that intercept animation-frame requests implement this method so
* that they can react to cancelation requests.
*/
void cancel(Window window);
/**
* Maps animation-frame request IDs to their task objects.
*/
static final Map<int, _AnimationFrameTask> _tasks = {};
/**
* Removes the mapping from [id] to [AnimationFrameTask].
*
* This function must be invoked by user-implemented animation-frame
* tasks, before running [callback].
*
* See [AnimationFrameTask].
*/
static void removeMapping(int id) {
_tasks.remove(id);
}
}
class _AnimationFrameTask implements AnimationFrameTask {
final int id;
final Zone zone;
final FrameRequestCallback _callback;
_AnimationFrameTask(this.id, this.zone, this._callback);
void cancel(Window window) {
window._cancelAnimationFrame(this.id);
}
}
/**
* The task specification for an animation-frame request.
*
* *Experimental*. This class may disappear without notice.
*/
class AnimationFrameRequestSpecification implements TaskSpecification {
/**
* The window on which [Window.requestAnimationFrame] was invoked.
*/
final Window window;
/**
* The callback that is executed when the animation-frame is ready.
*
* Note that the callback hasn't been registered in any zone when the `create`
* function (passed to [Zone.createTask]) is invoked.
*/
final FrameRequestCallback callback;
AnimationFrameRequestSpecification(this.window, this.callback);
String get name => "dart.html.request-animation-frame";
bool get isOneShot => true;
}
@DocsEditable()
/**
* Top-level container for the current browser tab or window.
@ -39460,7 +39185,9 @@ class Window extends EventTarget implements WindowEventHandlers, WindowBase, Glo
*/
Future<num> get animationFrame {
var completer = new Completer<num>.sync();
requestAnimationFrame(completer.complete);
requestAnimationFrame((time) {
completer.complete(time);
});
return completer.future;
}
@ -44765,41 +44492,6 @@ 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.
*/
@ -44807,16 +44499,8 @@ 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, String eventType, this._useCapture,
{String name, bool isOneShot: false})
: _eventType = eventType,
_isOneShot = isOneShot,
_name = name ?? "dart.html.event.$eventType";
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
@ -44824,31 +44508,13 @@ 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 _listen(onData, useCapture: this._useCapture);
return new _EventStreamSubscription<T>(
this._target, this._eventType, onData, this._useCapture);
}
}
@ -44863,9 +44529,8 @@ bool _matchesWithAncestors(Event event, String selector) {
*/
class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
implements ElementStream<T> {
_ElementEventStreamImpl(target, eventType, useCapture,
{String name, bool isOneShot: false}) :
super(target, eventType, useCapture, name: name, isOneShot: isOneShot);
_ElementEventStreamImpl(target, eventType, useCapture) :
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
(event) => _matchesWithAncestors(event, selector)).map((e) {
@ -44873,9 +44538,9 @@ class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
return e;
});
StreamSubscription<T> capture(void onData(T event)) {
return _listen(onData, useCapture: true);
}
StreamSubscription<T> capture(void onData(T event)) =>
new _EventStreamSubscription<T>(
this._target, this._eventType, onData, true);
}
/**
@ -44924,13 +44589,7 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
bool get isBroadcast => true;
}
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
// We would like this to just be EventListener<T> but that typdef cannot
// use generics until dartbug/26276 is fixed.
typedef _EventListener<T extends Event>(T event);
@ -44939,19 +44598,15 @@ 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/*<dynamic, Event>*/((e) => onData(e as T))
// _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((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, Zone zone)
: _zone = zone,
_onData = _registerZone/*<dynamic, Event>*/(zone, onData) {
this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@ -44973,7 +44628,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
// Remove current event listener.
_unlisten();
_onData = _registerZone/*<dynamic, Event>*/(_zone, handleData);
_onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@ -45002,25 +44657,14 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
void _tryResume() {
if (_onData == null || isPaused) return;
if (identical(_zone, Zone.ROOT)) {
_domCallback = _onData;
} else {
_domCallback = (event) {
_zone.runTask(_runEventNotification, this, event);
};
if (_onData != null && !isPaused) {
_target.addEventListener(_eventType, _onData, _useCapture);
}
_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, _domCallback, _useCapture);
_target.removeEventListener(_eventType, _onData, _useCapture);
}
}
@ -48212,26 +47856,31 @@ class _WrappedEvent implements Event {
// BSD-style license that can be found in the LICENSE file.
ZoneUnaryCallback/*<R, T>*/ _registerZone/*<R, T>*/(Zone zone,
ZoneUnaryCallback/*<R, T>*/ callback) {
// For performance reasons avoid registering if we are in the root zone.
if (identical(zone, Zone.ROOT)) return callback;
if (callback == null) return null;
return zone.registerUnaryCallback(callback);
}
// TODO(jacobr): remove these typedefs when dart:async supports generic types.
typedef R _wrapZoneCallback<A, R>(A a);
typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
ZoneUnaryCallback/*<R, T>*/ _wrapZone/*<R, T>*/(ZoneUnaryCallback/*<R, T>*/ callback) {
_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ callback) {
// For performance reasons avoid wrapping if we are in the root zone.
if (identical(Zone.current, Zone.ROOT)) return callback;
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
return Zone.current.bindUnaryCallback(callback, runGuarded: true);
// TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
// generic method support in zones.
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
_wrapZoneCallback/*<A, R>*/ wrapped =
Zone.current.bindUnaryCallback(callback, runGuarded: true);
return wrapped;
}
ZoneBinaryCallback/*<R, A, B>*/ _wrapBinaryZone/*<R, A, B>*/(
ZoneBinaryCallback/*<R, A, B>*/ callback) {
if (identical(Zone.current, Zone.ROOT)) return callback;
_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
return Zone.current.bindBinaryCallback(callback, runGuarded: true);
// We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
// generic method support in zones.
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
_wrapZoneBinaryCallback/*<A, B, R>*/ wrapped =
Zone.current.bindBinaryCallback(callback, runGuarded: true);
return wrapped;
}
/**

View file

@ -1,121 +0,0 @@
// Copyright (c) 2016, 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.
library EventTaskZoneTest;
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
import 'dart:async';
import 'dart:html';
// Tests event-subscription specifications.
main() {
useHtmlConfiguration();
var defaultTarget = new Element.div();
var defaultOnData = (x) => null;
EventSubscriptionSpecification createSpec({useCapture, isOneShot}) {
return new EventSubscriptionSpecification(
name: "name",
target: defaultTarget,
useCapture: useCapture,
isOneShot: isOneShot,
onData: defaultOnData,
eventType: "eventType");
}
for (var useCapture in [true, false]) {
for (var isOneShot in [true, false]) {
var spec = createSpec(useCapture: useCapture, isOneShot: isOneShot);
test(
"EventSubscriptionSpecification - constructor "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replaced = spec.replace(eventType: 'replace-eventType');
expect(replaced.name, "name");
expect(replaced.target, defaultTarget);
expect(replaced.useCapture, useCapture);
expect(replaced.isOneShot, isOneShot);
expect(replaced.onData, equals(defaultOnData));
expect(replaced.eventType, "replace-eventType");
});
test(
"replace name "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replaced = spec.replace(name: 'replace-name');
expect(replaced.name, "replace-name");
expect(replaced.target, defaultTarget);
expect(replaced.useCapture, useCapture);
expect(replaced.isOneShot, isOneShot);
expect(replaced.onData, equals(defaultOnData));
expect(replaced.eventType, "eventType");
});
test(
"replace target "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replacementTarget = new Element.a();
var replaced = spec.replace(target: replacementTarget);
expect(replaced.name, "name");
expect(replaced.target, replacementTarget);
expect(replaced.useCapture, useCapture);
expect(replaced.isOneShot, isOneShot);
expect(replaced.onData, equals(defaultOnData));
expect(replaced.eventType, "eventType");
});
test(
"replace useCapture "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replaced = spec.replace(useCapture: !useCapture);
expect(replaced.name, "name");
expect(replaced.target, defaultTarget);
expect(replaced.useCapture, !useCapture);
expect(replaced.isOneShot, isOneShot);
expect(replaced.onData, equals(defaultOnData));
expect(replaced.eventType, "eventType");
});
test(
"replace isOneShot "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replaced = spec.replace(isOneShot: !isOneShot);
expect(replaced.name, "name");
expect(replaced.target, defaultTarget);
expect(replaced.useCapture, useCapture);
expect(replaced.isOneShot, !isOneShot);
expect(replaced.onData, equals(defaultOnData));
expect(replaced.eventType, "eventType");
});
test(
"replace onData "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replacementOnData = (x) {};
var replaced = spec.replace(onData: replacementOnData);
expect(replaced.name, "name");
expect(replaced.target, defaultTarget);
expect(replaced.useCapture, useCapture);
expect(replaced.isOneShot, isOneShot);
expect(replaced.onData, equals(replacementOnData));
expect(replaced.eventType, "eventType");
});
test(
"replace eventType "
"useCapture: $useCapture isOneShot: $isOneShot", () {
var replaced = spec.replace(eventType: 'replace-eventType');
expect(replaced.name, "name");
expect(replaced.target, defaultTarget);
expect(replaced.useCapture, useCapture);
expect(replaced.isOneShot, isOneShot);
expect(replaced.onData, equals(defaultOnData));
expect(replaced.eventType, "replace-eventType");
});
}
}
}

View file

@ -1,239 +0,0 @@
// Copyright (c) 2016, 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.
library EventTaskZoneTest;
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
import 'dart:async';
import 'dart:html';
// Tests zone tasks with DOM events.
class AbortedEventStreamSubscription implements StreamSubscription<Event> {
final Zone zone;
AbortedEventStreamSubscription(this.zone);
@override
Future asFuture([futureValue]) {
throw new UnsupportedError("asFuture");
}
@override
Future cancel() {
return null;
}
@override
bool get isPaused => throw new UnsupportedError("pause");
@override
void onData(void handleData(Event data)) {
throw new UnsupportedError("cancel");
}
@override
void onDone(void handleDone()) {
throw new UnsupportedError("onDone");
}
@override
void onError(Function handleError) {
throw new UnsupportedError("onError");
}
@override
void pause([Future resumeSignal]) {
throw new UnsupportedError("pause");
}
@override
void resume() {
throw new UnsupportedError("resume");
}
static AbortedEventStreamSubscription _create(
EventSubscriptionSpecification spec, Zone zone) {
return new AbortedEventStreamSubscription(zone);
}
}
eventTest(String name, Event eventFn(), void validate(Event event),
void validateSpec(EventSubscriptionSpecification spec),
{String type: 'foo',
bool abortCreation: false,
EventSubscriptionSpecification modifySpec(
EventSubscriptionSpecification spec),
bool abortEvent: false,
Event modifyEvent(Event event)}) {
test(name, () {
var lastSpec;
var lastTask;
var lastEvent;
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
if (specification is EventSubscriptionSpecification) {
if (abortCreation) {
create = AbortedEventStreamSubscription._create;
}
if (modifySpec != null) {
specification = modifySpec(specification);
}
lastSpec = specification;
return lastTask = parent.createTask(zone, create, specification);
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
if (identical(task, lastTask)) {
if (abortEvent) return;
if (modifyEvent != null) {
arg = modifyEvent(arg);
}
parent.runTask(zone, run, task, arg);
return;
}
parent.runTask(zone, run, task, arg);
}
runZoned(() {
final el = new Element.tag('div');
var fired = false;
var sub = el.on[type].listen((ev) {
lastEvent = ev;
fired = true;
});
el.dispatchEvent(eventFn());
validateSpec(lastSpec);
validate(lastEvent);
if (abortEvent || abortCreation) {
expect(fired, isFalse, reason: 'Expected event to be intercepted.');
} else {
expect(fired, isTrue, reason: 'Expected event to be dispatched.');
}
sub.cancel();
},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
});
}
Function checkSpec(
[String expectedType = 'foo', bool expectedUseCapture = false]) {
return (EventSubscriptionSpecification spec) {
expect(spec.eventType, expectedType);
expect(spec.useCapture, expectedUseCapture);
};
}
main() {
useHtmlConfiguration();
eventTest('Event', () => new Event('foo'), (ev) {
expect(ev.type, equals('foo'));
}, checkSpec('foo'));
eventTest(
'WheelEvent',
() => new WheelEvent("mousewheel",
deltaX: 1,
deltaY: 0,
detail: 4,
screenX: 3,
screenY: 4,
clientX: 5,
clientY: 6,
ctrlKey: true,
altKey: true,
shiftKey: true,
metaKey: true), (ev) {
expect(ev.deltaX, 1);
expect(ev.deltaY, 0);
expect(ev.screen.x, 3);
expect(ev.screen.y, 4);
expect(ev.client.x, 5);
expect(ev.client.y, 6);
expect(ev.ctrlKey, isTrue);
expect(ev.altKey, isTrue);
expect(ev.shiftKey, isTrue);
expect(ev.metaKey, isTrue);
}, checkSpec('mousewheel'), type: 'mousewheel');
eventTest('Event - no-create', () => new Event('foo'), (ev) {
expect(ev, isNull);
}, checkSpec('foo'), abortCreation: true);
eventTest(
'WheelEvent - no-create',
() => new WheelEvent("mousewheel",
deltaX: 1,
deltaY: 0,
detail: 4,
screenX: 3,
screenY: 4,
clientX: 5,
clientY: 6,
ctrlKey: true,
altKey: true,
shiftKey: true,
metaKey: true), (ev) {
expect(ev, isNull);
}, checkSpec('mousewheel'), type: 'mousewheel', abortCreation: true);
eventTest('Event - no-run', () => new Event('foo'), (ev) {
expect(ev, isNull);
}, checkSpec('foo'), abortEvent: true);
eventTest(
'WheelEvent - no-run',
() => new WheelEvent("mousewheel",
deltaX: 1,
deltaY: 0,
detail: 4,
screenX: 3,
screenY: 4,
clientX: 5,
clientY: 6,
ctrlKey: true,
altKey: true,
shiftKey: true,
metaKey: true), (ev) {
expect(ev, isNull);
}, checkSpec('mousewheel'), type: 'mousewheel', abortEvent: true);
// Register for 'foo', but receive a 'bar' event, because the specification
// is rewritten.
eventTest(
'Event - replace eventType',
() => new Event('bar'),
(ev) {
expect(ev.type, equals('bar'));
},
checkSpec('bar'),
type: 'foo',
modifySpec: (EventSubscriptionSpecification spec) {
return spec.replace(eventType: 'bar');
});
// Intercept the 'foo' event and replace it with a 'bar' event.
eventTest(
'Event - intercept result',
() => new Event('foo'),
(ev) {
expect(ev.type, equals('bar'));
},
checkSpec('foo'),
type: 'foo',
modifyEvent: (Event event) {
return new Event('bar');
});
}

View file

@ -142,7 +142,6 @@ notification_test/supported_notification: Fail # Notification not supported on I
event_test: RuntimeError # Issue 23437. Only three failures, but hard to break them out.
wheelevent_test: RuntimeError # Issue 23437
text_event_test: RuntimeError # Issue 23437
event_zone_task_test: RuntimeError # Issue 23437
transition_event_test/functional: Skip # Times out. Issue 22167
request_animation_frame_test: Skip # Times out. Issue 22167
@ -362,7 +361,6 @@ touchevent_test/supported: Fail
[ (($runtime == dartium || $runtime == drt) && $system == macos) || $system == windows ]
xhr_test/xhr: Skip # Times out. Issue 21527
xhr_task_test/xhr: Skip # Times out. Issue 21527
[ $compiler == dart2analyzer ]
custom/document_register_basic_test: StaticWarning

View file

@ -1,170 +0,0 @@
// Copyright (c) 2016, 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.
library EventTaskZoneTest;
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
import 'dart:async';
import 'dart:html';
// Tests zone tasks with window.requestAnimationFrame.
class MockAnimationFrameTask implements AnimationFrameTask {
static int taskId = 499;
final int id;
final Zone zone;
bool _isCanceled = false;
Function _callback;
MockAnimationFrameTask(
this.id, this.zone, this._callback);
void cancel(Window window) {
_isCanceled = true;
}
trigger(num stamp) {
zone.runTask(run, this, stamp);
}
static create(AnimationFrameRequestSpecification spec, Zone zone) {
var callback = zone.registerUnaryCallback(spec.callback);
return new MockAnimationFrameTask(
taskId++, zone, callback);
}
static run(MockAnimationFrameTask task, num arg) {
AnimationFrameTask.removeMapping(task.id);
task._callback(arg);
}
}
animationFrameTest() {
test("animationFrameTest - no intercept", () async {
AnimationFrameTask lastTask;
bool sawRequest = false;
int id;
num providedArg;
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
if (specification is AnimationFrameRequestSpecification) {
sawRequest = true;
lastTask = parent.createTask(zone, create, specification);
id = lastTask.id;
return lastTask;
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
if (identical(task, lastTask)) {
providedArg = arg;
}
parent.runTask(zone, run, task, arg);
}
var completer = new Completer();
var publicId;
runZoned(() {
publicId = window.requestAnimationFrame((num stamp) {
completer.complete(stamp);
});
},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler, runTask: runTaskHandler));
var referenceCompleter = new Completer();
window.requestAnimationFrame((num stamp) {
referenceCompleter.complete(stamp);
});
var callbackStamp = await completer.future;
var referenceStamp = await referenceCompleter.future;
expect(callbackStamp, equals(referenceStamp));
expect(providedArg, equals(callbackStamp));
expect(sawRequest, isTrue);
expect(publicId, isNotNull);
expect(publicId, equals(id));
});
}
interceptedAnimationFrameTest() {
test("animationFrameTest - intercepted", () {
List<MockAnimationFrameTask> tasks = [];
List<num> loggedRuns = [];
int executedTaskId;
int executedStamp;
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
if (specification is AnimationFrameRequestSpecification) {
var task = parent.createTask(
zone, MockAnimationFrameTask.create, specification);
tasks.add(task);
return task;
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
if (tasks.contains(task)) {
loggedRuns.add(arg);
}
parent.runTask(zone, run, task, arg);
}
var id0, id1, id2;
runZoned(() {
id0 = window.requestAnimationFrame((num stamp) {
executedTaskId = id0;
executedStamp = stamp;
});
id1 = window.requestAnimationFrame((num stamp) {
executedTaskId = id1;
executedStamp = stamp;
});
id2 = window.requestAnimationFrame((num stamp) {
executedTaskId = id2;
executedStamp = stamp;
});
},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler, runTask: runTaskHandler));
expect(tasks.length, 3);
expect(executedTaskId, isNull);
expect(executedStamp, isNull);
expect(loggedRuns.isEmpty, isTrue);
tasks[0].trigger(123.1);
expect(executedTaskId, id0);
expect(executedStamp, 123.1);
tasks[1].trigger(123.2);
expect(executedTaskId, id1);
expect(executedStamp, 123.2);
expect(loggedRuns, equals([123.1, 123.2]));
window.cancelAnimationFrame(id2);
expect(tasks[2]._isCanceled, isTrue);
// Cancel it a second time. Should not crash.
window.cancelAnimationFrame(id2);
expect(tasks[2]._isCanceled, isTrue);
});
}
main() {
useHtmlConfiguration();
animationFrameTest();
interceptedAnimationFrameTest();
}

View file

@ -1,280 +0,0 @@
// Copyright (c) 2016, 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.
library XHRTask2Test;
import 'dart:async';
import 'dart:convert';
import 'dart:html';
import 'dart:typed_data';
import 'package:unittest/html_individual_config.dart';
import 'package:unittest/unittest.dart';
class MockProgressEvent implements ProgressEvent {
final target;
MockProgressEvent(this.target);
noSuchMethod(Invocation invocation) {
throw "missing function in MockProgressEvent";
}
}
class MockHttpRequestTask implements Future<HttpRequest> {
final Completer completer = new Completer<HttpRequest>();
final HttpRequestTaskSpecification spec;
final Zone zone;
MockHttpRequestTask(this.spec, this.zone);
void trigger(response) {
var xhr = new MockHttpRequest(spec, response);
var arg;
if (spec.url == "NonExistingFile") {
arg = new MockProgressEvent(xhr);
} else {
arg = xhr;
}
zone.runTask(run, this, arg);
}
then(onData, {onError}) => completer.future.then(onData, onError: onError);
catchError(f, {test}) => completer.future.catchError(f, test: test);
whenComplete(f) => completer.future.whenComplete(f);
asStream() => completer.future.asStream();
timeout(timeLimit, {onTimeout}) =>
completer.future.timeout(timeLimit, onTimeout: onTimeout);
static create(HttpRequestTaskSpecification spec, Zone zone) {
return new MockHttpRequestTask(spec, zone);
}
static run(MockHttpRequestTask task, value) {
if (value is HttpRequest) {
task.completer.complete(value);
} else {
task.completer.completeError(value);
}
}
}
class MockHttpRequest implements HttpRequest {
final HttpRequestTaskSpecification spec;
final response;
MockHttpRequest(this.spec, this.response);
noSuchMethod(Invocation invocation) {
print("isGetter: ${invocation.isGetter}");
print("isMethod: ${invocation.isMethod}");
print("memberName: ${invocation.memberName}");
}
int get status => spec.url == "NonExistingFile" ? 404 : 200;
get readyState => HttpRequest.DONE;
get responseText => "$response";
Map get responseHeaders => {'content-type': 'text/plain; charset=utf-8',};
}
main() {
useHtmlIndividualConfiguration();
unittestConfiguration.timeout = const Duration(milliseconds: 800);
var urlExpando = new Expando();
var url = 'some/url.html';
Function buildCreateTaskHandler(List log, List tasks) {
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification spec) {
if (spec is HttpRequestTaskSpecification) {
var url = spec.url;
var method = spec.method;
var withCredentials = spec.withCredentials;
var responseType = spec.responseType;
var mimeType = spec.mimeType;
var data = spec.sendData;
log.add("request $url");
var dataLog = data is List<int> ? "binary ${data.length}" : "$data";
log.add(" method: $method withCredentials: $withCredentials "
"responseType: $responseType mimeType: $mimeType data: $dataLog");
var task = parent.createTask(zone, MockHttpRequestTask.create, spec);
urlExpando[task] = url;
tasks.add(task);
return task;
}
if (spec is EventSubscriptionSpecification) {
EventSubscriptionSpecification eventSpec = spec;
if (eventSpec.target is HttpRequest) {
HttpRequest target = eventSpec.target;
log.add("event listener on http-request ${eventSpec.eventType}");
if (eventSpec.eventType == "readystatechange") {
var oldOnData = eventSpec.onData;
spec = eventSpec.replace(onData: (event) {
oldOnData(event);
if (target.readyState == HttpRequest.DONE) {
log.add("unknown request done");
}
});
}
}
}
return parent.createTask(zone, create, spec);
}
return createTaskHandler;
}
Function buildRunTaskHandler(List log, List tasks) {
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
if (tasks.contains(task)) {
var url = urlExpando[task];
if (arg is Error || arg is Exception) {
log.add("failed $url");
} else {
if (arg is ProgressEvent) {
log.add("success $url with progress-event");
} else if (arg is HttpRequest) {
log.add("success $url with http-request");
} else {
log.add("success $url (unknown arg)");
}
}
}
parent.runTask(zone, run, task, arg);
}
return runTaskHandler;
}
Future<List> runMocked(response, fun) async {
var log = [];
var tasks = [];
var future = runZoned(fun,
zoneSpecification: new ZoneSpecification(
createTask: buildCreateTaskHandler(log, tasks),
runTask: buildRunTaskHandler(log, tasks)));
// Wait a full cycle to make sure things settle.
await new Future(() {});
var beforeTriggerLog = log.toList();
log.clear();
expect(tasks.length, 1);
tasks.single.trigger(response);
await future;
return [beforeTriggerLog, log];
}
void validate200Response(xhr) {
expect(xhr.status, equals(200));
var data = JSON.decode(xhr.responseText);
expect(data, contains('feed'));
expect(data['feed'], contains('entry'));
expect(data, isMap);
}
void validate404(xhr) {
expect(xhr.status, equals(404));
// We cannot say much about xhr.responseText, most HTTP servers will
// include an HTML page explaining the error to a human.
String responseText = xhr.responseText;
expect(responseText, isNotNull);
}
group('xhr', () {
test('XHR.request No file', () async {
var log = await runMocked("404", () {
var completer = new Completer();
HttpRequest.request('NonExistingFile').then((_) {
fail('Request should not have succeeded.');
}, onError: expectAsync((error) {
var xhr = error.target;
expect(xhr.readyState, equals(HttpRequest.DONE));
validate404(xhr);
completer.complete('done');
}));
return completer.future;
});
expect(
log,
equals([
[
'request NonExistingFile',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null',
],
['success NonExistingFile with progress-event']
]));
});
test('XHR.request file', () async {
var log = await runMocked('{"feed": {"entry": 499}}', () {
var completer = new Completer();
HttpRequest.request(url).then(expectAsync((xhr) {
expect(xhr.readyState, equals(HttpRequest.DONE));
validate200Response(xhr);
completer.complete('done');
}));
return completer.future;
});
expect(
log,
equals([
[
'request $url',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null'
],
['success $url with http-request']
]));
});
test('XHR.getString file', () async {
var log = await runMocked("foo", () {
return HttpRequest.getString(url).then(expectAsync((str) {}));
});
expect(
log,
equals([
[
'request $url',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null'
],
['success $url with http-request']
]));
});
test('XHR.request responseType arraybuffer', () async {
if (Platform.supportsTypedData) {
var data = new Uint8List(128);
var log = await runMocked(data.buffer, () {
return HttpRequest.request(url,
responseType: 'arraybuffer',
requestHeaders: {
'Content-Type': 'text/xml'
}).then(expectAsync((xhr) {
expect(xhr.status, equals(200));
var byteBuffer = xhr.response;
expect(byteBuffer, new isInstanceOf<ByteBuffer>());
expect(byteBuffer, isNotNull);
}));
});
expect(
log,
equals([
[
'request $url',
' method: null withCredentials: null responseType: arraybuffer'
' mimeType: null data: null'
],
['success $url with http-request']
]));
}
;
});
});
}

View file

@ -1,508 +0,0 @@
// Copyright (c) 2016, 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.
library XHRTaskTest;
import 'dart:async';
import 'dart:convert';
import 'dart:html';
import 'dart:typed_data';
import 'package:unittest/html_individual_config.dart';
import 'package:unittest/unittest.dart';
main() {
useHtmlIndividualConfiguration();
// Cache blocker is a workaround for:
// https://code.google.com/p/dart/issues/detail?id=11834
var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
var url = '/root_dart/tests/html/xhr_cross_origin_data.txt?'
'cacheBlock=$cacheBlocker';
var urlExpando = new Expando();
Function buildCreateTaskHandler(List log, List tasks) {
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification spec) {
if (spec is HttpRequestTaskSpecification) {
var url = spec.url;
var method = spec.method;
var withCredentials = spec.withCredentials;
var responseType = spec.responseType;
var mimeType = spec.mimeType;
var data = spec.sendData;
log.add("request $url");
var dataLog = data is List<int> ? "binary ${data.length}" : "$data";
log.add(" method: $method withCredentials: $withCredentials "
"responseType: $responseType mimeType: $mimeType data: $dataLog");
var task = parent.createTask(zone, create, spec);
urlExpando[task] = url;
tasks.add(task);
return task;
}
if (spec is HttpRequestSendTaskSpecification) {
var data = spec.sendData;
var dataLog = data is List<int> ? "binary ${data.length}" : "$data";
log.add("http-request (no info), data: $dataLog");
var task = parent.createTask(zone, create, spec);
tasks.add(task);
urlExpando[task] = "unknown";
return task;
}
if (spec is EventSubscriptionSpecification) {
EventSubscriptionSpecification eventSpec = spec;
if (eventSpec.target is HttpRequest) {
HttpRequest target = eventSpec.target;
log.add("event listener on http-request ${eventSpec.eventType}");
if (eventSpec.eventType == "readystatechange") {
var oldOnData = eventSpec.onData;
spec = eventSpec.replace(onData: (event) {
oldOnData(event);
if (target.readyState == HttpRequest.DONE) {
log.add("unknown request done");
}
});
}
}
}
return parent.createTask(zone, create, spec);
}
return createTaskHandler;
}
Function buildRunTaskHandler(List log, List tasks) {
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskRun run, Object task, Object arg) {
if (tasks.contains(task)) {
var url = urlExpando[task];
if (arg is Error || arg is Exception) {
log.add("failed $url");
} else {
if (arg is ProgressEvent) {
log.add("success $url with progress-event");
} else if (arg is HttpRequest){
log.add("success $url with http-request");
} else {
log.add("success $url (unknown arg)");
}
}
}
parent.runTask(zone, run, task, arg);
}
return runTaskHandler;
}
Future<List> runWithLogging(fun) async {
var log = [];
var tasks = [];
await runZoned(fun, zoneSpecification: new ZoneSpecification(
createTask: buildCreateTaskHandler(log, tasks),
runTask: buildRunTaskHandler(log, tasks)));
return log;
}
void validate200Response(xhr) {
expect(xhr.status, equals(200));
var data = JSON.decode(xhr.responseText);
expect(data, contains('feed'));
expect(data['feed'], contains('entry'));
expect(data, isMap);
}
void validate404(xhr) {
expect(xhr.status, equals(404));
// We cannot say much about xhr.responseText, most HTTP servers will
// include an HTML page explaining the error to a human.
String responseText = xhr.responseText;
expect(responseText, isNotNull);
}
group('xhr', () {
test('XHR No file', () async {
var log = await runWithLogging(() {
var completer = new Completer();
HttpRequest xhr = new HttpRequest();
xhr.open("GET", "NonExistingFile", async: true);
xhr.onReadyStateChange.listen(expectAsyncUntil((event) {
if (xhr.readyState == HttpRequest.DONE) {
validate404(xhr);
completer.complete("done");
}
}, () => xhr.readyState == HttpRequest.DONE));
xhr.send();
return completer.future;
});
expect(log, equals([
'event listener on http-request readystatechange',
'http-request (no info), data: null',
'unknown request done'
]));
});
test('XHR_file', () async {
var log = await runWithLogging(() {
var completer = new Completer();
var loadEndCalled = false;
var xhr = new HttpRequest();
xhr.open('GET', url, async: true);
xhr.onReadyStateChange.listen(expectAsyncUntil((e) {
if (xhr.readyState == HttpRequest.DONE) {
validate200Response(xhr);
Timer.run(expectAsync(() {
expect(loadEndCalled, HttpRequest.supportsLoadEndEvent);
completer.complete("done");
}));
}
}, () => xhr.readyState == HttpRequest.DONE));
xhr.onLoadEnd.listen((ProgressEvent e) {
loadEndCalled = true;
});
xhr.send();
return completer.future;
});
expect(log, equals([
'event listener on http-request readystatechange',
'event listener on http-request loadend',
'http-request (no info), data: null',
'unknown request done'
]));
});
test('XHR.request No file', () async {
var log = await runWithLogging(() {
var completer = new Completer();
HttpRequest.request('NonExistingFile').then(
(_) { fail('Request should not have succeeded.'); },
onError: expectAsync((error) {
var xhr = error.target;
expect(xhr.readyState, equals(HttpRequest.DONE));
validate404(xhr);
completer.complete('done');
}));
return completer.future;
});
expect(log, equals([
'request NonExistingFile',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success NonExistingFile with progress-event'
]));
});
test('XHR.request file', () async {
var log = await runWithLogging(() {
var completer = new Completer();
HttpRequest.request(url).then(expectAsync((xhr) {
expect(xhr.readyState, equals(HttpRequest.DONE));
validate200Response(xhr);
completer.complete('done');
}));
return completer.future;
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
test('XHR.request onProgress', () async {
var log = await runWithLogging(() {
var completer = new Completer();
var progressCalled = false;
HttpRequest.request(url,
onProgress: (_) {
progressCalled = true;
}).then(expectAsync(
(xhr) {
expect(xhr.readyState, equals(HttpRequest.DONE));
expect(progressCalled, HttpRequest.supportsProgressEvent);
validate200Response(xhr);
completer.complete("done");
}));
return completer.future;
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null',
'event listener on http-request progress',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
test('XHR.request withCredentials No file', () async {
var log = await runWithLogging(() {
var completer = new Completer();
HttpRequest.request('NonExistingFile', withCredentials: true).then(
(_) { fail('Request should not have succeeded.'); },
onError: expectAsync((error) {
var xhr = error.target;
expect(xhr.readyState, equals(HttpRequest.DONE));
validate404(xhr);
completer.complete("done");
}));
return completer.future;
});
expect(log, equals([
'request NonExistingFile',
' method: null withCredentials: true responseType: null '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success NonExistingFile with progress-event'
]));
});
test('XHR.request withCredentials file', () async {
var log = await runWithLogging(() {
var completer = new Completer();
HttpRequest.request(url, withCredentials: true).then(expectAsync((xhr) {
expect(xhr.readyState, equals(HttpRequest.DONE));
validate200Response(xhr);
completer.complete("done");
}));
return completer.future;
});
expect(log, equals([
'request $url',
' method: null withCredentials: true responseType: null '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
test('XHR.getString file', () async {
var log = await runWithLogging(() {
return HttpRequest.getString(url).then(expectAsync((str) {}));
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
test('XHR.getString No file', () async {
var log = await runWithLogging(() {
return HttpRequest.getString('NonExistingFile').then(
(_) { fail('Succeeded for non-existing file.'); },
onError: expectAsync((error) {
validate404(error.target);
}));
});
expect(log, equals([
'request NonExistingFile',
' method: null withCredentials: null responseType: null '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success NonExistingFile with progress-event'
]));
});
test('XHR.request responseType arraybuffer', () async {
if (Platform.supportsTypedData) {
var log = await runWithLogging(() {
return HttpRequest.request(url, responseType: 'arraybuffer',
requestHeaders: {'Content-Type': 'text/xml'}).then(
expectAsync((xhr) {
expect(xhr.status, equals(200));
var byteBuffer = xhr.response;
expect(byteBuffer, new isInstanceOf<ByteBuffer>());
expect(byteBuffer, isNotNull);
}));
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: arraybuffer '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
};
});
test('overrideMimeType', () async {
var expectation =
HttpRequest.supportsOverrideMimeType ? returnsNormally : throws;
var log = await runWithLogging(() {
var completer = new Completer();
expect(() {
HttpRequest.request(url, mimeType: 'application/binary')
.whenComplete(completer.complete);
}, expectation);
return completer.future;
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: null '
'mimeType: application/binary data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
if (Platform.supportsTypedData) {
test('xhr upload', () async {
var log = await runWithLogging(() {
var xhr = new HttpRequest();
var progressCalled = false;
xhr.upload.onProgress.listen((e) {
progressCalled = true;
});
xhr.open('POST',
'${window.location.protocol}//${window.location.host}/echo');
// 10MB of payload data w/ a bit of data to make sure it
// doesn't get compressed to nil.
var data = new Uint8List(1 * 1024 * 1024);
for (var i = 0; i < data.length; ++i) {
data[i] = i & 0xFF;
}
xhr.send(new Uint8List.view(data.buffer));
return xhr.onLoad.first.then((_) {
expect(
progressCalled, isTrue, reason: 'onProgress should be fired');
});
});
expect(log, equals([
'http-request (no info), data: binary 1048576',
'event listener on http-request load',
]));
});
}
test('xhr postFormData', () async {
var url = '${window.location.protocol}//${window.location.host}/echo';
var log = await runWithLogging(() {
var data = { 'name': 'John', 'time': '2 pm'};
var parts = [];
for (var key in data.keys) {
parts.add('${Uri.encodeQueryComponent(key)}='
'${Uri.encodeQueryComponent(data[key])}');
}
var encodedData = parts.join('&');
return HttpRequest.postFormData(url, data).then((xhr) {
expect(xhr.responseText, encodedData);
});
});
expect(log, equals([
'request $url',
' method: POST withCredentials: null responseType: null '
'mimeType: null data: name=John&time=2+pm',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
});
group('xhr_requestBlob', () {
test('XHR.request responseType blob', () async {
if (Platform.supportsTypedData) {
var log = await runWithLogging(() {
return HttpRequest.request(url, responseType: 'blob').then(
(xhr) {
expect(xhr.status, equals(200));
var blob = xhr.response;
expect(blob is Blob, isTrue);
expect(blob, isNotNull);
});
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: blob '
'mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
}
});
});
group('json', () {
test('xhr responseType json', () async {
var url = '${window.location.protocol}//${window.location.host}/echo';
var log = await runWithLogging(() {
var completer = new Completer();
var data = {
'key': 'value',
'a': 'b',
'one': 2,
};
HttpRequest.request(url,
method: 'POST',
sendData: JSON.encode(data),
responseType: 'json').then(
expectAsync((xhr) {
expect(xhr.status, equals(200));
var json = xhr.response;
expect(json, equals(data));
completer.complete("done");
}));
return completer.future;
});
expect(log, equals([
'request $url',
' method: POST withCredentials: null responseType: json mimeType: null'
' data: {"key":"value","a":"b","one":2}',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
});
group('headers', () {
test('xhr responseHeaders', () async {
var log = await runWithLogging(() {
return HttpRequest.request(url).then(
(xhr) {
var contentTypeHeader = xhr.responseHeaders['content-type'];
expect(contentTypeHeader, isNotNull);
// Should be like: 'text/plain; charset=utf-8'
expect(contentTypeHeader.contains('text/plain'), isTrue);
expect(contentTypeHeader.contains('charset=utf-8'), isTrue);
});
});
expect(log, equals([
'request $url',
' method: null withCredentials: null responseType: null'
' mimeType: null data: null',
'event listener on http-request load',
'event listener on http-request error',
'success $url with http-request'
]));
});
});
}

View file

@ -1,310 +0,0 @@
// Copyright (c) 2016, 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.
// Tests basic functionality of tasks in zones.
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'dart:async';
List log = [];
class MySpecification extends TaskSpecification {
final Function callback;
final bool isOneShot;
final int value;
MySpecification(void this.callback(), this.isOneShot, this.value);
String get name => "test.specification-name";
}
class MyTask {
final Zone zone;
final Function callback;
final int id;
int invocationCount = 0;
bool shouldStop = false;
MyTask(this.zone, void this.callback(), this.id);
}
void runMyTask(MyTask task, int value) {
log.add("running "
"zone: ${Zone.current['name']} "
"task-id: ${task.id} "
"invocation-count: ${task.invocationCount} "
"value: $value");
task.callback();
task.invocationCount++;
}
MyTask createMyTask(MySpecification spec, Zone zone) {
var task = new MyTask(zone, spec.callback, spec.value);
log.add("creating task: ${spec.value} oneshot?: ${spec.isOneShot}");
if (spec.isOneShot) {
Timer.run(() {
zone.runTask(runMyTask, task, task.id);
});
} else {
new Timer.periodic(const Duration(milliseconds: 10), (Timer timer) {
zone.runTask(runMyTask, task, task.id);
if (task.shouldStop) {
timer.cancel();
}
});
}
return task;
}
MyTask startTask(f, bool oneShot, int value) {
var spec = new MySpecification(f, oneShot, value);
return Zone.current.createTask(createMyTask, spec);
}
/// Makes sure things are working in a simple setting.
/// No interceptions, changes, ...
Future testCustomTask() {
var testCompleter = new Completer();
asyncStart();
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
if (specification is MySpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-value: ${specification.value} "
"spec-oneshot?: ${specification.isOneShot}");
MyTask result = parent.createTask(zone, create, specification);
log.add("create leave");
return result;
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
if (task is MyTask) {
log.add("run enter "
"zone: ${self['name']} "
"task-id: ${task.id} "
"invocation-count: ${task.invocationCount} "
"arg: $arg");
parent.runTask(zone, run, task, arg);
log.add("run leave invocation-count: ${task.invocationCount}");
return;
}
parent.runTask(zone, run, task, arg);
}
runZoned(() async {
var completer0 = new Completer();
startTask(() {
completer0.complete("done");
}, true, 0);
await completer0.future;
Expect.listEquals([
'create enter zone: custom zone spec-value: 0 spec-oneshot?: true',
'creating task: 0 oneshot?: true',
'create leave',
'run enter zone: custom zone task-id: 0 invocation-count: 0 arg: 0',
'running zone: custom zone task-id: 0 invocation-count: 0 value: 0',
'run leave invocation-count: 1'
], log);
log.clear();
var completer1 = new Completer();
MyTask task1;
task1 = startTask(() {
if (task1.invocationCount == 1) {
task1.shouldStop = true;
completer1.complete("done");
}
}, false, 1);
await completer1.future;
Expect.listEquals([
'create enter zone: custom zone spec-value: 1 spec-oneshot?: false',
'creating task: 1 oneshot?: false',
'create leave',
'run enter zone: custom zone task-id: 1 invocation-count: 0 arg: 1',
'running zone: custom zone task-id: 1 invocation-count: 0 value: 1',
'run leave invocation-count: 1',
'run enter zone: custom zone task-id: 1 invocation-count: 1 arg: 1',
'running zone: custom zone task-id: 1 invocation-count: 1 value: 1',
'run leave invocation-count: 2',
], log);
log.clear();
testCompleter.complete("done");
asyncEnd();
},
zoneValues: {'name': 'custom zone'},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
return testCompleter.future;
}
/// More complicated zone, that intercepts...
Future testCustomTask2() {
var testCompleter = new Completer();
asyncStart();
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
if (specification is MySpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-value: ${specification.value} "
"spec-oneshot?: ${specification.isOneShot}");
var replacement = new MySpecification(specification.callback,
specification.isOneShot, specification.value + 1);
MyTask result = parent.createTask(zone, create, replacement);
log.add("create leave");
return result;
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
if (task is MyTask) {
log.add("run enter "
"zone: ${self['name']} "
"task-id: ${task.id} "
"invocation-count: ${task.invocationCount} "
"arg: $arg");
int value = arg;
parent.runTask(zone, run, task, value + 101);
log.add("run leave invocation-count: ${task.invocationCount}");
return;
}
parent.runTask(zone, run, task, arg);
}
runZoned(() async {
var completer0 = new Completer();
startTask(() {
completer0.complete("done");
}, true, 0);
await completer0.future;
Expect.listEquals([
'create enter zone: outer-zone spec-value: 0 spec-oneshot?: true',
'creating task: 1 oneshot?: true',
'create leave',
'run enter zone: outer-zone task-id: 1 invocation-count: 0 arg: 1',
'running zone: outer-zone task-id: 1 invocation-count: 0 value: 102',
'run leave invocation-count: 1'
], log);
log.clear();
var completer1 = new Completer();
MyTask task1;
task1 = startTask(() {
if (task1.invocationCount == 1) {
task1.shouldStop = true;
completer1.complete("done");
}
}, false, 1);
await completer1.future;
Expect.listEquals([
'create enter zone: outer-zone spec-value: 1 spec-oneshot?: false',
'creating task: 2 oneshot?: false',
'create leave',
'run enter zone: outer-zone task-id: 2 invocation-count: 0 arg: 2',
'running zone: outer-zone task-id: 2 invocation-count: 0 value: 103',
'run leave invocation-count: 1',
'run enter zone: outer-zone task-id: 2 invocation-count: 1 arg: 2',
'running zone: outer-zone task-id: 2 invocation-count: 1 value: 103',
'run leave invocation-count: 2',
], log);
log.clear();
var nestedCompleter = new Completer();
runZoned(() async {
var completer0 = new Completer();
startTask(() {
completer0.complete("done");
}, true, 0);
await completer0.future;
Expect.listEquals([
'create enter zone: inner-zone spec-value: 0 spec-oneshot?: true',
'create enter zone: outer-zone spec-value: 1 spec-oneshot?: true',
'creating task: 2 oneshot?: true',
'create leave',
'create leave',
'run enter zone: inner-zone task-id: 2 invocation-count: 0 arg: 2',
'run enter zone: outer-zone task-id: 2 invocation-count: 0 arg: 103',
'running zone: inner-zone task-id: 2 invocation-count: 0 value: 204',
'run leave invocation-count: 1',
'run leave invocation-count: 1'
], log);
log.clear();
var completer1 = new Completer();
MyTask task1;
task1 = startTask(() {
if (task1.invocationCount == 1) {
task1.shouldStop = true;
completer1.complete("done");
}
}, false, 1);
await completer1.future;
Expect.listEquals([
'create enter zone: inner-zone spec-value: 1 spec-oneshot?: false',
'create enter zone: outer-zone spec-value: 2 spec-oneshot?: false',
'creating task: 3 oneshot?: false',
'create leave',
'create leave',
'run enter zone: inner-zone task-id: 3 invocation-count: 0 arg: 3',
'run enter zone: outer-zone task-id: 3 invocation-count: 0 arg: 104',
'running zone: inner-zone task-id: 3 invocation-count: 0 value: 205',
'run leave invocation-count: 1',
'run leave invocation-count: 1',
'run enter zone: inner-zone task-id: 3 invocation-count: 1 arg: 3',
'run enter zone: outer-zone task-id: 3 invocation-count: 1 arg: 104',
'running zone: inner-zone task-id: 3 invocation-count: 1 value: 205',
'run leave invocation-count: 2',
'run leave invocation-count: 2',
], log);
log.clear();
nestedCompleter.complete("done");
},
zoneValues: {'name': 'inner-zone'},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
await nestedCompleter.future;
testCompleter.complete("done");
asyncEnd();
},
zoneValues: {'name': 'outer-zone'},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
return testCompleter.future;
}
runTests() async {
await testCustomTask();
await testCustomTask2();
}
main() {
asyncStart();
runTests().then((_) {
asyncEnd();
});
}

View file

@ -1,515 +0,0 @@
// Copyright (c) 2016, 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.
// Tests timer tasks.
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'dart:async';
import 'dart:collection';
class MyTimerSpecification implements SingleShotTimerTaskSpecification {
final Function callback;
final Duration duration;
MyTimerSpecification(this.callback, this.duration);
bool get isOneShot => true;
String get name => "test.timer-override";
}
class MyPeriodicTimerSpecification implements PeriodicTimerTaskSpecification {
final Function callback;
final Duration duration;
MyPeriodicTimerSpecification(this.callback, this.duration);
bool get isOneShot => true;
String get name => "test.periodic-timer-override";
}
/// Makes sure things are working in a simple setting.
/// No interceptions, changes, ...
Future testTimerTask() {
List log = [];
var testCompleter = new Completer();
asyncStart();
int taskIdCounter = 0;
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
var taskMap = self['taskMap'];
var taskIdMap = self['taskIdMap'];
if (specification is SingleShotTimerTaskSpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-duration: ${specification.duration} "
"spec-oneshot?: ${specification.isOneShot}");
var result = parent.createTask(zone, create, specification);
taskMap[result] = specification;
taskIdMap[specification] = taskIdCounter++;
log.add("create leave");
return result;
} else if (specification is PeriodicTimerTaskSpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-duration: ${specification.duration} "
"spec-oneshot?: ${specification.isOneShot}");
var result = parent.createTask(zone, create, specification);
taskMap[result] = specification;
taskIdMap[specification] = taskIdCounter++;
log.add("create leave");
return result;
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
var taskMap = self['taskMap'];
var taskIdMap = self['taskIdMap'];
if (taskMap.containsKey(task)) {
var spec = taskMap[task];
log.add("run enter "
"zone: ${self['name']} "
"task-id: ${taskIdMap[spec]} "
"arg: $arg");
parent.runTask(zone, run, task, arg);
log.add("run leave");
return;
}
parent.runTask(zone, run, task, arg);
}
runZoned(() async {
var completer0 = new Completer();
Timer.run(() {
completer0.complete("done");
});
await completer0.future;
Expect.listEquals([
'create enter zone: custom zone spec-duration: 0:00:00.000000 '
'spec-oneshot?: true',
'create leave',
'run enter zone: custom zone task-id: 0 arg: null',
'run leave'
], log);
log.clear();
var completer1 = new Completer();
var counter1 = 0;
new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
if (counter1++ > 1) {
timer.cancel();
completer1.complete("done");
}
});
await completer1.future;
Expect.listEquals([
'create enter zone: custom zone spec-duration: 0:00:00.005000 '
'spec-oneshot?: false',
'create leave',
'run enter zone: custom zone task-id: 1 arg: null',
'run leave',
'run enter zone: custom zone task-id: 1 arg: null',
'run leave',
'run enter zone: custom zone task-id: 1 arg: null',
'run leave'
], log);
log.clear();
testCompleter.complete("done");
asyncEnd();
},
zoneValues: {'name': 'custom zone', 'taskMap': {}, 'taskIdMap': {}},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
return testCompleter.future;
}
/// More complicated zone, that intercepts...
Future testTimerTask2() {
List log = [];
var testCompleter = new Completer();
asyncStart();
int taskIdCounter = 0;
Object createTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
var taskMap = self['taskMap'];
var taskIdMap = self['taskIdMap'];
if (specification is SingleShotTimerTaskSpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-duration: ${specification.duration} "
"spec-oneshot?: ${specification.isOneShot}");
var mySpec = new MyTimerSpecification(specification.callback,
specification.duration + const Duration(milliseconds: 2));
var result = parent.createTask(zone, create, mySpec);
taskMap[result] = specification;
taskIdMap[specification] = taskIdCounter++;
log.add("create leave");
return result;
} else if (specification is PeriodicTimerTaskSpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-duration: ${specification.duration} "
"spec-oneshot?: ${specification.isOneShot}");
var mySpec = new MyPeriodicTimerSpecification(specification.callback,
specification.duration + const Duration(milliseconds: 2));
var result = parent.createTask(zone, create, specification);
taskMap[result] = specification;
taskIdMap[specification] = taskIdCounter++;
log.add("create leave");
return result;
}
return parent.createTask(zone, create, specification);
}
void runTaskHandler(Zone self, ZoneDelegate parent, Zone zone, TaskRun run,
Object task, Object arg) {
var taskMap = self['taskMap'];
var taskIdMap = self['taskIdMap'];
if (taskMap.containsKey(task)) {
var spec = taskMap[task];
log.add("run enter "
"zone: ${self['name']} "
"task-id: ${taskIdMap[spec]} "
"arg: $arg");
parent.runTask(zone, run, task, arg);
log.add("run leave");
return;
}
parent.runTask(zone, run, task, arg);
}
runZoned(() async {
var completer0 = new Completer();
Timer.run(() {
completer0.complete("done");
});
await completer0.future;
// No visible change (except for the zone name) in the log, compared to the
// simple invocations.
Expect.listEquals([
'create enter zone: outer-zone spec-duration: 0:00:00.000000 '
'spec-oneshot?: true',
'create leave',
'run enter zone: outer-zone task-id: 0 arg: null',
'run leave'
], log);
log.clear();
var completer1 = new Completer();
var counter1 = 0;
new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
if (counter1++ > 1) {
timer.cancel();
completer1.complete("done");
}
});
await completer1.future;
// No visible change (except for the zone nome) in the log, compared to the
// simple invocations.
Expect.listEquals([
'create enter zone: outer-zone spec-duration: 0:00:00.005000 '
'spec-oneshot?: false',
'create leave',
'run enter zone: outer-zone task-id: 1 arg: null',
'run leave',
'run enter zone: outer-zone task-id: 1 arg: null',
'run leave',
'run enter zone: outer-zone task-id: 1 arg: null',
'run leave'
], log);
log.clear();
var nestedCompleter = new Completer();
runZoned(() async {
var completer0 = new Completer();
Timer.run(() {
completer0.complete("done");
});
await completer0.future;
// The outer zone sees the duration change of the inner zone.
Expect.listEquals([
'create enter zone: inner-zone spec-duration: 0:00:00.000000 '
'spec-oneshot?: true',
'create enter zone: outer-zone spec-duration: 0:00:00.002000 '
'spec-oneshot?: true',
'create leave',
'create leave',
'run enter zone: inner-zone task-id: 3 arg: null',
'run enter zone: outer-zone task-id: 2 arg: null',
'run leave',
'run leave'
], log);
log.clear();
var completer1 = new Completer();
var counter1 = 0;
new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
if (counter1++ > 1) {
timer.cancel();
completer1.complete("done");
}
});
await completer1.future;
// The outer zone sees the duration change of the inner zone.
Expect.listEquals([
'create enter zone: inner-zone spec-duration: 0:00:00.005000 '
'spec-oneshot?: false',
'create enter zone: outer-zone spec-duration: 0:00:00.005000 '
'spec-oneshot?: false',
'create leave',
'create leave',
'run enter zone: inner-zone task-id: 5 arg: null',
'run enter zone: outer-zone task-id: 4 arg: null',
'run leave',
'run leave',
'run enter zone: inner-zone task-id: 5 arg: null',
'run enter zone: outer-zone task-id: 4 arg: null',
'run leave',
'run leave',
'run enter zone: inner-zone task-id: 5 arg: null',
'run enter zone: outer-zone task-id: 4 arg: null',
'run leave',
'run leave'
], log);
log.clear();
nestedCompleter.complete("done");
},
zoneValues: {'name': 'inner-zone', 'taskMap': {}, 'taskIdMap': {}},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
await nestedCompleter.future;
testCompleter.complete("done");
asyncEnd();
},
zoneValues: {'name': 'outer-zone', 'taskMap': {}, 'taskIdMap': {}},
zoneSpecification: new ZoneSpecification(
createTask: createTaskHandler,
runTask: runTaskHandler));
return testCompleter.future;
}
class TimerEntry {
final int time;
final SimulatedTimer timer;
TimerEntry(this.time, this.timer);
}
class SimulatedTimer implements Timer {
static int _idCounter = 0;
Zone _zone;
final int _id = _idCounter++;
final Duration _duration;
final Function _callback;
final bool _isPeriodic;
bool _isActive = true;
SimulatedTimer(this._zone, this._duration, this._callback, this._isPeriodic);
bool get isActive => _isActive;
void cancel() {
_isActive = false;
}
void _run() {
if (!isActive) return;
_zone.runTask(_runTimer, this, null);
}
static void _runTimer(SimulatedTimer timer, _) {
if (timer._isPeriodic) {
timer._callback(timer);
} else {
timer._callback();
}
}
}
testSimulatedTimer() {
List log = [];
var currentTime = 0;
// Using a simple list as queue. Not very efficient, but the test has only
// very few timers running at the same time.
var queue = new DoubleLinkedQueue<TimerEntry>();
// Schedules the given callback at now + duration.
void schedule(int scheduledTime, SimulatedTimer timer) {
log.add("scheduling timer ${timer._id} for $scheduledTime");
if (queue.isEmpty) {
queue.add(new TimerEntry(scheduledTime, timer));
} else {
DoubleLinkedQueueEntry current = queue.firstEntry();
while (current != null) {
if (current.element.time <= scheduledTime) {
current = current.nextEntry();
} else {
current.prepend(new TimerEntry(scheduledTime, timer));
break;
}
}
if (current == null) {
queue.add(new TimerEntry(scheduledTime, timer));
}
}
}
void runQueue() {
while (queue.isNotEmpty) {
var item = queue.removeFirst();
// If multiple callbacks were scheduled at the same time, increment the
// current time instead of staying at the same time.
currentTime = item.time > currentTime ? item.time : currentTime + 1;
SimulatedTimer timer = item.timer;
log.add("running timer ${timer._id} at $currentTime "
"(active?: ${timer.isActive})");
if (!timer.isActive) continue;
if (timer._isPeriodic) {
schedule(currentTime + timer._duration.inMilliseconds, timer);
}
item.timer._run();
}
}
SimulatedTimer createSimulatedOneShotTimer(
SingleShotTimerTaskSpecification spec, Zone zone) {
var timer = new SimulatedTimer(zone, spec.duration, spec.callback, false);
schedule(currentTime + spec.duration.inMilliseconds, timer);
return timer;
}
SimulatedTimer createSimulatedPeriodicTimer(
PeriodicTimerTaskSpecification spec, Zone zone) {
var timer = new SimulatedTimer(zone, spec.duration, spec.callback, true);
schedule(currentTime + spec.duration.inMilliseconds, timer);
return timer;
}
Object createSimulatedTaskHandler(Zone self, ZoneDelegate parent, Zone zone,
TaskCreate create, TaskSpecification specification) {
var taskMap = self['taskMap'];
var taskIdMap = self['taskIdMap'];
if (specification is SingleShotTimerTaskSpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-duration: ${specification.duration} "
"spec-oneshot?: ${specification.isOneShot}");
var result =
parent.createTask(zone, createSimulatedOneShotTimer, specification);
log.add("create leave");
return result;
}
if (specification is PeriodicTimerTaskSpecification) {
log.add("create enter "
"zone: ${self['name']} "
"spec-duration: ${specification.duration} "
"spec-oneshot?: ${specification.isOneShot}");
var result =
parent.createTask(zone, createSimulatedPeriodicTimer, specification);
log.add("create leave");
return result;
}
return parent.createTask(zone, create, specification);
}
runZoned(() {
Timer.run(() {
log.add("running Timer.run");
});
var timer0;
new Timer(const Duration(milliseconds: 10), () {
log.add("running Timer(10)");
timer0.cancel();
log.add("canceled timer0");
});
timer0 = new Timer(const Duration(milliseconds: 15), () {
log.add("running Timer(15)");
});
var counter1 = 0;
new Timer.periodic(const Duration(milliseconds: 5), (Timer timer) {
log.add("running periodic timer $counter1");
if (counter1++ > 1) {
timer.cancel();
}
});
},
zoneSpecification:
new ZoneSpecification(createTask: createSimulatedTaskHandler));
runQueue();
Expect.listEquals([
'create enter zone: null spec-duration: 0:00:00.000000 spec-oneshot?: true',
'scheduling timer 0 for 0',
'create leave',
'create enter zone: null spec-duration: 0:00:00.010000 spec-oneshot?: true',
'scheduling timer 1 for 10',
'create leave',
'create enter zone: null spec-duration: 0:00:00.015000 spec-oneshot?: true',
'scheduling timer 2 for 15',
'create leave',
'create enter zone: null spec-duration: 0:00:00.005000 '
'spec-oneshot?: false',
'scheduling timer 3 for 5',
'create leave',
'running timer 0 at 1 (active?: true)',
'running Timer.run',
'running timer 3 at 5 (active?: true)',
'scheduling timer 3 for 10',
'running periodic timer 0',
'running timer 1 at 10 (active?: true)',
'running Timer(10)',
'canceled timer0',
'running timer 3 at 11 (active?: true)',
'scheduling timer 3 for 16',
'running periodic timer 1',
'running timer 2 at 15 (active?: false)',
'running timer 3 at 16 (active?: true)',
'scheduling timer 3 for 21',
'running periodic timer 2',
'running timer 3 at 21 (active?: false)'
], log);
log.clear();
}
runTests() async {
await testTimerTask();
await testTimerTask2();
testSimulatedTimer();
}
main() {
asyncStart();
runTests().then((_) {
asyncEnd();
});
}

View file

@ -167,8 +167,6 @@ async/stream_asyncmap_test: RuntimeError # Timer interface not supported: Issue
async/stream_transformation_broadcast_test: RuntimeError # Timer interface not supported: Issue 7728.
async/stream_controller_test: Fail # Timer interface not supported: Issue 7728.
async/future_constructor2_test: Fail # Timer interface not supported: Issue 7728.
async/zone_timer_task_test: Fail # Timer interface not supported: Issue 7728.
async/zone_task_test: Fail # Timer interface not supported: Issue 7728.
mirrors/mirrors_reader_test: Skip # Running in v8 suffices. Issue 16589 - RuntimeError. Issue 22130 - Crash (out of memory).
[ $compiler == dart2js && $checked ]

View file

@ -4201,7 +4201,7 @@
" *",
" * Note: Most simple HTTP requests can be accomplished using the [getString],",
" * [request], [requestCrossOrigin], or [postFormData] methods. Use of this",
" * `open` method is intended only for more complex HTTP requests where",
" * `open` method is intended only for more complext HTTP requests where",
" * finer-grained control is needed.",
" */"
],
@ -4298,7 +4298,7 @@
" *",
" * Note: Most simple HTTP requests can be accomplished using the [getString],",
" * [request], [requestCrossOrigin], or [postFormData] methods. Use of this",
" * `send` method is intended only for more complex HTTP requests where",
" * `send` method is intended only for more complext HTTP requests where",
" * finer-grained control is needed.",
" *",
" * ## Other resources",

View file

@ -404,8 +404,6 @@ private_html_members = monitored.Set('htmlrenamer.private_html_members', [
'Window.requestAnimationFrame',
'Window.setInterval',
'Window.setTimeout',
'XMLHttpRequest.send',
])
# Members from the standard dom that exist in the dart:html library with

View file

@ -118,41 +118,6 @@ 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.
*/
@ -160,16 +125,8 @@ 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, String eventType, this._useCapture,
{String name, bool isOneShot: false})
: _eventType = eventType,
_isOneShot = isOneShot,
_name = name ?? "dart.html.event.$eventType";
_EventStream(this._target, this._eventType, this._useCapture);
// DOM events are inherently multi-subscribers.
Stream<T> asBroadcastStream({void onListen(StreamSubscription<T> subscription),
@ -177,31 +134,13 @@ 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 _listen(onData, useCapture: this._useCapture);
return new _EventStreamSubscription<T>(
this._target, this._eventType, onData, this._useCapture);
}
}
@ -216,9 +155,8 @@ bool _matchesWithAncestors(Event event, String selector) {
*/
class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
implements ElementStream<T> {
_ElementEventStreamImpl(target, eventType, useCapture,
{String name, bool isOneShot: false}) :
super(target, eventType, useCapture, name: name, isOneShot: isOneShot);
_ElementEventStreamImpl(target, eventType, useCapture) :
super(target, eventType, useCapture);
Stream<T> matches(String selector) => this.where(
(event) => _matchesWithAncestors(event, selector)).map((e) {
@ -226,9 +164,9 @@ class _ElementEventStreamImpl<T extends Event> extends _EventStream<T>
return e;
});
StreamSubscription<T> capture(void onData(T event)) {
return _listen(onData, useCapture: true);
}
StreamSubscription<T> capture(void onData(T event)) =>
new _EventStreamSubscription<T>(
this._target, this._eventType, onData, true);
}
/**
@ -277,13 +215,7 @@ class _ElementListEventStreamImpl<T extends Event> extends Stream<T>
bool get isBroadcast => true;
}
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
// We would like this to just be EventListener<T> but that typdef cannot
// use generics until dartbug/26276 is fixed.
typedef _EventListener<T extends Event>(T event);
@ -292,19 +224,15 @@ 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/*<dynamic, Event>*/((e) => onData(e as T))
// _onData = onData == null ? null : _wrapZone/*<Event, dynamic>*/((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, Zone zone)
: _zone = zone,
_onData = _registerZone/*<dynamic, Event>*/(zone, onData) {
this._useCapture) : _onData = _wrapZone/*<Event, dynamic>*/(onData) {
_tryResume();
}
@ -326,7 +254,7 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
// Remove current event listener.
_unlisten();
_onData = _registerZone/*<dynamic, Event>*/(_zone, handleData);
_onData = _wrapZone/*<Event, dynamic>*/(handleData);
_tryResume();
}
@ -355,25 +283,14 @@ class _EventStreamSubscription<T extends Event> extends StreamSubscription<T> {
}
void _tryResume() {
if (_onData == null || isPaused) return;
if (identical(_zone, Zone.ROOT)) {
_domCallback = _onData;
} else {
_domCallback = (event) {
_zone.runTask(_runEventNotification, this, event);
};
if (_onData != null && !isPaused) {
_target.addEventListener(_eventType, _onData, _useCapture);
}
_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, _domCallback, _useCapture);
_target.removeEventListener(_eventType, _onData, _useCapture);
}
}

View file

@ -4,26 +4,31 @@
part of dart.dom.html;
ZoneUnaryCallback/*<R, T>*/ _registerZone/*<R, T>*/(Zone zone,
ZoneUnaryCallback/*<R, T>*/ callback) {
// For performance reasons avoid registering if we are in the root zone.
if (identical(zone, Zone.ROOT)) return callback;
if (callback == null) return null;
return zone.registerUnaryCallback(callback);
}
// TODO(jacobr): remove these typedefs when dart:async supports generic types.
typedef R _wrapZoneCallback<A, R>(A a);
typedef R _wrapZoneBinaryCallback<A, B, R>(A a, B b);
ZoneUnaryCallback/*<R, T>*/ _wrapZone/*<R, T>*/(ZoneUnaryCallback/*<R, T>*/ callback) {
_wrapZoneCallback/*<A, R>*/ _wrapZone/*<A, R>*/(_wrapZoneCallback/*<A, R>*/ callback) {
// For performance reasons avoid wrapping if we are in the root zone.
if (identical(Zone.current, Zone.ROOT)) return callback;
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
return Zone.current.bindUnaryCallback(callback, runGuarded: true);
// TODO(jacobr): we cast to _wrapZoneCallback/*<A, R>*/ to hack around missing
// generic method support in zones.
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
_wrapZoneCallback/*<A, R>*/ wrapped =
Zone.current.bindUnaryCallback(callback, runGuarded: true);
return wrapped;
}
ZoneBinaryCallback/*<R, A, B>*/ _wrapBinaryZone/*<R, A, B>*/(
ZoneBinaryCallback/*<R, A, B>*/ callback) {
if (identical(Zone.current, Zone.ROOT)) return callback;
_wrapZoneBinaryCallback/*<A, B, R>*/ _wrapBinaryZone/*<A, B, R>*/(_wrapZoneBinaryCallback/*<A, B, R>*/ callback) {
if (Zone.current == Zone.ROOT) return callback;
if (callback == null) return null;
return Zone.current.bindBinaryCallback(callback, runGuarded: true);
// We cast to _wrapZoneBinaryCallback/*<A, B, R>*/ to hack around missing
// generic method support in zones.
// ignore: STRONG_MODE_DOWN_CAST_COMPOSITE
_wrapZoneBinaryCallback/*<A, B, R>*/ wrapped =
Zone.current.bindBinaryCallback(callback, runGuarded: true);
return wrapped;
}
/**

View file

@ -4,99 +4,6 @@
part of $LIBRARYNAME;
typedef void RemoveFrameRequestMapping(int id);
/**
* The task object representing animation-frame requests.
*
* For historical reasons, [Window.requestAnimationFrame] returns an integer
* to users. However, zone tasks must be unique objects, and an integer can
* therefore not be used as task object. The [Window] class thus keeps a mapping
* from the integer ID to the corresponding task object. All zone related
* operations work on this task object, whereas users of
* [Window.requestAnimationFrame] only see the integer ID.
*
* Since this mapping takes up space, it must be removed when the
* animation-frame task has triggered. The default implementation does this
* automatically, but intercepting implementations of `requestAnimationFrame`
* must make sure to call the [AnimationFrameTask.removeMapping]
* function that is provided in the task specification.
*
* *Experimental*. This class may disappear without notice.
*/
abstract class AnimationFrameTask {
/** The ID that is returned to users. */
int get id;
/** The zone in which the task will run. */
Zone get zone;
/**
* Cancels the animation-frame request.
*
* A call to [Window.cancelAnimationFrame] with an `id` argument equal to [id]
* forwards the request to this function.
*
* Zones that intercept animation-frame requests implement this method so
* that they can react to cancelation requests.
*/
void cancel(Window window);
/**
* Maps animation-frame request IDs to their task objects.
*/
static final Map<int, _AnimationFrameTask> _tasks = {};
/**
* Removes the mapping from [id] to [AnimationFrameTask].
*
* This function must be invoked by user-implemented animation-frame
* tasks, before running [callback].
*
* See [AnimationFrameTask].
*/
static void removeMapping(int id) {
_tasks.remove(id);
}
}
class _AnimationFrameTask implements AnimationFrameTask {
final int id;
final Zone zone;
final FrameRequestCallback _callback;
_AnimationFrameTask(this.id, this.zone, this._callback);
void cancel(Window window) {
window._cancelAnimationFrame(this.id);
}
}
/**
* The task specification for an animation-frame request.
*
* *Experimental*. This class may disappear without notice.
*/
class AnimationFrameRequestSpecification implements TaskSpecification {
/**
* The window on which [Window.requestAnimationFrame] was invoked.
*/
final Window window;
/**
* The callback that is executed when the animation-frame is ready.
*
* Note that the callback hasn't been registered in any zone when the `create`
* function (passed to [Zone.createTask]) is invoked.
*/
final FrameRequestCallback callback;
AnimationFrameRequestSpecification(this.window, this.callback);
String get name => "dart.html.request-animation-frame";
bool get isOneShot => true;
}
@DocsEditable()
$if DART2JS
$(ANNOTATIONS)@Native("Window,DOMWindow")
@ -122,7 +29,9 @@ $endif
*/
Future<num> get animationFrame {
var completer = new Completer<num>.sync();
requestAnimationFrame(completer.complete);
requestAnimationFrame((time) {
completer.complete(time);
});
return completer.future;
}
@ -206,30 +115,7 @@ $if DART2JS
@DomName('Window.requestAnimationFrame')
int requestAnimationFrame(FrameRequestCallback callback) {
_ensureRequestAnimationFrame();
if (identical(Zone.current, Zone.ROOT)) {
return _requestAnimationFrame(callback);
}
var spec = new AnimationFrameRequestSpecification(this, callback);
var task = Zone.current.createTask/*<AnimationFrameTask>*/(
_createAnimationFrameTask, spec);
AnimationFrameTask._tasks[task.id] = task;
return task.id;
}
static _AnimationFrameTask _createAnimationFrameTask(
AnimationFrameRequestSpecification spec, Zone zone) {
var task;
var id = spec.window._requestAnimationFrame((num time) {
AnimationFrameTask.removeMapping(task.id);
zone.runTask(_runAnimationFrame, task, time);
});
var callback = zone.registerUnaryCallback(spec.callback);
task = new _AnimationFrameTask(id, zone, callback);
return task;
}
static void _runAnimationFrame(_AnimationFrameTask task, num time) {
task._callback(time);
return _requestAnimationFrame(_wrapZone/*<num, dynamic>*/(callback));
}
/**
@ -242,13 +128,7 @@ $if DART2JS
*/
void cancelAnimationFrame(int id) {
_ensureRequestAnimationFrame();
var task = AnimationFrameTask._tasks.remove(id);
if (task == null) {
// Assume that the animation frame request wasn't intercepted by a zone.
_cancelAnimationFrame(id);
return;
}
task.cancel(this);
_cancelAnimationFrame(id);
}
@JSName('requestAnimationFrame')

View file

@ -4,109 +4,6 @@
part of $LIBRARYNAME;
/**
* A task specification for HTTP requests.
*
* This specification is not available when an HTTP request is sent through
* direct use of [HttpRequest.send]. See [HttpRequestSendTaskSpecification].
*
* A task created from this specification is a `Future<HttpRequest>`.
*
* *Experimental*. This class may disappear without notice.
*/
class HttpRequestTaskSpecification extends TaskSpecification {
/// The URL of the request.
final String url;
/// The HTTP request method.
///
/// By default (when `null`) this is a `"GET"` request. Alternatively, the
/// method can be `"POST"`, `"PUT"`, `"DELETE"`, etc.
final String method;
/// Whether the request should send credentials. Credentials are only useful
/// for cross-origin requests.
///
/// See [HttpRequest.request] for more information.
final bool withCredentials;
/// The desired response format.
///
/// Supported types are:
/// - `""`: (same as `"text"`),
/// - `"arraybuffer"`,
/// - `"blob"`,
/// - `"document"`,
/// - `"json"`,
/// - `"text"`
///
/// When no value is provided (when equal to `null`) defaults to `""`.
final String responseType;
/// The desired MIME type.
///
/// This overrides the default MIME type which is set up to transfer textual
/// data.
final String mimeType;
/// The request headers that should be sent with the request.
final Map<String, String> requestHeaders;
/// The data that is sent with the request.
///
/// When data is provided (the value is not `null`), it must be a
/// [ByteBuffer], [Blob], [Document], [String], or [FormData].
final dynamic sendData;
/// The function that is invoked on progress updates. This function is
/// registered as an event listener on the created [HttpRequest] object, and
/// thus has its own task. Further invocations of the progress function do
/// *not* use the HTTP request task as task object.
///
/// Creating an HTTP request automatically registers the on-progress listener.
final ZoneUnaryCallback<dynamic, ProgressEvent> onProgress;
HttpRequestTaskSpecification(this.url,
{String this.method, bool this.withCredentials, String this.responseType,
String this.mimeType, Map<String, String> this.requestHeaders,
this.sendData,
void this.onProgress(ProgressEvent e)});
String get name => "dart.html.http-request";
bool get isOneShot => true;
}
/**
* A task specification for HTTP requests that are initiated through a direct
* invocation of [HttpRequest.send].
*
* This specification serves as signal to zones that an HTTP request has been
* initiated. The created task is the [request] object itself, and
* no callback is ever executed in this task.
*
* Note that event listeners on the HTTP request are also registered in the
* zone (although with their own task creations), and that a zone can thus
* detect when the HTTP request returns.
*
* HTTP requests that are initiated through `request` methods don't use
* this class but use [HttpRequestTaskSpecification].
*
* *Experimental*. This class may disappear without notice.
*/
class HttpRequestSendTaskSpecification extends TaskSpecification {
final HttpRequest request;
final dynamic sendData;
HttpRequestSendTaskSpecification(this.request, this.sendData);
String get name => "dart.html.http-request-send";
/**
* No callback is ever executed in an HTTP request send task.
*/
bool get isOneShot => false;
}
/**
* A client-side XHR request for getting data from a URL,
* formally known as XMLHttpRequest.
@ -293,34 +190,7 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
{String method, bool withCredentials, String responseType,
String mimeType, Map<String, String> requestHeaders, sendData,
void onProgress(ProgressEvent e)}) {
var spec = new HttpRequestTaskSpecification(
url, method: method,
withCredentials: withCredentials,
responseType: responseType,
mimeType: mimeType,
requestHeaders: requestHeaders,
sendData: sendData,
onProgress: onProgress);
if (identical(Zone.current, Zone.ROOT)) {
return _createHttpRequestTask(spec, null);
}
return Zone.current.createTask(_createHttpRequestTask, spec);
}
static Future<HttpRequest> _createHttpRequestTask(
HttpRequestTaskSpecification spec, Zone zone) {
String url = spec.url;
String method = spec.method;
bool withCredentials = spec.withCredentials;
String responseType = spec.responseType;
String mimeType = spec.mimeType;
Map<String, String> requestHeaders = spec.requestHeaders;
var sendData = spec.sendData;
var onProgress = spec.onProgress;
var completer = new Completer<HttpRequest>();
var task = completer.future;
var xhr = new HttpRequest();
if (method == null) {
@ -360,42 +230,23 @@ $(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS
// redirect case will be handled by the browser before it gets to us,
// so if we see it we should pass it through to the user.
var unknownRedirect = xhr.status > 307 && xhr.status < 400;
var isSuccessful = accepted || fileUri || notModified || unknownRedirect;
if (zone == null && isSuccessful) {
if (accepted || fileUri || notModified || unknownRedirect) {
completer.complete(xhr);
} else if (zone == null) {
completer.completeError(e);
} else if (isSuccessful) {
zone.runTask((task, value) {
completer.complete(value);
}, task, xhr);
} else {
zone.runTask((task, error) {
completer.completeError(error);
}, task, e);
completer.completeError(e);
}
});
if (zone == null) {
xhr.onError.listen(completer.completeError);
} else {
xhr.onError.listen((error) {
zone.runTask((task, error) {
completer.completeError(error);
}, task, error);
});
}
xhr.onError.listen(completer.completeError);
if (sendData != null) {
// TODO(floitsch): should we go through 'send()' and have nested tasks?
xhr._send(sendData);
xhr.send(sendData);
} else {
xhr._send();
xhr.send();
}
return task;
return completer.future;
}
/**
@ -465,9 +316,6 @@ $endif
return xhr.responseText;
});
}
// TODO(floitsch): the following code doesn't go through task zones.
// Since 'XDomainRequest' is an IE9 feature we should probably just remove
// it.
$if DART2JS
var completer = new Completer<String>();
if (method == null) {
@ -548,7 +396,7 @@ $endif
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `open` method is intended only for more complex HTTP requests where
* `open` method is intended only for more complext HTTP requests where
* finer-grained control is needed.
*/
@DomName('XMLHttpRequest.open')
@ -565,35 +413,5 @@ $else
void open(String method, String url, {bool async, String user, String password}) native;
$endif
/**
* Sends the request with any given `data`.
*
* Note: Most simple HTTP requests can be accomplished using the [getString],
* [request], [requestCrossOrigin], or [postFormData] methods. Use of this
* `send` method is intended only for more complex HTTP requests where
* finer-grained control is needed.
*
* ## Other resources
*
* * [XMLHttpRequest.send](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#send%28%29)
* from MDN.
*/
@DomName('XMLHttpRequest.send')
@DocsEditable()
void send([body_OR_data]) {
if (identical(Zone.current, Zone.ROOT)) {
_send(body_OR_data);
} else {
Zone.current.createTask(_createHttpRequestSendTask,
new HttpRequestSendTaskSpecification(this, body_OR_data));
}
}
static HttpRequest _createHttpRequestSendTask(
HttpRequestSendTaskSpecification spec, Zone zone) {
spec.request._send(spec.sendData);
return spec.request;
}
$!MEMBERS
}