745f112ef6
Opt an initial batch of files under samples, samples-dev, utils, and runtime/tools/dartfuzz out of null safety in preparation for switching the flag on by default. Change-Id: Icdfd52a5a969e678a7205903332f73fe3841c223 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166960 Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Leaf Petersen <leafp@google.com>
399 lines
9.1 KiB
Dart
399 lines
9.1 KiB
Dart
// Copyright (c) 2011, 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.
|
|
|
|
// @dart = 2.9
|
|
|
|
part of touch;
|
|
|
|
/**
|
|
* Wraps a callback with translations of mouse events to touch events. Use
|
|
* this function to invoke your callback that expects touch events after
|
|
* touch events are created from the actual mouse events.
|
|
*/
|
|
EventListener mouseToTouchCallback(EventListener callback) {
|
|
return (Event e) {
|
|
var touches = <Touch>[];
|
|
var targetTouches = <Touch>[];
|
|
var changedTouches = <Touch>[];
|
|
final mockTouch = new MockTouch(e);
|
|
final mockTouchList = <Touch>[mockTouch];
|
|
if (e.type == 'mouseup') {
|
|
changedTouches = mockTouchList;
|
|
} else {
|
|
touches = mockTouchList;
|
|
targetTouches = mockTouchList;
|
|
}
|
|
callback(new MockTouchEvent(e, touches, targetTouches, changedTouches));
|
|
// Required to prevent spurious selection changes while tracking touches
|
|
// on devices that don't support touch events.
|
|
e.preventDefault();
|
|
};
|
|
}
|
|
|
|
/** Helper method to attach event listeners to a [node]. */
|
|
void _addEventListeners(Element node, EventListener onStart,
|
|
EventListener onMove, EventListener onEnd, EventListener onCancel,
|
|
[bool capture = false]) {
|
|
Function removeListeners;
|
|
|
|
onEndWrapper(e) {
|
|
removeListeners();
|
|
return onEnd(e);
|
|
}
|
|
|
|
onLeaveWrapper(e) {
|
|
removeListeners();
|
|
return onEnd(e);
|
|
}
|
|
|
|
onCancelWrapper(e) {
|
|
removeListeners();
|
|
return onCancel(e);
|
|
}
|
|
|
|
if (Device.supportsTouch) {
|
|
var touchMoveSub;
|
|
var touchEndSub;
|
|
var touchLeaveSub;
|
|
var touchCancelSub;
|
|
|
|
removeListeners = () {
|
|
touchMoveSub.cancel();
|
|
touchEndSub.cancel();
|
|
touchLeaveSub.cancel();
|
|
touchCancelSub.cancel();
|
|
};
|
|
|
|
Element.touchStartEvent.forTarget(node, useCapture: capture).listen((e) {
|
|
touchMoveSub = Element.touchMoveEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onMove);
|
|
touchEndSub = Element.touchEndEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onEndWrapper);
|
|
touchLeaveSub = Element.touchLeaveEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onLeaveWrapper);
|
|
touchCancelSub = Element.touchCancelEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onCancelWrapper);
|
|
return onStart(e);
|
|
});
|
|
} else {
|
|
onStart = mouseToTouchCallback(onStart);
|
|
onMove = mouseToTouchCallback(onMove);
|
|
onEnd = mouseToTouchCallback(onEnd);
|
|
// onLeave will never be called if the device does not support touches.
|
|
|
|
var mouseMoveSub;
|
|
var mouseUpSub;
|
|
var touchCancelSub;
|
|
|
|
removeListeners = () {
|
|
mouseMoveSub.cancel();
|
|
mouseUpSub.cancel();
|
|
touchCancelSub.cancel();
|
|
};
|
|
|
|
Element.mouseDownEvent.forTarget(node, useCapture: capture).listen((e) {
|
|
mouseMoveSub = Element.mouseMoveEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onMove);
|
|
mouseUpSub = Element.mouseUpEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onEndWrapper);
|
|
touchCancelSub = Element.touchCancelEvent
|
|
.forTarget(document, useCapture: capture)
|
|
.listen(onCancelWrapper);
|
|
return onStart(e);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets whether the given touch event targets the node, or one of the node's
|
|
* children.
|
|
*/
|
|
bool _touchEventTargetsNode(event, Node node) {
|
|
Node target = event.changedTouches[0].target;
|
|
|
|
// TODO(rnystrom): Move this into Dom.
|
|
// Walk up the parents looking for the node.
|
|
while (target != null) {
|
|
if (target == node) {
|
|
return true;
|
|
}
|
|
target = target.parent;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
abstract class Touchable {
|
|
/**
|
|
* Provide the HTML element that should respond to touch events.
|
|
*/
|
|
Element getElement();
|
|
|
|
/**
|
|
* The object has received a touchend event.
|
|
*/
|
|
void onTouchEnd();
|
|
|
|
/**
|
|
* The object has received a touchstart event.
|
|
* Returns return true if you want to allow a drag sequence to begin,
|
|
* false you want to disable dragging for the duration of this touch.
|
|
*/
|
|
bool onTouchStart(TouchEvent e);
|
|
}
|
|
|
|
abstract class Draggable implements Touchable {
|
|
/**
|
|
* The object's drag sequence is now complete.
|
|
*/
|
|
void onDragEnd();
|
|
|
|
/**
|
|
* The object has been dragged to a new position.
|
|
*/
|
|
void onDragMove();
|
|
|
|
/**
|
|
* The object has started dragging.
|
|
* Returns true to allow a drag sequence to begin (custom behavior),
|
|
* false to disable dragging for this touch duration (allow native scrolling).
|
|
*/
|
|
bool onDragStart(TouchEvent e);
|
|
|
|
bool get verticalEnabled;
|
|
bool get horizontalEnabled;
|
|
}
|
|
|
|
class MockTouch implements Touch {
|
|
MouseEvent wrapped;
|
|
|
|
MockTouch(MouseEvent this.wrapped) {}
|
|
|
|
int get clientX => wrapped.client.x;
|
|
|
|
int get clientY => wrapped.client.y;
|
|
|
|
get client => wrapped.client;
|
|
|
|
int get identifier => 0;
|
|
|
|
int get pageX => wrapped.page.x;
|
|
|
|
int get pageY => wrapped.page.y;
|
|
|
|
int get screenX => wrapped.screen.x;
|
|
|
|
int get screenY {
|
|
return wrapped.screen.y;
|
|
}
|
|
|
|
EventTarget get target => wrapped.target;
|
|
|
|
double get force {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
Point get page {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
int get radiusX {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
int get radiusY {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
String get region {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
num get rotationAngle {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
Point get screen {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
num get webkitForce {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
int get webkitRadiusX {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
int get webkitRadiusY {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
num get webkitRotationAngle {
|
|
throw new UnimplementedError();
|
|
}
|
|
}
|
|
|
|
class MockTouchList extends Object
|
|
with ListMixin<Touch>, ImmutableListMixin<Touch>
|
|
implements TouchList {
|
|
final List<Touch> values;
|
|
|
|
MockTouchList(this.values);
|
|
|
|
static bool get supported => true;
|
|
|
|
int get length => values.length;
|
|
|
|
Touch operator [](int index) => values[index];
|
|
|
|
void operator []=(int index, Touch value) {
|
|
throw new UnsupportedError("Cannot assign element of immutable List.");
|
|
}
|
|
|
|
set length(int value) {
|
|
throw new UnsupportedError("Cannot resize immutable List.");
|
|
}
|
|
|
|
Touch item(int index) => values[index];
|
|
}
|
|
|
|
class MockTouchEvent implements TouchEvent {
|
|
dynamic /*MouseEvent*/ wrapped;
|
|
final TouchList touches;
|
|
final TouchList targetTouches;
|
|
final TouchList changedTouches;
|
|
MockTouchEvent(MouseEvent this.wrapped, List<Touch> touches,
|
|
List<Touch> targetTouches, List<Touch> changedTouches)
|
|
: touches = new MockTouchList(touches),
|
|
targetTouches = new MockTouchList(targetTouches),
|
|
changedTouches = new MockTouchList(changedTouches);
|
|
|
|
bool get bubbles => wrapped.bubbles;
|
|
|
|
bool get cancelBubble => wrapped.cancelBubble;
|
|
|
|
void set cancelBubble(bool value) {
|
|
wrapped.cancelBubble = value;
|
|
}
|
|
|
|
bool get cancelable => wrapped.cancelable;
|
|
|
|
EventTarget get currentTarget => wrapped.currentTarget;
|
|
|
|
bool get defaultPrevented => wrapped.defaultPrevented;
|
|
|
|
int get eventPhase => wrapped.eventPhase;
|
|
|
|
void set returnValue(bool value) {
|
|
wrapped.returnValue = value;
|
|
}
|
|
|
|
bool get returnValue => wrapped.returnValue;
|
|
|
|
EventTarget get target => wrapped.target;
|
|
|
|
/*At different times, int, double, and String*/
|
|
get timeStamp => wrapped.timeStamp;
|
|
|
|
String get type => wrapped.type;
|
|
|
|
void preventDefault() {
|
|
wrapped.preventDefault();
|
|
}
|
|
|
|
void stopImmediatePropagation() {
|
|
wrapped.stopImmediatePropagation();
|
|
}
|
|
|
|
void stopPropagation() {
|
|
wrapped.stopPropagation();
|
|
}
|
|
|
|
int get charCode => wrapped.charCode;
|
|
|
|
int get detail => wrapped.detail;
|
|
|
|
// TODO(sra): keyCode is not on MouseEvent.
|
|
//int get keyCode => (wrapped as KeyboardEvent).keyCode;
|
|
|
|
int get layerX => wrapped.layer.x;
|
|
|
|
int get layerY => wrapped.layer.y;
|
|
|
|
int get pageX => wrapped.page.x;
|
|
|
|
int get pageY => wrapped.page.y;
|
|
|
|
Window get view => wrapped.view;
|
|
|
|
int get which => wrapped.which;
|
|
|
|
bool get altKey => wrapped.altKey;
|
|
|
|
bool get ctrlKey => wrapped.ctrlKey;
|
|
|
|
bool get metaKey => wrapped.metaKey;
|
|
|
|
bool get shiftKey => wrapped.shiftKey;
|
|
|
|
DataTransfer get clipboardData {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
List<EventTarget> deepPath() {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
bool get isTrusted {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
Point get layer {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
Element get matchingTarget {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
Point get page {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
List<EventTarget> get path {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
bool get scoped {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
Point get screen {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
/*InputDeviceCapabilities*/ get sourceCapabilities {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
/*InputDevice*/ get sourceDevice {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
bool get composed {
|
|
throw new UnimplementedError();
|
|
}
|
|
|
|
List<EventTarget> composedPath() {
|
|
throw new UnimplementedError();
|
|
}
|
|
}
|