feat: two-finger long-press opens the panel
A second way in that does not depend on finding a 7px tab. Two fingers rather than one because Chromium claims the one-finger long press for image menus and text selection, and a manga reader is all images. Passive listeners; a pinch-zoom cancels via the 15px slop check. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1200,6 +1200,71 @@
|
||||
setInterval(fire, 1500); // catch routes that bypass history
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Two-finger long-press — a way in that does not depend on finding a 7px tab
|
||||
//
|
||||
// Deliberately two fingers, not one: Chromium claims the one-finger long
|
||||
// press for image context menus, text selection, and link previews, and on a
|
||||
// manga reader the whole viewport is images. It assigns no two-finger long
|
||||
// press, so these listeners stay passive and never preventDefault.
|
||||
// ============================================================
|
||||
|
||||
const LONGPRESS_MS = 500;
|
||||
const LONGPRESS_SLOP = 15; // px either finger may drift before it counts as a drag
|
||||
|
||||
function installLongPress() {
|
||||
let timer = null;
|
||||
let start = null; // [{x, y}, {x, y}] — where each finger landed
|
||||
|
||||
const cancel = () => {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
start = null;
|
||||
};
|
||||
|
||||
const opts = { passive: true, capture: true };
|
||||
|
||||
// Fires once per finger, so the first touch cancels and the second arms.
|
||||
// A third finger cancels again.
|
||||
document.addEventListener(
|
||||
"touchstart",
|
||||
(e) => {
|
||||
cancel();
|
||||
if (e.touches.length !== 2) return;
|
||||
start = [
|
||||
{ x: e.touches[0].clientX, y: e.touches[0].clientY },
|
||||
{ x: e.touches[1].clientX, y: e.touches[1].clientY },
|
||||
];
|
||||
timer = setTimeout(() => {
|
||||
cancel();
|
||||
togglePanel();
|
||||
}, LONGPRESS_MS);
|
||||
},
|
||||
opts
|
||||
);
|
||||
|
||||
// A pinch-zoom is two fingers held down, so the slop check is what keeps it
|
||||
// from opening the panel mid-gesture.
|
||||
document.addEventListener(
|
||||
"touchmove",
|
||||
(e) => {
|
||||
if (!start || e.touches.length !== 2) return cancel();
|
||||
for (let i = 0; i < 2; i++) {
|
||||
if (
|
||||
Math.abs(e.touches[i].clientX - start[i].x) > LONGPRESS_SLOP ||
|
||||
Math.abs(e.touches[i].clientY - start[i].y) > LONGPRESS_SLOP
|
||||
) {
|
||||
return cancel();
|
||||
}
|
||||
}
|
||||
},
|
||||
opts
|
||||
);
|
||||
|
||||
document.addEventListener("touchend", cancel, opts);
|
||||
document.addEventListener("touchcancel", cancel, opts);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Boot
|
||||
// ============================================================
|
||||
@@ -1209,6 +1274,7 @@
|
||||
state.page = detect();
|
||||
render();
|
||||
installNavWatcher();
|
||||
installLongPress();
|
||||
window.addEventListener("online", drain); // signal returned while the page stayed open
|
||||
// Sync first: both auto-record and the latest-chapter checks below need to
|
||||
// know which series are bookmarked and how fresh they are.
|
||||
|
||||
Reference in New Issue
Block a user