mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-30 23:49:10 -04:00
Clamp touch selection endpoints to the visible page
Chrome word-snapping during a touch selection drag can map the endpoint past the visible column into the next (off-screen) page, selecting the entire visible page at once. Re-map the endpoint via caretRangeFromPoint at the same line height inside the visible column whenever it lands outside the last visible range.
This commit is contained in:
@@ -599,6 +599,10 @@ export class Paginator extends HTMLElement {
|
|||||||
})
|
})
|
||||||
doc.addEventListener('pointerup', () => isPointerSelecting = false)
|
doc.addEventListener('pointerup', () => isPointerSelecting = false)
|
||||||
doc.addEventListener('pointercancel', () => isPointerSelecting = false)
|
doc.addEventListener('pointercancel', () => isPointerSelecting = false)
|
||||||
|
let touchSelecting = false
|
||||||
|
doc.addEventListener('pointerdown', e => {
|
||||||
|
touchSelecting = e.pointerType === 'touch'
|
||||||
|
})
|
||||||
let isKeyboardSelecting = false
|
let isKeyboardSelecting = false
|
||||||
doc.addEventListener('keydown', () => isKeyboardSelecting = true)
|
doc.addEventListener('keydown', () => isKeyboardSelecting = true)
|
||||||
doc.addEventListener('keyup', () => isKeyboardSelecting = false)
|
doc.addEventListener('keyup', () => isKeyboardSelecting = false)
|
||||||
@@ -608,6 +612,11 @@ export class Paginator extends HTMLElement {
|
|||||||
if (!range) return
|
if (!range) return
|
||||||
const sel = doc.getSelection()
|
const sel = doc.getSelection()
|
||||||
if (!sel.rangeCount) return
|
if (!sel.rangeCount) return
|
||||||
|
if (touchSelecting) {
|
||||||
|
if (sel.isCollapsed) touchSelecting = false
|
||||||
|
else if (sel.type === 'Range')
|
||||||
|
this.#clampTouchSelection(sel, doc)
|
||||||
|
}
|
||||||
if (isPointerSelecting && sel.type === 'Range')
|
if (isPointerSelecting && sel.type === 'Range')
|
||||||
checkPointerSelection(range, sel)
|
checkPointerSelection(range, sel)
|
||||||
else if (isKeyboardSelecting) {
|
else if (isKeyboardSelecting) {
|
||||||
@@ -952,6 +961,25 @@ export class Paginator extends HTMLElement {
|
|||||||
return getVisibleRange(this.#view.document,
|
return getVisibleRange(this.#view.document,
|
||||||
this.start - size, this.end - size, this.#getRectMapper())
|
this.start - size, this.end - size, this.#getRectMapper())
|
||||||
}
|
}
|
||||||
|
#clampTouchSelection(sel, doc) {
|
||||||
|
const range = this.#lastVisibleRange
|
||||||
|
if (!range || !sel.rangeCount) return
|
||||||
|
const backward = selectionIsBackward(sel)
|
||||||
|
const probe = sel.getRangeAt(0).cloneRange()
|
||||||
|
probe.collapse(!backward)
|
||||||
|
if (backward
|
||||||
|
? range.compareBoundaryPoints(Range.START_TO_START, probe) <= 0
|
||||||
|
: range.compareBoundaryPoints(Range.END_TO_END, probe) >= 0) return
|
||||||
|
const rect = probe.getBoundingClientRect()
|
||||||
|
if (!rect) return
|
||||||
|
const x = backward ? this.start + 1 : this.end - 1
|
||||||
|
const caret = doc.caretRangeFromPoint?.(x, rect.top)
|
||||||
|
?? doc.caretPositionFromPoint?.(x, rect.top)
|
||||||
|
if (!caret) return
|
||||||
|
const node = caret.startContainer ?? caret.offsetNode
|
||||||
|
const offset = caret.startOffset ?? caret.offset
|
||||||
|
if (node) sel.extend(node, offset)
|
||||||
|
}
|
||||||
#afterScroll(reason) {
|
#afterScroll(reason) {
|
||||||
const range = this.#getVisibleRange()
|
const range = this.#getVisibleRange()
|
||||||
this.#lastVisibleRange = range
|
this.#lastVisibleRange = range
|
||||||
|
|||||||
Reference in New Issue
Block a user