mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-22 17:24:48 -05:00
LibWeb: Add definitions for PointerEvent event handlers
Also removing a FIXME about not covering all of the event names as it is not exactly clear when such a FIXME would be addressed, especially as these come from multiple specifications.
This commit is contained in:
parent
4d38e04e48
commit
75b7a3e413
Notes:
github-actions[bot]
2024-11-22 13:34:51 +00:00
Author: https://github.com/shannonbooth Commit: https://github.com/LadybirdBrowser/ladybird/commit/75b7a3e413e Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2500
8 changed files with 806 additions and 27 deletions
|
@ -86,6 +86,19 @@ interface mixin GlobalEventHandlers {
|
|||
attribute EventHandler onwebkitanimationstart;
|
||||
attribute EventHandler onwebkittransitionend;
|
||||
attribute EventHandler onwheel;
|
||||
|
||||
// https://w3c.github.io/pointerevents/#extensions-to-the-globaleventhandlers-mixin
|
||||
attribute EventHandler onpointerover;
|
||||
attribute EventHandler onpointerenter;
|
||||
attribute EventHandler onpointerdown;
|
||||
attribute EventHandler onpointermove;
|
||||
[SecureContext] attribute EventHandler onpointerrawupdate;
|
||||
attribute EventHandler onpointerup;
|
||||
attribute EventHandler onpointercancel;
|
||||
attribute EventHandler onpointerout;
|
||||
attribute EventHandler onpointerleave;
|
||||
attribute EventHandler ongotpointercapture;
|
||||
attribute EventHandler onlostpointercapture;
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/#windoweventhandlers
|
||||
|
|
|
@ -159,6 +159,7 @@ namespace AttributeNames {
|
|||
__ENUMERATE_HTML_ATTRIBUTE(onfocusin) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onfocusout) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onformdata) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(ongotpointercapture) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onhashchange) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(oninput) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(oninvalid) \
|
||||
|
@ -170,6 +171,7 @@ namespace AttributeNames {
|
|||
__ENUMERATE_HTML_ATTRIBUTE(onloadeddata) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onloadedmetadata) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onloadstart) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onlostpointercapture) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onmessage) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onmessageerror) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onmousedown) \
|
||||
|
@ -186,6 +188,15 @@ namespace AttributeNames {
|
|||
__ENUMERATE_HTML_ATTRIBUTE(onpause) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onplay) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onplaying) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointercancel) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerdown) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerenter) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerleave) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointermove) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerout) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerover) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerrawupdate) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpointerup) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onpopstate) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onprogress) \
|
||||
__ENUMERATE_HTML_ATTRIBUTE(onratechange) \
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
E(onfocusin, HTML::EventNames::focusin) \
|
||||
E(onfocusout, HTML::EventNames::focusout) \
|
||||
E(onformdata, HTML::EventNames::formdata) \
|
||||
E(ongotpointercapture, UIEvents::EventNames::gotpointercapture) \
|
||||
E(oninput, HTML::EventNames::input) \
|
||||
E(oninvalid, HTML::EventNames::invalid) \
|
||||
E(onkeydown, UIEvents::EventNames::keydown) \
|
||||
|
@ -46,6 +47,7 @@
|
|||
E(onloadeddata, HTML::EventNames::loadeddata) \
|
||||
E(onloadedmetadata, HTML::EventNames::loadedmetadata) \
|
||||
E(onloadstart, HTML::EventNames::loadstart) \
|
||||
E(onlostpointercapture, UIEvents::EventNames::lostpointercapture) \
|
||||
E(onmousedown, UIEvents::EventNames::mousedown) \
|
||||
E(onmouseenter, UIEvents::EventNames::mouseenter) \
|
||||
E(onmouseleave, UIEvents::EventNames::mouseleave) \
|
||||
|
@ -56,6 +58,15 @@
|
|||
E(onpause, HTML::EventNames::pause) \
|
||||
E(onplay, HTML::EventNames::play) \
|
||||
E(onplaying, HTML::EventNames::playing) \
|
||||
E(onpointercancel, UIEvents::EventNames::pointercancel) \
|
||||
E(onpointerdown, UIEvents::EventNames::pointerdown) \
|
||||
E(onpointerenter, UIEvents::EventNames::pointerenter) \
|
||||
E(onpointerleave, UIEvents::EventNames::pointerleave) \
|
||||
E(onpointermove, UIEvents::EventNames::pointermove) \
|
||||
E(onpointerout, UIEvents::EventNames::pointerout) \
|
||||
E(onpointerover, UIEvents::EventNames::pointerover) \
|
||||
E(onpointerrawupdate, UIEvents::EventNames::pointerrawupdate) \
|
||||
E(onpointerup, UIEvents::EventNames::pointerup) \
|
||||
E(onprogress, HTML::EventNames::progress) \
|
||||
E(onratechange, HTML::EventNames::ratechange) \
|
||||
E(onreset, HTML::EventNames::reset) \
|
||||
|
|
|
@ -12,33 +12,35 @@
|
|||
|
||||
namespace Web::UIEvents::EventNames {
|
||||
|
||||
// FIXME: This is not all of the events
|
||||
|
||||
#define ENUMERATE_UI_EVENTS \
|
||||
__ENUMERATE_UI_EVENT(auxclick) \
|
||||
__ENUMERATE_UI_EVENT(beforeinput) \
|
||||
__ENUMERATE_UI_EVENT(click) \
|
||||
__ENUMERATE_UI_EVENT(contextmenu) \
|
||||
__ENUMERATE_UI_EVENT(dblclick) \
|
||||
__ENUMERATE_UI_EVENT(input) \
|
||||
__ENUMERATE_UI_EVENT(keydown) \
|
||||
__ENUMERATE_UI_EVENT(keypress) \
|
||||
__ENUMERATE_UI_EVENT(keyup) \
|
||||
__ENUMERATE_UI_EVENT(mousedown) \
|
||||
__ENUMERATE_UI_EVENT(mouseenter) \
|
||||
__ENUMERATE_UI_EVENT(mouseleave) \
|
||||
__ENUMERATE_UI_EVENT(mousemove) \
|
||||
__ENUMERATE_UI_EVENT(mouseout) \
|
||||
__ENUMERATE_UI_EVENT(mouseover) \
|
||||
__ENUMERATE_UI_EVENT(mouseup) \
|
||||
__ENUMERATE_UI_EVENT(pointerdown) \
|
||||
__ENUMERATE_UI_EVENT(pointerenter) \
|
||||
__ENUMERATE_UI_EVENT(pointerleave) \
|
||||
__ENUMERATE_UI_EVENT(pointermove) \
|
||||
__ENUMERATE_UI_EVENT(pointerout) \
|
||||
__ENUMERATE_UI_EVENT(pointerover) \
|
||||
__ENUMERATE_UI_EVENT(pointerup) \
|
||||
__ENUMERATE_UI_EVENT(resize) \
|
||||
#define ENUMERATE_UI_EVENTS \
|
||||
__ENUMERATE_UI_EVENT(auxclick) \
|
||||
__ENUMERATE_UI_EVENT(beforeinput) \
|
||||
__ENUMERATE_UI_EVENT(click) \
|
||||
__ENUMERATE_UI_EVENT(contextmenu) \
|
||||
__ENUMERATE_UI_EVENT(dblclick) \
|
||||
__ENUMERATE_UI_EVENT(gotpointercapture) \
|
||||
__ENUMERATE_UI_EVENT(input) \
|
||||
__ENUMERATE_UI_EVENT(keydown) \
|
||||
__ENUMERATE_UI_EVENT(keypress) \
|
||||
__ENUMERATE_UI_EVENT(keyup) \
|
||||
__ENUMERATE_UI_EVENT(lostpointercapture) \
|
||||
__ENUMERATE_UI_EVENT(mousedown) \
|
||||
__ENUMERATE_UI_EVENT(mouseenter) \
|
||||
__ENUMERATE_UI_EVENT(mouseleave) \
|
||||
__ENUMERATE_UI_EVENT(mousemove) \
|
||||
__ENUMERATE_UI_EVENT(mouseout) \
|
||||
__ENUMERATE_UI_EVENT(mouseover) \
|
||||
__ENUMERATE_UI_EVENT(mouseup) \
|
||||
__ENUMERATE_UI_EVENT(pointercancel) \
|
||||
__ENUMERATE_UI_EVENT(pointerdown) \
|
||||
__ENUMERATE_UI_EVENT(pointerenter) \
|
||||
__ENUMERATE_UI_EVENT(pointerleave) \
|
||||
__ENUMERATE_UI_EVENT(pointermove) \
|
||||
__ENUMERATE_UI_EVENT(pointerout) \
|
||||
__ENUMERATE_UI_EVENT(pointerover) \
|
||||
__ENUMERATE_UI_EVENT(pointerrawupdate) \
|
||||
__ENUMERATE_UI_EVENT(pointerup) \
|
||||
__ENUMERATE_UI_EVENT(resize) \
|
||||
__ENUMERATE_UI_EVENT(wheel)
|
||||
|
||||
#define __ENUMERATE_UI_EVENT(name) extern FlyString name;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
Summary
|
||||
|
||||
Harness status: OK
|
||||
|
||||
Rerun
|
||||
|
||||
Found 30 tests
|
||||
|
||||
30 Pass
|
||||
Details
|
||||
Result Test Name MessagePass The default value of onpointerdown is always null
|
||||
Pass The onpointerdown content attribute must be compiled into the onpointerdown property
|
||||
Pass dispatching a pointerdown event must trigger element.onpointerdown
|
||||
Pass The default value of onpointerup is always null
|
||||
Pass The onpointerup content attribute must be compiled into the onpointerup property
|
||||
Pass dispatching a pointerup event must trigger element.onpointerup
|
||||
Pass The default value of onpointercancel is always null
|
||||
Pass The onpointercancel content attribute must be compiled into the onpointercancel property
|
||||
Pass dispatching a pointercancel event must trigger element.onpointercancel
|
||||
Pass The default value of onpointermove is always null
|
||||
Pass The onpointermove content attribute must be compiled into the onpointermove property
|
||||
Pass dispatching a pointermove event must trigger element.onpointermove
|
||||
Pass The default value of onpointerover is always null
|
||||
Pass The onpointerover content attribute must be compiled into the onpointerover property
|
||||
Pass dispatching a pointerover event must trigger element.onpointerover
|
||||
Pass The default value of onpointerout is always null
|
||||
Pass The onpointerout content attribute must be compiled into the onpointerout property
|
||||
Pass dispatching a pointerout event must trigger element.onpointerout
|
||||
Pass The default value of onpointerenter is always null
|
||||
Pass The onpointerenter content attribute must be compiled into the onpointerenter property
|
||||
Pass dispatching a pointerenter event must trigger element.onpointerenter
|
||||
Pass The default value of onpointerleave is always null
|
||||
Pass The onpointerleave content attribute must be compiled into the onpointerleave property
|
||||
Pass dispatching a pointerleave event must trigger element.onpointerleave
|
||||
Pass The default value of ongotpointercapture is always null
|
||||
Pass The ongotpointercapture content attribute must be compiled into the ongotpointercapture property
|
||||
Pass dispatching a gotpointercapture event must trigger element.ongotpointercapture
|
||||
Pass The default value of onlostpointercapture is always null
|
||||
Pass The onlostpointercapture content attribute must be compiled into the onlostpointercapture property
|
||||
Pass dispatching a lostpointercapture event must trigger element.onlostpointercapture
|
|
@ -0,0 +1,67 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>PointerEvent: Constructor test</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
|
||||
<script src="../resources/testharness.js"></script>
|
||||
<script src="../resources/testharnessreport.js"></script>
|
||||
<!-- Additional helper script for common checks across event types -->
|
||||
<script type="text/javascript" src="pointerevent_support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>PointerEvent: Dispatch custom event</h1>
|
||||
<h4>Test Description: This test checks if on pointer event handlers through attributes works properly using synthetic pointerevents. For valid results, this test must be run without generating real (trusted) events on the black rectangle below.</h4>
|
||||
<div id="target0"
|
||||
onpointercancel="window.eventHappened = 'pointercancel';"
|
||||
onpointerdown="window.eventHappened = 'pointerdown';"
|
||||
onpointerup="window.eventHappened = 'pointerup';"
|
||||
onpointermove="window.eventHappened = 'pointermove';"
|
||||
onpointerout="window.eventHappened = 'pointerout';"
|
||||
onpointerover="window.eventHappened = 'pointerover';"
|
||||
onpointerleave="window.eventHappened = 'pointerleave';"
|
||||
onpointerenter="window.eventHappened = 'pointerenter';"
|
||||
ongotpointercapture="window.eventHappened = 'gotpointercapture';"
|
||||
onlostpointercapture="window.eventHappened = 'lostpointercapture';"
|
||||
></div>
|
||||
<script>
|
||||
window.eventHappened = '';
|
||||
|
||||
All_Pointer_Events.forEach(function(event) {
|
||||
var on_event = "on" + event;
|
||||
|
||||
test(function() {
|
||||
const htmlElement = document.createElement("span");
|
||||
const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||||
for (var location of [window, htmlElement, svgElement, document]) {
|
||||
assert_equals(location[on_event], null,
|
||||
`The default value of the property is null for a ${location.constructor.name} instance`);
|
||||
}
|
||||
}, "The default value of " + on_event + " is always null");
|
||||
|
||||
test(function() {
|
||||
window.eventHappened = '';
|
||||
const element = document.querySelector("#target0");
|
||||
const compiledHandler = element[on_event];
|
||||
assert_equals(typeof compiledHandler, "function", "The " + on_event + " property must be a function");
|
||||
compiledHandler();
|
||||
assert_equals(window.eventHappened, event, "Calling the handler must run the code");
|
||||
}, "The " + on_event + " content attribute must be compiled into the " + on_event + " property");
|
||||
|
||||
var handlerTest = async_test("dispatching a " + event + " event must trigger element." + on_event);
|
||||
const element = document.createElement("meta");
|
||||
element[on_event] = function(e) {
|
||||
handlerTest.step(function() {
|
||||
assert_equals(e.currentTarget, element, "The event must be fired at the <meta> element");
|
||||
});
|
||||
handlerTest.done();
|
||||
};
|
||||
element.dispatchEvent(new Event(event));
|
||||
});
|
||||
</script>
|
||||
<div id="complete-notice">
|
||||
<p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
|
||||
</div>
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,112 @@
|
|||
#innerFrame {
|
||||
position: absolute;
|
||||
top: 300px;
|
||||
left: 200px;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
#square1 {
|
||||
top: 330px;
|
||||
left: 150px;
|
||||
background: black;
|
||||
}
|
||||
|
||||
#square2 {
|
||||
top: 50px;
|
||||
left: 30px;
|
||||
visibility: hidden;
|
||||
background: red;
|
||||
}
|
||||
|
||||
.square {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#target0 {
|
||||
background: black;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#target1 {
|
||||
background: purple;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#scrollTarget {
|
||||
background: darkblue;
|
||||
}
|
||||
|
||||
.touchActionNone {
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
#innerframe {
|
||||
width: 90%;
|
||||
margin: 10px;
|
||||
margin-left: 10%;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
width: 700px;
|
||||
height: 430px;
|
||||
margin: 20px;
|
||||
overflow: auto;
|
||||
background: black;
|
||||
}
|
||||
|
||||
.scroller > div {
|
||||
height: 1000px;
|
||||
width: 1000px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.scroller > div div {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0em;
|
||||
padding: 1.2em;
|
||||
}
|
||||
|
||||
#complete-notice {
|
||||
background: #afa;
|
||||
border: 1px solid #0a0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#pointertype-log {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#event-log {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#listener {
|
||||
background: orange;
|
||||
border: 1px solid orange;
|
||||
position: absolute;
|
||||
top: -100px;
|
||||
}
|
||||
|
||||
body.scrollable {
|
||||
min-height: 5000px;
|
||||
}
|
|
@ -0,0 +1,523 @@
|
|||
const All_Pointer_Events = [
|
||||
"pointerdown",
|
||||
"pointerup",
|
||||
"pointercancel",
|
||||
"pointermove",
|
||||
"pointerover",
|
||||
"pointerout",
|
||||
"pointerenter",
|
||||
"pointerleave",
|
||||
"gotpointercapture",
|
||||
"lostpointercapture"
|
||||
];
|
||||
|
||||
// https://w3c.github.io/pointerevents/#the-button-property
|
||||
// Values for the button property, which indicates the device button whose state
|
||||
// change fired the event.
|
||||
const ButtonChange = {
|
||||
NONE: -1,
|
||||
PEN_CONTACT: 0,
|
||||
TOUCH_CONTACT: 0,
|
||||
LEFT_MOUSE: 0,
|
||||
MIDDLE_MOUSE: 1,
|
||||
RIGHT_MOUSE: 2,
|
||||
X1_MOUSE: 3,
|
||||
X2_MOUSE: 4,
|
||||
PEN_ERASER_BUTTON: 5
|
||||
};
|
||||
|
||||
// https://w3c.github.io/pointerevents/#the-buttons-property
|
||||
// The buttons property gives the current state of the device buttons as a
|
||||
// bitmask.
|
||||
const ButtonsBitfield = {
|
||||
NONE: 0,
|
||||
PEN_CONTACT: 1,
|
||||
TOUCH_CONTACT: 1,
|
||||
LEFT_MOUSE: 1,
|
||||
RIGHT_MOUSE: 2,
|
||||
PEN_BARREL_BUTTON: 2,
|
||||
MIDDLE_MOUSE: 4,
|
||||
X1_MOUSE: 8,
|
||||
X2_MOUSE: 16,
|
||||
PEN_ERASER_BUTTON: 32
|
||||
};
|
||||
|
||||
// Check for conformance to PointerEvent interface
|
||||
// https://w3c.github.io/pointerevents/#pointerevent-interface
|
||||
function check_PointerEvent(event, testNamePrefix, standardAttrs = true) {
|
||||
if (testNamePrefix === undefined)
|
||||
testNamePrefix = "";
|
||||
|
||||
// Use expectedPointerType if set otherwise just use the incoming event pointerType in the test name.
|
||||
var pointerTestName = (testNamePrefix ? testNamePrefix + ' ' : '')
|
||||
+ (expectedPointerType == null ? event.pointerType : expectedPointerType) + ' ' + event.type;
|
||||
|
||||
if (standardAttrs) {
|
||||
if (expectedPointerType != null) {
|
||||
test(function () {
|
||||
assert_equals(event.pointerType, expectedPointerType);
|
||||
}, pointerTestName + ".pointerType is correct.");
|
||||
}
|
||||
|
||||
test(function () {
|
||||
assert_true(event instanceof event.target.ownerDocument.defaultView.PointerEvent);
|
||||
}, pointerTestName + " event is a PointerEvent event");
|
||||
}
|
||||
|
||||
// Check attributes for conformance to WebIDL (existence, type, being readable).
|
||||
var idl_type_check = {
|
||||
"long": function (v) { return typeof v === "number" && Math.round(v) === v; },
|
||||
"float": function (v) { return typeof v === "number"; },
|
||||
"string": function (v) { return typeof v === "string"; },
|
||||
"boolean": function (v) { return typeof v === "boolean" },
|
||||
"object": function (v) { return typeof v === "object" }
|
||||
};
|
||||
|
||||
// Check values for inherited attributes.
|
||||
// https://w3c.github.io/pointerevents/#attributes-and-default-actions
|
||||
if (!standardAttrs) {
|
||||
test(function () {
|
||||
assert_implements_optional("fromElement" in event);
|
||||
assert_equals(event.fromElement, null);
|
||||
}, pointerTestName + ".fromElement value is null");
|
||||
test(function () {
|
||||
assert_implements_optional("toElement" in event);
|
||||
assert_equals(event.toElement, null);
|
||||
}, pointerTestName + ".toElement value is null");
|
||||
} else {
|
||||
test(function () {
|
||||
assert_equals(event.isTrusted, true);
|
||||
}, pointerTestName + ".isTrusted value is true");
|
||||
test(function () {
|
||||
let expected = (event.type != 'pointerenter' && event.type != 'pointerleave');
|
||||
assert_equals(event.composed, expected);
|
||||
}, pointerTestName + ".composed value is valid");
|
||||
test(function () {
|
||||
let expected = (event.type != 'pointerenter' && event.type != 'pointerleave');
|
||||
assert_equals(event.bubbles, expected);
|
||||
}, pointerTestName + ".bubbles value is valid");
|
||||
test(function () {
|
||||
let cancelable_events = [
|
||||
'pointerdown', 'pointermove', 'pointerup', 'pointerover', 'pointerout'
|
||||
];
|
||||
assert_equals(event.cancelable, cancelable_events.includes(event.type));
|
||||
}, pointerTestName + ".cancelable value is valid");
|
||||
|
||||
// Check the pressure value.
|
||||
// https://w3c.github.io/pointerevents/#dom-pointerevent-pressure
|
||||
test(function () {
|
||||
assert_greater_than_equal(event.pressure, 0, "pressure is greater than or equal to 0");
|
||||
assert_less_than_equal(event.pressure, 1, "pressure is less than or equal to 1");
|
||||
|
||||
if (event.buttons === 0) {
|
||||
assert_equals(event.pressure, 0, "pressure is 0 with no buttons pressed");
|
||||
} else {
|
||||
assert_greater_than(event.pressure, 0, "pressure is greater than 0 with a button pressed");
|
||||
if (event.pointerType === "mouse") {
|
||||
assert_equals(event.pressure, 0.5, "pressure is 0.5 for mouse with a button pressed");
|
||||
}
|
||||
}
|
||||
}, pointerTestName + ".pressure value is valid");
|
||||
|
||||
// Check mouse-specific properties.
|
||||
if (event.pointerType === "mouse") {
|
||||
test(function () {
|
||||
assert_equals(event.width, 1, "width of mouse should be 1");
|
||||
assert_equals(event.height, 1, "height of mouse should be 1");
|
||||
assert_equals(event.tiltX, 0, event.type + ".tiltX is 0 for mouse");
|
||||
assert_equals(event.tiltY, 0, event.type + ".tiltY is 0 for mouse");
|
||||
assert_true(event.isPrimary, event.type + ".isPrimary is true for mouse");
|
||||
}, pointerTestName + " properties for pointerType = mouse");
|
||||
}
|
||||
|
||||
// Check "pointerup" specific properties.
|
||||
if (event.type == "pointerup") {
|
||||
test(function () {
|
||||
assert_equals(event.width, 1, "width of pointerup should be 1");
|
||||
assert_equals(event.height, 1, "height of pointerup should be 1");
|
||||
}, pointerTestName + " properties for pointerup");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showPointerTypes() {
|
||||
var complete_notice = document.getElementById("complete-notice");
|
||||
var pointertype_log = document.getElementById("pointertype-log");
|
||||
var pointertypes = Object.keys(detected_pointertypes);
|
||||
pointertype_log.innerHTML = pointertypes.length ?
|
||||
pointertypes.join(",") : "(none)";
|
||||
complete_notice.style.display = "block";
|
||||
}
|
||||
|
||||
function showLoggedEvents() {
|
||||
var event_log_elem = document.getElementById("event-log");
|
||||
event_log_elem.innerHTML = event_log.length ? event_log.join(", ") : "(none)";
|
||||
|
||||
var complete_notice = document.getElementById("complete-notice");
|
||||
complete_notice.style.display = "block";
|
||||
}
|
||||
|
||||
function failOnScroll() {
|
||||
assert_true(false,
|
||||
"scroll received while shouldn't");
|
||||
}
|
||||
|
||||
function updateDescriptionNextStep() {
|
||||
document.getElementById('desc').innerHTML = "Test Description: Try to scroll text RIGHT.";
|
||||
}
|
||||
|
||||
function updateDescriptionComplete() {
|
||||
document.getElementById('desc').innerHTML = "Test Description: Test complete";
|
||||
}
|
||||
|
||||
function objectScroller(target, direction, value) {
|
||||
if (direction == 'up') {
|
||||
target.scrollTop = 0;
|
||||
} else if (direction == 'left') {
|
||||
target.scrollLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function sPointerCapture(e) {
|
||||
try {
|
||||
target0.setPointerCapture(e.pointerId);
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
}
|
||||
|
||||
function rPointerCapture(e) {
|
||||
try {
|
||||
captureButton.value = 'Set Capture';
|
||||
target0.releasePointerCapture(e.pointerId);
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
}
|
||||
|
||||
var globalPointerEventTest = null;
|
||||
var expectedPointerType = null;
|
||||
const ALL_POINTERS = ['mouse', 'touch', 'pen'];
|
||||
|
||||
function MultiPointerTypeTest(testName, types) {
|
||||
this.testName = testName;
|
||||
this.types = types;
|
||||
this.currentTypeIndex = 0;
|
||||
this.currentTest = null;
|
||||
this.createNextTest();
|
||||
}
|
||||
|
||||
MultiPointerTypeTest.prototype.step = function(op) {
|
||||
this.currentTest.step(op);
|
||||
}
|
||||
|
||||
MultiPointerTypeTest.prototype.skip = function() {
|
||||
var prevTest = this.currentTest;
|
||||
this.createNextTest();
|
||||
prevTest.timeout();
|
||||
}
|
||||
|
||||
MultiPointerTypeTest.prototype.done = function() {
|
||||
if (this.currentTest.status != 1) {
|
||||
var prevTest = this.currentTest;
|
||||
this.createNextTest();
|
||||
if (prevTest != null)
|
||||
prevTest.done();
|
||||
}
|
||||
}
|
||||
|
||||
MultiPointerTypeTest.prototype.step = function(stepFunction) {
|
||||
this.currentTest.step(stepFunction);
|
||||
}
|
||||
|
||||
MultiPointerTypeTest.prototype.createNextTest = function() {
|
||||
if (this.currentTypeIndex < this.types.length) {
|
||||
var pointerTypeDescription = document.getElementById('pointerTypeDescription');
|
||||
document.getElementById('pointerTypeDescription').innerHTML = "Follow the test instructions with <span style='color: red'>" + this.types[this.currentTypeIndex] + "</span>. If you don't have the device <a href='javascript:;' onclick='globalPointerEventTest.skip()'>skip it</a>.";
|
||||
this.currentTest = async_test(this.types[this.currentTypeIndex] + ' ' + this.testName);
|
||||
expectedPointerType = this.types[this.currentTypeIndex];
|
||||
this.currentTypeIndex++;
|
||||
} else {
|
||||
document.getElementById('pointerTypeDescription').innerHTML = "";
|
||||
}
|
||||
resetTestState();
|
||||
}
|
||||
|
||||
function setup_pointerevent_test(testName, supportedPointerTypes) {
|
||||
return globalPointerEventTest = new MultiPointerTypeTest(testName, supportedPointerTypes);
|
||||
}
|
||||
|
||||
function checkPointerEventType(event) {
|
||||
assert_equals(event.pointerType, expectedPointerType, "pointerType should be the same as the requested device.");
|
||||
}
|
||||
|
||||
function touchScrollInTarget(target, direction) {
|
||||
var x_delta = 0;
|
||||
var y_delta = 0;
|
||||
if (direction == "down") {
|
||||
x_delta = 0;
|
||||
y_delta = -10;
|
||||
} else if (direction == "up") {
|
||||
x_delta = 0;
|
||||
y_delta = 10;
|
||||
} else if (direction == "right") {
|
||||
x_delta = -10;
|
||||
y_delta = 0;
|
||||
} else if (direction == "left") {
|
||||
x_delta = 10;
|
||||
y_delta = 0;
|
||||
} else {
|
||||
throw("scroll direction '" + direction + "' is not expected, direction should be 'down', 'up', 'left' or 'right'");
|
||||
}
|
||||
return new test_driver.Actions()
|
||||
.addPointer("touchPointer1", "touch")
|
||||
.pointerMove(0, 0, {origin: target})
|
||||
.pointerDown()
|
||||
.pointerMove(x_delta, y_delta, {origin: target})
|
||||
.pointerMove(2 * x_delta, 2 * y_delta, {origin: target})
|
||||
.pointerMove(3 * x_delta, 3 * y_delta, {origin: target})
|
||||
.pointerMove(4 * x_delta, 4 * y_delta, {origin: target})
|
||||
.pointerMove(5 * x_delta, 5 * y_delta, {origin: target})
|
||||
.pointerMove(6 * x_delta, 6 * y_delta, {origin: target})
|
||||
.pause(100)
|
||||
.pointerUp()
|
||||
.send();
|
||||
}
|
||||
|
||||
function clickInTarget(pointerType, target) {
|
||||
var pointerId = pointerType + "Pointer1";
|
||||
return new test_driver.Actions()
|
||||
.addPointer(pointerId, pointerType)
|
||||
.pointerMove(0, 0, {origin: target})
|
||||
.pointerDown()
|
||||
.pointerUp()
|
||||
.send();
|
||||
}
|
||||
|
||||
function rightClickInTarget(pointerType, target) {
|
||||
let pointerId = pointerType + "Pointer1";
|
||||
let actions = new test_driver.Actions();
|
||||
return actions.addPointer(pointerId, pointerType)
|
||||
.pointerMove(0, 0, {origin: target})
|
||||
.pointerDown({button:actions.ButtonType.RIGHT})
|
||||
.pointerUp({button:actions.ButtonType.RIGHT})
|
||||
.send();
|
||||
}
|
||||
|
||||
function twoFingerDrag(target) {
|
||||
return new test_driver.Actions()
|
||||
.addPointer("touchPointer1", "touch")
|
||||
.addPointer("touchPointer2", "touch")
|
||||
.pointerMove(0, 0, { origin: target, sourceName: "touchPointer1" })
|
||||
.pointerMove(10, 0, { origin: target, sourceName: "touchPointer2" })
|
||||
.pointerDown({ sourceName: "touchPointer1" })
|
||||
.pointerDown({ sourceName: "touchPointer2" })
|
||||
.pointerMove(0, 10, { origin: target, sourceName: "touchPointer1" })
|
||||
.pointerMove(10, 10, { origin: target, sourceName: "touchPointer2" })
|
||||
.pointerMove(0, 20, { origin: target, sourceName: "touchPointer1" })
|
||||
.pointerMove(10, 20, { origin: target, sourceName: "touchPointer2" })
|
||||
.pause(100)
|
||||
.pointerUp({ sourceName: "touchPointer1" })
|
||||
.pointerUp({ sourceName: "touchPointer2" })
|
||||
.send();
|
||||
}
|
||||
|
||||
function pointerDragInTarget(pointerType, target, direction) {
|
||||
var x_delta = 0;
|
||||
var y_delta = 0;
|
||||
if (direction == "down") {
|
||||
x_delta = 0;
|
||||
y_delta = 10;
|
||||
} else if (direction == "up") {
|
||||
x_delta = 0;
|
||||
y_delta = -10;
|
||||
} else if (direction == "right") {
|
||||
x_delta = 10;
|
||||
y_delta = 0;
|
||||
} else if (direction == "left") {
|
||||
x_delta = -10;
|
||||
y_delta = 0;
|
||||
} else {
|
||||
throw("drag direction '" + direction + "' is not expected, direction should be 'down', 'up', 'left' or 'right'");
|
||||
}
|
||||
var pointerId = pointerType + "Pointer1";
|
||||
return new test_driver.Actions()
|
||||
.addPointer(pointerId, pointerType)
|
||||
.pointerMove(0, 0, {origin: target})
|
||||
.pointerDown()
|
||||
.pointerMove(x_delta, y_delta, {origin: target})
|
||||
.pointerMove(2 * x_delta, 2 * y_delta, {origin: target})
|
||||
.pointerMove(3 * x_delta, 3 * y_delta, {origin: target})
|
||||
.pointerUp()
|
||||
.send();
|
||||
}
|
||||
|
||||
function pointerHoverInTarget(pointerType, target, direction) {
|
||||
var x_delta = 0;
|
||||
var y_delta = 0;
|
||||
if (direction == "down") {
|
||||
x_delta = 0;
|
||||
y_delta = 10;
|
||||
} else if (direction == "up") {
|
||||
x_delta = 0;
|
||||
y_delta = -10;
|
||||
} else if (direction == "right") {
|
||||
x_delta = 10;
|
||||
y_delta = 0;
|
||||
} else if (direction == "left") {
|
||||
x_delta = -10;
|
||||
y_delta = 0;
|
||||
} else {
|
||||
throw("drag direction '" + direction + "' is not expected, direction should be 'down', 'up', 'left' or 'right'");
|
||||
}
|
||||
var pointerId = pointerType + "Pointer1";
|
||||
return new test_driver.Actions()
|
||||
.addPointer(pointerId, pointerType)
|
||||
.pointerMove(0, 0, {origin: target})
|
||||
.pointerMove(x_delta, y_delta, {origin: target})
|
||||
.pointerMove(2 * x_delta, 2 * y_delta, {origin: target})
|
||||
.pointerMove(3 * x_delta, 3 * y_delta, {origin: target})
|
||||
.send();
|
||||
}
|
||||
|
||||
function moveToDocument(pointerType) {
|
||||
var pointerId = pointerType + "Pointer1";
|
||||
return new test_driver.Actions()
|
||||
.addPointer(pointerId, pointerType)
|
||||
// WebDriver initializes the pointer position (0, 0), therefore, we need
|
||||
// to move different position first. Otherwise, moving to (0, 0) may be
|
||||
// ignored.
|
||||
.pointerMove(1, 1)
|
||||
.pointerMove(0, 0)
|
||||
.send();
|
||||
}
|
||||
|
||||
// Returns a promise that only gets resolved when the condition is met.
|
||||
function resolveWhen(condition) {
|
||||
return new Promise((resolve, reject) => {
|
||||
function tick() {
|
||||
if (condition())
|
||||
resolve();
|
||||
else
|
||||
requestAnimationFrame(tick.bind(this));
|
||||
}
|
||||
tick();
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a promise that only gets resolved after n animation frames
|
||||
function waitForAnimationFrames(n) {
|
||||
let p = 0;
|
||||
function next() {
|
||||
p++;
|
||||
return p === n;
|
||||
}
|
||||
return resolveWhen(next);
|
||||
}
|
||||
|
||||
function isPointerEvent(eventName) {
|
||||
return All_Pointer_Events.includes(eventName);
|
||||
}
|
||||
|
||||
function isMouseEvent(eventName) {
|
||||
return ["mousedown", "mouseup", "mousemove", "mouseover",
|
||||
"mouseenter", "mouseout", "mouseleave",
|
||||
"click", "contextmenu", "dblclick"
|
||||
].includes(eventName);
|
||||
}
|
||||
|
||||
// Events is a list of events fired at a target.
|
||||
//
|
||||
// Checks to see if each pointer event has a corresponding mouse event in the
|
||||
// event array and the two events are in the proper order (pointer event is
|
||||
// first).
|
||||
//
|
||||
// See https://w3c.github.io/pointerevents/#mapping-for-devices-that-support-hover
|
||||
function arePointerEventsBeforeCompatMouseEvents(events) {
|
||||
function arePointerAndMouseEventCompatible(pointerEventName, mouseEventName) {
|
||||
return pointerEventName.startsWith("pointer")
|
||||
&& mouseEventName.startsWith("mouse")
|
||||
&& pointerEventName.substring(7) === mouseEventName.substring(5);
|
||||
}
|
||||
|
||||
function arePointerAndMouseEventInProperOrder(pointerEventIndex, mouseEventIndex, events) {
|
||||
return (pointerEventIndex < mouseEventIndex && isPointerEvent(events[pointerEventIndex]) && isMouseEvent(events[mouseEventIndex])
|
||||
&& arePointerAndMouseEventCompatible(events[pointerEventIndex], events[mouseEventIndex]));
|
||||
}
|
||||
|
||||
let currentPointerEventIndex = events.findIndex((event) => isPointerEvent(event));
|
||||
let currentMouseEventIndex = events.findIndex((event) => isMouseEvent(event));
|
||||
|
||||
while (1) {
|
||||
if (currentMouseEventIndex < 0 && currentPointerEventIndex < 0)
|
||||
return true;
|
||||
if (currentMouseEventIndex < 0 || currentPointerEventIndex < 0)
|
||||
return false;
|
||||
if (!arePointerAndMouseEventInProperOrder(currentPointerEventIndex, currentMouseEventIndex, events))
|
||||
return false;
|
||||
|
||||
let pointerIdx = events.slice(currentPointerEventIndex + 1).findIndex(isPointerEvent);
|
||||
let mouseIdx = events.slice(currentMouseEventIndex + 1).findIndex(isMouseEvent);
|
||||
|
||||
currentPointerEventIndex = (pointerIdx < 0) ? pointerIdx : (currentPointerEventIndex + 1 + pointerIdx);
|
||||
currentMouseEventIndex = (mouseIdx < 0) ? mouseIdx : (currentMouseEventIndex + 1 + mouseIdx);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns a |Promise| that gets resolved with the event object when |target|
|
||||
// receives an event of type |event_type|.
|
||||
//
|
||||
// The optional |test| parameter adds event handler cleanup for the case |test|
|
||||
// terminates before the event is received.
|
||||
function getEvent(event_type, target, test) {
|
||||
return new Promise(resolve => {
|
||||
const listener = e => resolve(e);
|
||||
target.addEventListener(event_type, listener, { once: true });
|
||||
if (test) {
|
||||
test.add_cleanup(() =>
|
||||
target.removeEventListener(event_type, listener, { once: true }));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a |Promise| that gets resolved with |event.data| when |window|
|
||||
// receives from |source| a "message" event whose |event.data.type| matches the
|
||||
// string |message_data_type|.
|
||||
//
|
||||
// The optional |test| parameter adds event handler cleanup for the case |test|
|
||||
// terminates before a matching event is received.
|
||||
function getMessageData(message_data_type, source, test) {
|
||||
return new Promise(resolve => {
|
||||
const listener = e => {
|
||||
if (e.source != source || !e.data || e.data.type != message_data_type)
|
||||
return;
|
||||
window.removeEventListener("message", listener);
|
||||
resolve(e.data);
|
||||
}
|
||||
|
||||
window.addEventListener("message", listener);
|
||||
if (test) {
|
||||
test.add_cleanup(() =>
|
||||
window.removeEventListener("message", listener));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// The optional |test| parameter adds event handler cleanup for the case |test|
|
||||
// terminates before the event is received.
|
||||
function preventDefaultPointerdownOnce(target, test) {
|
||||
return new Promise((resolve) => {
|
||||
const listener = e => {
|
||||
e.preventDefault();
|
||||
resolve();
|
||||
}
|
||||
|
||||
target.addEventListener("pointerdown", listener, { once: true });
|
||||
if (test) {
|
||||
test.add_cleanup(() =>
|
||||
target.removeEventListener("pointerdown", listener, { once: true }));
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue