mirror of
https://github.com/vale981/tridactyl
synced 2025-03-05 17:41:40 -05:00
Try to make the highlight's position always correct
This will reposition the highlight whenever user focus other match, but the scroll behavior may work bad sometimes.
This commit is contained in:
parent
725dcf92f1
commit
b218014913
1 changed files with 42 additions and 27 deletions
|
@ -26,7 +26,7 @@ function getFindHost() {
|
|||
class FindHighlight extends HTMLSpanElement {
|
||||
public top = Infinity
|
||||
|
||||
constructor(private rects, public range: Range) {
|
||||
constructor(public range: Range) {
|
||||
super()
|
||||
{
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1716685
|
||||
|
@ -38,32 +38,45 @@ class FindHighlight extends HTMLSpanElement {
|
|||
this.style.position = "absolute"
|
||||
this.style.top = "0px"
|
||||
this.style.left = "0px"
|
||||
for (const rect of rects) {
|
||||
if (rect.top < this.top) {
|
||||
this.top = rect.top
|
||||
this.updateRectsPosition()
|
||||
;(this as any).unfocus()
|
||||
}
|
||||
|
||||
updateRectsPosition() {
|
||||
const rects = this.getClientRects()
|
||||
this.top = Infinity
|
||||
const windowTop = window.pageYOffset
|
||||
const windowLeft = window.pageXOffset
|
||||
for (let i=0; i<rects.length; i++) {
|
||||
const rect = rects[i]
|
||||
if ((rect.top + windowTop) < this.top) {
|
||||
this.top = rect.top + windowTop
|
||||
}
|
||||
let highlight
|
||||
if (i in this.children) highlight = this.children[i]
|
||||
else {
|
||||
highlight = document.createElement("span")
|
||||
this.appendChild(highlight)
|
||||
}
|
||||
const highlight = document.createElement("span")
|
||||
highlight.className = "TridactylFindHighlight"
|
||||
highlight.style.position = "absolute"
|
||||
highlight.style.top = `${rect.top}px`
|
||||
highlight.style.left = `${rect.left}px`
|
||||
highlight.style.top = `${rect.top + windowTop}px`
|
||||
highlight.style.left = `${rect.left + windowLeft}px`
|
||||
highlight.style.width = `${rect.right - rect.left}px`
|
||||
highlight.style.height = `${rect.bottom - rect.top}px`
|
||||
highlight.style.zIndex = "2147483645"
|
||||
highlight.style.pointerEvents = "none"
|
||||
this.appendChild(highlight)
|
||||
}
|
||||
;(this as any).unfocus()
|
||||
}
|
||||
|
||||
static fromFindApi(rectData, rangeData, allTextNode: Text[]) {
|
||||
static fromFindApi(found, allTextNode: Text[]) {
|
||||
const range = document.createRange()
|
||||
range.setStart(
|
||||
allTextNode[rangeData.startTextNodePos],
|
||||
rangeData.startOffset,
|
||||
allTextNode[found.startTextNodePos],
|
||||
found.startOffset,
|
||||
)
|
||||
range.setEnd(allTextNode[rangeData.endTextNodePos], rangeData.endOffset)
|
||||
return new this(rectData, range)
|
||||
range.setEnd(allTextNode[found.endTextNodePos], found.endOffset)
|
||||
return new this(range)
|
||||
}
|
||||
|
||||
getBoundingClientRect() {
|
||||
|
@ -79,7 +92,9 @@ class FindHighlight extends HTMLSpanElement {
|
|||
}
|
||||
focus() {
|
||||
if (!DOM.isVisible(this)) {
|
||||
this.children[0].scrollIntoView({
|
||||
// this may not always work, eg if the parent contains a lot of
|
||||
// child element and text node.
|
||||
this.range.startContainer.parentElement.scrollIntoView({
|
||||
block: "center",
|
||||
inline: "center",
|
||||
})
|
||||
|
@ -99,7 +114,7 @@ class FindHighlight extends HTMLSpanElement {
|
|||
}
|
||||
|
||||
for (const node of this.children) {
|
||||
;(node as HTMLElement).style.background = `rgba(255,127,255,0.5)`
|
||||
node.style.background = `rgba(255,127,255,0.5)`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,11 +174,7 @@ export async function jumpToMatch(searchQuery, option) {
|
|||
continue
|
||||
}
|
||||
const range = results.rangeData[i]
|
||||
const high = FindHighlight.fromFindApi(
|
||||
data.rectsAndTexts.rectList,
|
||||
range,
|
||||
nodes,
|
||||
)
|
||||
const high = FindHighlight.fromFindApi(range, nodes)
|
||||
host.appendChild(high)
|
||||
lastHighlights.push(high)
|
||||
}
|
||||
|
@ -177,16 +188,14 @@ export async function jumpToMatch(searchQuery, option) {
|
|||
if ("jumpTo" in option) {
|
||||
selected =
|
||||
(option["jumpTo"] + lastHighlights.length) % lastHighlights.length
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
;(lastHighlights[selected] as any).focus()
|
||||
focusHighlight(selected)
|
||||
return
|
||||
}
|
||||
|
||||
// Just reuse the code to find the first match in the view
|
||||
selected = 0
|
||||
if (DOM.isVisible(lastHighlights[selected])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
;(lastHighlights[selected] as any).focus()
|
||||
focusHighlight(selected)
|
||||
} else {
|
||||
const searchFromView = true
|
||||
await jumpToNextMatch(1, searchFromView)
|
||||
|
@ -203,6 +212,13 @@ export function removeHighlighting() {
|
|||
while (host.firstChild) host.removeChild(host.firstChild)
|
||||
}
|
||||
|
||||
export function focusHighlight(index) {
|
||||
lastHighlights[index].focus()
|
||||
for (const node of lastHighlights) {
|
||||
node.updateRectsPosition()
|
||||
}
|
||||
}
|
||||
|
||||
export async function jumpToNextMatch(n: number, searchFromView = false) {
|
||||
let lastSearchQuery
|
||||
if (!lastHighlights) {
|
||||
|
@ -250,8 +266,7 @@ export async function jumpToNextMatch(n: number, searchFromView = false) {
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
;(lastHighlights[selected] as any).focus()
|
||||
focusHighlight(selected)
|
||||
}
|
||||
|
||||
export function currentMatchRange(): Range {
|
||||
|
|
Loading…
Add table
Reference in a new issue