mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Paginator: fix caret position when navigating
The effect of this is more obvious if you enable caret browsing (F7 in all browsers). Previously, if you go to a fragment, the caret isn't moved. Now it works as expected.
This commit is contained in:
+36
-16
@@ -123,6 +123,22 @@ const getVisibleRange = (doc, start, end, mapRect) => {
|
|||||||
return range
|
return range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setSelectionTo = (target, collapse) => {
|
||||||
|
let range
|
||||||
|
if (target.startContainer) range = target.cloneRange()
|
||||||
|
else if (target.nodeType) {
|
||||||
|
range = document.createRange()
|
||||||
|
range.selectNode(target)
|
||||||
|
}
|
||||||
|
if (range) {
|
||||||
|
const sel = range.startContainer.ownerDocument.defaultView.getSelection()
|
||||||
|
sel.removeAllRanges()
|
||||||
|
if (collapse === -1) range.collapse(true)
|
||||||
|
else if (collapse === 1) range.collapse()
|
||||||
|
sel.addRange(range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getDirection = doc => {
|
const getDirection = doc => {
|
||||||
const { defaultView } = doc
|
const { defaultView } = doc
|
||||||
const { writingMode, direction } = defaultView.getComputedStyle(doc.body)
|
const { writingMode, direction } = defaultView.getComputedStyle(doc.body)
|
||||||
@@ -522,7 +538,16 @@ export class Paginator extends HTMLElement {
|
|||||||
|
|
||||||
doc.addEventListener('focusin', e => this.scrolled ? null :
|
doc.addEventListener('focusin', e => this.scrolled ? null :
|
||||||
// NOTE: `requestAnimationFrame` is needed in WebKit
|
// NOTE: `requestAnimationFrame` is needed in WebKit
|
||||||
requestAnimationFrame(() => this.scrollToAnchor(e.target)))
|
requestAnimationFrame(() => this.#scrollToAnchor(e.target)))
|
||||||
|
})
|
||||||
|
this.addEventListener('relocate', ({ detail }) => {
|
||||||
|
if (detail.reason === 'selection') setSelectionTo(this.#anchor, 0)
|
||||||
|
else if (detail.reason === 'navigation') {
|
||||||
|
if (this.#anchor === 1) setSelectionTo(detail.range, 1)
|
||||||
|
else if (typeof this.#anchor === 'number')
|
||||||
|
setSelectionTo(detail.range, -1)
|
||||||
|
else setSelectionTo(this.#anchor, -1)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.#mediaQueryListener = () => {
|
this.#mediaQueryListener = () => {
|
||||||
@@ -560,7 +585,7 @@ export class Paginator extends HTMLElement {
|
|||||||
}
|
}
|
||||||
this.#view = new View({
|
this.#view = new View({
|
||||||
container: this,
|
container: this,
|
||||||
onExpand: () => this.scrollToAnchor(this.#anchor),
|
onExpand: () => this.#scrollToAnchor(this.#anchor),
|
||||||
})
|
})
|
||||||
this.#container.append(this.#view.element)
|
this.#container.append(this.#view.element)
|
||||||
return this.#view
|
return this.#view
|
||||||
@@ -647,7 +672,7 @@ export class Paginator extends HTMLElement {
|
|||||||
vertical: this.#vertical,
|
vertical: this.#vertical,
|
||||||
rtl: this.#rtl,
|
rtl: this.#rtl,
|
||||||
}))
|
}))
|
||||||
this.scrollToAnchor(this.#anchor)
|
this.#scrollToAnchor(this.#anchor)
|
||||||
}
|
}
|
||||||
get scrolled() {
|
get scrolled() {
|
||||||
return this.getAttribute('flow') === 'scrolled'
|
return this.getAttribute('flow') === 'scrolled'
|
||||||
@@ -807,6 +832,9 @@ export class Paginator extends HTMLElement {
|
|||||||
return this.#scrollTo(offset, reason, smooth)
|
return this.#scrollTo(offset, reason, smooth)
|
||||||
}
|
}
|
||||||
async scrollToAnchor(anchor, select) {
|
async scrollToAnchor(anchor, select) {
|
||||||
|
return this.#scrollToAnchor(anchor, select ? 'selection' : 'navigation')
|
||||||
|
}
|
||||||
|
async #scrollToAnchor(anchor, reason = 'anchor') {
|
||||||
this.#anchor = anchor
|
this.#anchor = anchor
|
||||||
const rects = uncollapse(anchor)?.getClientRects?.()
|
const rects = uncollapse(anchor)?.getClientRects?.()
|
||||||
// if anchor is an element or a range
|
// if anchor is an element or a range
|
||||||
@@ -816,28 +844,19 @@ export class Paginator extends HTMLElement {
|
|||||||
const rect = Array.from(rects)
|
const rect = Array.from(rects)
|
||||||
.find(r => r.width > 0 && r.height > 0) || rects[0]
|
.find(r => r.width > 0 && r.height > 0) || rects[0]
|
||||||
if (!rect) return
|
if (!rect) return
|
||||||
await this.#scrollToRect(rect, 'anchor')
|
await this.#scrollToRect(rect, reason)
|
||||||
if (select) this.#selectAnchor()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// if anchor is a fraction
|
// if anchor is a fraction
|
||||||
if (this.scrolled) {
|
if (this.scrolled) {
|
||||||
await this.#scrollTo(anchor * this.viewSize, 'anchor')
|
await this.#scrollTo(anchor * this.viewSize, reason)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { pages } = this
|
const { pages } = this
|
||||||
if (!pages) return
|
if (!pages) return
|
||||||
const textPages = pages - 2
|
const textPages = pages - 2
|
||||||
const newPage = Math.round(anchor * (textPages - 1))
|
const newPage = Math.round(anchor * (textPages - 1))
|
||||||
await this.#scrollToPage(newPage + 1, 'anchor')
|
await this.#scrollToPage(newPage + 1, reason)
|
||||||
}
|
|
||||||
#selectAnchor() {
|
|
||||||
const { defaultView } = this.#view.document
|
|
||||||
if (this.#anchor.startContainer) {
|
|
||||||
const sel = defaultView.getSelection()
|
|
||||||
sel.removeAllRanges()
|
|
||||||
sel.addRange(this.#anchor)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#getVisibleRange() {
|
#getVisibleRange() {
|
||||||
if (this.scrolled) return getVisibleRange(this.#view.document,
|
if (this.scrolled) return getVisibleRange(this.#view.document,
|
||||||
@@ -849,7 +868,8 @@ export class Paginator extends HTMLElement {
|
|||||||
#afterScroll(reason) {
|
#afterScroll(reason) {
|
||||||
const range = this.#getVisibleRange()
|
const range = this.#getVisibleRange()
|
||||||
// don't set new anchor if relocation was to scroll to anchor
|
// don't set new anchor if relocation was to scroll to anchor
|
||||||
if (reason !== 'anchor') this.#anchor = range
|
if (reason !== 'selection' && reason !== 'navigation' && reason !== 'anchor')
|
||||||
|
this.#anchor = range
|
||||||
else this.#justAnchored = true
|
else this.#justAnchored = true
|
||||||
|
|
||||||
const index = this.#index
|
const index = this.#index
|
||||||
|
|||||||
Reference in New Issue
Block a user