mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(reader): preserve valid EPUB side clicks
Evaluate the long-hold threshold when the pointer is released so the double-click delay does not discard valid page turns. Closes #1992
This commit is contained in:
@@ -551,6 +551,53 @@ describe('useFoliateInput', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ holdMs: 250, expectedNavigationCount: 1 },
|
||||
{ holdMs: 500, expectedNavigationCount: 0 },
|
||||
])('handles a $holdMs ms pointer hold before the delayed click-zone action', ({ holdMs, expectedNavigationCount }) => {
|
||||
vi.useFakeTimers()
|
||||
|
||||
const next = vi.fn<() => void>()
|
||||
const view: ViewLike = {
|
||||
prev: vi.fn<() => void>(),
|
||||
next,
|
||||
getBoundingClientRect: () => ({ left: 0, width: 100 }) as DOMRect,
|
||||
}
|
||||
const input = useFoliateInput(() => view, undefined, vi.fn<() => void>(), vi.fn<() => void>())
|
||||
const doc = makeDocTarget()
|
||||
input.attachIframeClicks(doc)
|
||||
|
||||
const originalMaxTouchPoints = Object.getOwnPropertyDescriptor(navigator, 'maxTouchPoints')
|
||||
const originalOntouchstart = Object.getOwnPropertyDescriptor(window, 'ontouchstart')
|
||||
Object.defineProperty(navigator, 'maxTouchPoints', {
|
||||
configurable: true,
|
||||
get: () => 0,
|
||||
})
|
||||
Reflect.deleteProperty(window as unknown as Record<string, unknown>, 'ontouchstart')
|
||||
|
||||
const postMessage = vi.spyOn(window, 'postMessage').mockImplementation(() => {})
|
||||
|
||||
doc.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))
|
||||
vi.advanceTimersByTime(holdMs)
|
||||
doc.dispatchEvent(new MouseEvent('click', { bubbles: true, clientX: 95, clientY: 100 }))
|
||||
const message = postMessage.mock.calls[0]?.[0]
|
||||
if (message) window.dispatchEvent(new MessageEvent('message', { data: message, origin: window.location.origin }))
|
||||
vi.advanceTimersByTime(300)
|
||||
|
||||
expect(postMessage).toHaveBeenCalledTimes(expectedNavigationCount)
|
||||
expect(next).toHaveBeenCalledTimes(expectedNavigationCount)
|
||||
|
||||
postMessage.mockRestore()
|
||||
input.cleanup()
|
||||
|
||||
if (originalMaxTouchPoints) {
|
||||
Object.defineProperty(navigator, 'maxTouchPoints', originalMaxTouchPoints)
|
||||
}
|
||||
if (originalOntouchstart) {
|
||||
Object.defineProperty(window, 'ontouchstart', originalOntouchstart)
|
||||
}
|
||||
})
|
||||
|
||||
it('ignores a page-turn click message that arrives after annotation tap suppression starts', () => {
|
||||
vi.useFakeTimers()
|
||||
|
||||
|
||||
@@ -200,6 +200,7 @@ export function useFoliateInput(
|
||||
'click',
|
||||
(e: MouseEvent) => {
|
||||
if (Date.now() - lastTouchTime < 500) return
|
||||
if (!longHoldTimeout) return
|
||||
const iframe = doc.defaultView?.frameElement as HTMLIFrameElement | null
|
||||
if (!iframe) return
|
||||
const rect = iframe.getBoundingClientRect()
|
||||
@@ -264,7 +265,6 @@ export function useFoliateInput(
|
||||
setTimeout(() => {
|
||||
if (isTapNavigationSuppressed()) return
|
||||
if (Date.now() - lastClickTime < DOUBLE_CLICK_MS) return
|
||||
if (!longHoldTimeout) return
|
||||
if (isNavigating) return
|
||||
|
||||
const isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0
|
||||
|
||||
Reference in New Issue
Block a user