Revise scrolling

This commit is contained in:
Simon Rozman 2025-02-28 11:32:21 +01:00
parent d246d07d7f
commit 51099347f2

View File

@ -73,6 +73,9 @@ class BesService {
})
besServices.push(this)
// Initial sync the scroll as hostElement may be scrolled by non-(0, 0) at the time of BesService registration.
this.onScroll()
}
/**
@ -360,11 +363,13 @@ class BesService {
*/
drawMistakeMarkup(match) {
const range = match.range
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
const scrollX = canvasPanelRect.left
const scrollY = canvasPanelRect.top
match.highlights = Array.from(range.getClientRects())
if (match.highlights.length === 0) return
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
for (let rect of match.highlights) {
rect.x -= canvasPanelRect.x
rect.y -= canvasPanelRect.y
}
const dpr = window.devicePixelRatio
this.ctx.lineWidth = 2 * dpr // Use 2 for clearer visibility
const ruleId = match.match.rule.id
@ -386,7 +391,7 @@ class BesService {
const scale = (markerY2 - markerY1) / 18
const x = match.highlights[0].left
const y = match.highlights[0].bottom
this.drawMissingComma(x - scrollX, y - scrollY, scale, '?')
this.drawMissingComma(x, y, scale, '?')
break
}
@ -413,25 +418,20 @@ class BesService {
// in another line, making a confusing UX.
const x = match.highlights[0].left
const y = match.highlights[0].bottom
this.drawMissingComma(x - scrollX, y - scrollY, scale)
this.drawMissingComma(x, y, scale)
} else if (/^\s+$/.test(toInsert)) {
const x = match.highlights[0].left
const y1 = match.highlights[0].bottom - 2 * scale
const y2 = match.highlights[0].top + 2 * scale
this.drawWrongSpacing(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale
)
this.drawWrongSpacing(x, y1, y2, scale)
} else {
const x = match.highlights[0].left - 1 * scale
const y1 = match.highlights[0].bottom
const y2 = match.highlights[0].top
this.drawMissingText(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
x,
y1,
y2,
scale,
replacement.substr(lengthDiff).trim()
)
@ -446,25 +446,20 @@ class BesService {
if (toInsert === ',') {
const x = match.highlights.at(-1).right
const y = match.highlights.at(-1).bottom
this.drawMissingComma(x - scrollX, y - scrollY, scale)
this.drawMissingComma(x, y, scale)
} else if (/^\s+$/.test(toInsert)) {
const x = match.highlights.at(-1).right
const y1 = match.highlights.at(-1).bottom - 2 * scale
const y2 = match.highlights.at(-1).top + 2 * scale
this.drawWrongSpacing(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale
)
this.drawWrongSpacing(x, y1, y2, scale)
} else {
const x = match.highlights.at(-1).right + 1 * scale
const y1 = match.highlights.at(-1).bottom
const y2 = match.highlights.at(-1).top
this.drawMissingText(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
x,
y1,
y2,
scale,
replacement.substr(-lengthDiff).trim()
)
@ -488,12 +483,7 @@ class BesService {
const x = (rect.left + rect.right) / 2
const y1 = rect.top
const y2 = rect.bottom
this.drawWrongSpacing(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale
)
this.drawWrongSpacing(x, y1, y2, scale)
} else {
for (let rect of this.makeRange(
match.data,
@ -501,10 +491,10 @@ class BesService {
match.match.offset - lengthDiff
)?.getClientRects())
this.drawExcessiveText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY
rect.left,
rect.bottom,
rect.right,
rect.top
)
}
} else if (context.substr(0, replacement.length) === replacement) {
@ -523,12 +513,7 @@ class BesService {
const x = (rect.left + rect.right) / 2
const y1 = rect.top
const y2 = rect.bottom
this.drawWrongSpacing(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale
)
this.drawWrongSpacing(x, y1, y2, scale)
} else {
for (let rect of this.makeRange(
match.data,
@ -536,10 +521,10 @@ class BesService {
match.match.offset + match.match.length
)?.getClientRects())
this.drawExcessiveText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY
rect.left,
rect.bottom,
rect.right,
rect.top
)
}
} else {
@ -559,20 +544,20 @@ class BesService {
for (let rect of match.highlights) {
if (first) {
this.drawWrongText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY,
rect.left,
rect.bottom,
rect.right,
rect.top,
scale,
replacement
)
first = false
} else {
this.drawExcessiveText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY
rect.left,
rect.bottom,
rect.right,
rect.top
)
}
}
@ -600,22 +585,11 @@ class BesService {
if (/^\s+$/.test(toInsert)) {
const y1 = rects[0].bottom - 2 * scale
const y2 = rects[0].top + 2 * scale
this.drawWrongSpacing(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale
)
this.drawWrongSpacing(x, y1, y2, scale)
} else {
const y1 = rects[0].bottom
const y2 = rects[0].top
this.drawMissingText(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale,
toInsert.trim()
)
this.drawMissingText(x, y1, y2, scale, toInsert.trim())
}
} else if (lengthL + lengthR === replacement.length) {
// Something to remove
@ -629,19 +603,14 @@ class BesService {
const x = (rects[0].left + rects[0].right) / 2
const y1 = rects[0].top
const y2 = rects[0].bottom
this.drawWrongSpacing(
x - scrollX,
y1 - scrollY,
y2 - scrollY,
scale
)
this.drawWrongSpacing(x, y1, y2, scale)
} else {
for (let rect of rects)
this.drawExcessiveText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY
rect.left,
rect.bottom,
rect.right,
rect.top
)
}
} else {
@ -655,20 +624,20 @@ class BesService {
for (let rect of rects) {
if (first) {
this.drawWrongText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY,
rect.left,
rect.bottom,
rect.right,
rect.top,
scale,
toReplace
)
first = false
} else {
this.drawExcessiveText(
rect.left - scrollX,
rect.bottom - scrollY,
rect.right - scrollX,
rect.top - scrollY
rect.left,
rect.bottom,
rect.right,
rect.top
)
}
}
@ -684,19 +653,14 @@ class BesService {
const x2 = rect.right
const y = rect.bottom
const scale = (rect.bottom - rect.top) / 18
this.drawAttentionRequired(
x1 - scrollX,
x2 - scrollX,
y - scrollY,
scale
)
this.drawAttentionRequired(x1, x2, y, scale)
}
markerY1 = Math.min(...match.highlights.map(rect => rect.top))
markerY2 = Math.max(...match.highlights.map(rect => rect.bottom))
}
this.drawSideMarker(markerY1 - scrollY, markerY2 - scrollY)
this.drawSideMarker(markerY1, markerY2)
}
static commonPrefixLength(s1, s2) {
@ -872,15 +836,11 @@ class BesService {
*/
setCorrectionPanelSize() {
this.disableMutationObserver()
const styles = window.getComputedStyle(this.hostElement)
const hostRect = this.hostElement.getBoundingClientRect()
// Sync margins one by one. Firefox is not happy when syncing all at once.
this.scrollPanel.style.marginLeft = styles.marginLeft
this.scrollPanel.style.marginTop = styles.marginTop
this.scrollPanel.style.marginRight = styles.marginRight
this.scrollPanel.style.marginBottom = styles.marginBottom
this.scrollPanel.style.boxSizing = styles.boxSizing
this.scrollPanel.style.scrollBehavior = styles.scrollBehavior
this.textFont = styles.fontFamily
// Resize canvas if needed.
this.canvasPanel.style.width = `${this.hostElement.scrollWidth}px`
this.canvasPanel.style.height = `${this.hostElement.scrollHeight}px`
const dpr = window.devicePixelRatio
@ -895,6 +855,14 @@ class BesService {
this.canvasPanel.height = newCanvasHeight
this.redrawAllMistakeMarkup()
}
// Note: Firefox is not happy when syncing all margins at once.
this.scrollPanel.style.marginLeft = styles.marginLeft
this.scrollPanel.style.marginTop = styles.marginTop
this.scrollPanel.style.marginRight = styles.marginRight
this.scrollPanel.style.marginBottom = styles.marginBottom
this.scrollPanel.style.boxSizing = styles.boxSizing
this.scrollPanel.style.scrollBehavior = styles.scrollBehavior
if (this.isHostElementInline()) {
const totalWidth =
parseFloat(styles.paddingLeft) +
@ -905,9 +873,11 @@ class BesService {
this.scrollPanel.style.width = `${totalWidth}px`
this.scrollPanel.style.height = styles.height
} else {
const hostRect = this.hostElement.getBoundingClientRect()
this.scrollPanel.style.width = `${hostRect.width}px`
this.scrollPanel.style.height = `${hostRect.height}px`
}
this.enableMutationObserver()
}
@ -934,6 +904,7 @@ class BesService {
* @param {*} match Grammar checking rule match
*/
highlightMistake(match) {
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
match.highlights.forEach(rect => {
const el = document.createElement('div')
el.classList.add('bes-highlight-rect')
@ -942,8 +913,8 @@ class BesService {
? 'bes-highlight-spelling-rect'
: 'bes-highlight-grammar-rect'
)
el.style.left = `${rect.x + window.scrollX}px`
el.style.top = `${rect.y + window.scrollY}px`
el.style.left = `${rect.x + canvasPanelRect.x + window.scrollX}px`
el.style.top = `${rect.y + canvasPanelRect.y + window.scrollY}px`
el.style.width = `${rect.width}px`
el.style.height = `${rect.height}px`
document.body.appendChild(el)
@ -1357,12 +1328,14 @@ class BesTreeService extends BesService {
const source = event?.detail !== 1 ? event?.detail : event
const el = this.getBlockParent(source.targetElement || source.target)
if (!el) return
// TODO: Adjust source.clientX and source.clientY for scrolling offset.
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
let x = source.clientX - canvasPanelRect.x
let y = source.clientY - canvasPanelRect.y
const pointsInRect = []
for (let result of this.results) {
for (let m of result.matches) {
for (let rect of m.highlights) {
if (BesService.isPointInRect(source.clientX, source.clientY, rect)) {
if (BesService.isPointInRect(x, y, rect)) {
pointsInRect.push({ el, match: m })
}
}
@ -2022,12 +1995,14 @@ class BesPlainTextService extends BesService {
const source = event?.detail !== 1 ? event?.detail : event
const el = source.targetElement || source.target || this.hostElement
if (!el) return
// TODO: Adjust source.clientX and source.clientY for scrolling offset.
const canvasPanelRect = this.canvasPanel.getBoundingClientRect()
let x = source.clientX - canvasPanelRect.x
let y = source.clientY - canvasPanelRect.y
const pointsInRect = []
for (let result of this.results) {
for (let m of result.matches) {
for (let rect of m.highlights) {
if (BesService.isPointInRect(source.clientX, source.clientY, rect)) {
if (BesService.isPointInRect(x, y, rect)) {
pointsInRect.push({ el: result.range, match: m })
}
}