fix(reader): keep double-click-and-drag from turning the page (#4524) (#4536)

On the web, double-clicking a word and then dragging to extend the
native selection also turned the page. The first click's deferred
single-click timer fires 250ms later while the second click's button is
still held during the drag, so it posts iframe-single-click and flips
the page. A plain double-click escapes this because its fast second
click updates lastClickTime in time.

Track the mouse-button state in iframeEventHandlers and suppress the
deferred single click while the button is held (a drag is in progress).
A normal single click is unaffected: its button is already released by
the time the deferred timer fires.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin
2026-06-12 00:39:01 +08:00
committed by GitHub
parent d165e8df2c
commit 6dc42222e0
4 changed files with 158 additions and 0 deletions
@@ -3,6 +3,7 @@ import { eventDispatcher } from '@/utils/event';
let lastClickTime = 0;
let longHoldTimeout: ReturnType<typeof setTimeout> | null = null;
let isMouseDown = false;
let keyboardState = {
key: '',
@@ -87,6 +88,7 @@ export const handleKeyup = (bookKey: string, event: KeyboardEvent) => {
};
export const handleMousedown = (bookKey: string, event: MouseEvent) => {
isMouseDown = true;
longHoldTimeout = setTimeout(() => {
longHoldTimeout = null;
}, LONG_HOLD_THRESHOLD);
@@ -109,6 +111,7 @@ export const handleMousedown = (bookKey: string, event: MouseEvent) => {
};
export const handleMouseup = (bookKey: string, event: MouseEvent) => {
isMouseDown = false;
// we will handle mouse back and forward buttons ourselves
if ([3, 4].includes(event.button)) {
event.preventDefault();
@@ -209,6 +212,13 @@ export const handleClick = (
return;
}
// if the mouse button is still held, a drag is in progress (e.g. a
// double-click-and-drag selection); sending a single click here would turn
// the page mid-selection (#4524).
if (isMouseDown) {
return;
}
// if long hold is detected, we don't want to send single click event
if (!longHoldTimeout) {
return;