mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:31:21 +00:00
Revert "Reapply zone tasks."
This reverts commit f746f8f77e
.
Review URL: https://codereview.chromium.org/2123593002 .
This commit is contained in:
parent
f746f8f77e
commit
dae3922915
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
});
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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']
|
||||
]));
|
||||
}
|
||||
;
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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'
|
||||
]));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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 ]
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue