mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
67 lines
3.3 KiB
HTML
67 lines
3.3 KiB
HTML
<!doctype html>
|
|
<meta charset="utf-8">
|
|
<title>22 touch events</title>
|
|
<link rel="stylesheet" href="../_style.css">
|
|
<script src="../_lib.js"></script>
|
|
<body>
|
|
<main>
|
|
<p>Goal: tap the green pad on a touch-capable device (or via DevTools touch
|
|
emulation). Page asserts a real <code>touchstart</code>/<code>touchend</code> sequence:
|
|
<code>touches</code> / <code>changedTouches</code> are
|
|
<code>TouchList</code> objects containing <code>Touch</code> instances with
|
|
<code>identifier</code>, <code>clientX/Y</code>, <code>radiusX/Y</code>, and
|
|
<code>force</code> in [0,1]. Synthetic <code>PointerEvent</code> with
|
|
<code>pointerType="touch"</code> alone does not satisfy this — touch events must
|
|
fire too.</p>
|
|
<p><b>Note for caller:</b> requires Chrome touch emulation on (DevTools → Sensors →
|
|
"Touch: Force enabled") or a real touchscreen. This is intentional: pi-chrome's
|
|
synthetic <code>pointerType:'touch'</code> does NOT also dispatch TouchEvents.</p>
|
|
<div id="pad" style="width:200px;height:200px;background:#1f7a1f;border-radius:12px;color:#fff;display:flex;align-items:center;justify-content:center;font:18px monospace;touch-action:none;user-select:none">
|
|
TAP
|
|
</div>
|
|
</main>
|
|
<script>
|
|
Challenge.init({ id: "touch-events", instructions: "tap the pad on a touch-capable device" });
|
|
const pad = document.getElementById("pad");
|
|
|
|
let touchStart = null, touchEnd = null;
|
|
pad.addEventListener("touchstart", (e) => {
|
|
touchStart = e;
|
|
Challenge.log("touchstart", { tl: e.touches.length, ct: e.changedTouches.length, isTrusted: e.isTrusted });
|
|
}, { passive: true });
|
|
pad.addEventListener("touchend", (e) => {
|
|
touchEnd = e;
|
|
const bad = [];
|
|
if (!touchStart) return Challenge.fail("touchend without touchstart");
|
|
if (!e.isTrusted || !touchStart.isTrusted) bad.push("touch event isTrusted=false");
|
|
|
|
const ts = touchStart.changedTouches;
|
|
if (!ts || ts.length === 0) bad.push("touchstart.changedTouches empty");
|
|
else {
|
|
const T = ts[0];
|
|
// Window.Touch should exist as the constructor.
|
|
if (typeof window.Touch !== "function") bad.push("window.Touch constructor missing (no native TouchEvent support)");
|
|
if (!(T instanceof Touch)) bad.push("changedTouches[0] not instanceof Touch");
|
|
if (typeof T.identifier !== "number") bad.push("Touch.identifier not number");
|
|
if (!Number.isFinite(T.clientX) || !Number.isFinite(T.clientY)) bad.push("Touch.clientX/Y invalid");
|
|
if (!("force" in T) || typeof T.force !== "number" || T.force < 0 || T.force > 1) bad.push(`Touch.force=${T.force}`);
|
|
if (!("radiusX" in T) || typeof T.radiusX !== "number") bad.push("Touch.radiusX missing");
|
|
}
|
|
|
|
if (!(touchStart instanceof TouchEvent)) bad.push("touchstart not instanceof TouchEvent");
|
|
|
|
if (bad.length) Challenge.fail(...bad);
|
|
else Challenge.pass("real TouchEvent + Touch object surface present");
|
|
}, { passive: true });
|
|
|
|
// Capability check: if TouchEvent constructor missing entirely, hint immediately on click.
|
|
pad.addEventListener("click", () => {
|
|
if (!touchStart && typeof window.TouchEvent !== "function") {
|
|
Challenge.fail("TouchEvent constructor not available on this UA (enable touch emulation)");
|
|
} else if (!touchStart) {
|
|
Challenge.fail("click fired but no touchstart — synthetic pointer without TouchEvent");
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|