Compare commits
7 Commits
0ed93fb9b2
...
bf7b844e1c
Author | SHA1 | Date | |
---|---|---|---|
bf7b844e1c | |||
d990cd061a | |||
51099347f2 | |||
d246d07d7f | |||
6b1b46de55 | |||
9c7c967039 | |||
acd7ac1a2b |
@ -8,9 +8,33 @@
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<script>const besUrl = 'http://localhost:225/api/v2';</script>
|
||||
<script src="../service.js"></script>
|
||||
<style>
|
||||
.mock-resizable {
|
||||
overflow-x: scroll;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
border-radius: 3px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.mock-content {
|
||||
width: 1000px;
|
||||
height: 600px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.mock-flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex">
|
||||
<div class="mock-flex">
|
||||
<div class="mock-content">
|
||||
<p>Element to delete</p>
|
||||
<p>Element to delete</p>
|
||||
@ -18,7 +42,7 @@
|
||||
<p>Element to delete</p>
|
||||
<p>Element to delete</p>
|
||||
</div>
|
||||
<div class="resizable">
|
||||
<div class="mock-resizable">
|
||||
<div class="my-block my-control bes-service" contenteditable="true">
|
||||
<p>Tukaj vpišite besedilo ki ga želite popraviti.</p>
|
||||
<p>Prišla je njena lepa hčera. Smatram da tega nebi bilo potrebno storiti. Predavanje je trajalo dve ure. S njim grem v Kamnik. Janez jutri nebo prišel. Prišel je z 100 idejami.</p>
|
||||
|
344
service.js
344
service.js
@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,7 +201,7 @@ class BesService {
|
||||
*/
|
||||
setMarkupStyle(style) {
|
||||
this.markupStyle = style
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -354,17 +357,19 @@ class BesService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates grammar mistake markup in DOM and populates collection of highlight rectangles.
|
||||
* Draws grammar mistake markup on canvas and populates collection of highlight rectangles.
|
||||
*
|
||||
* @param {*} match Grammar checking rule match
|
||||
*/
|
||||
addMistakeMarkup(match) {
|
||||
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,36 +653,22 @@ 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)
|
||||
}
|
||||
|
||||
static commonPrefixLength(s1, s2) {
|
||||
let i = 0
|
||||
let len = Math.min(s1.length, s2.length)
|
||||
while (i < len && s1[i] === s2[i]) i++
|
||||
return i
|
||||
}
|
||||
|
||||
static commonSuffixLength(s1, s2) {
|
||||
let i = 0
|
||||
let i1 = s1.length
|
||||
let i2 = s2.length
|
||||
while (0 < i1-- && 0 < i2-- && s1[i1] === s2[i2]) i++
|
||||
return i
|
||||
this.drawSideMarker(markerY1, markerY2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the marker that helps visualize lines of text where grammar mistakes were detected
|
||||
*
|
||||
* @param {Number} y1 Marker top [px]
|
||||
* @param {Number} y2 Marker bottom [px]
|
||||
*/
|
||||
drawSideMarker(y1, y2) {
|
||||
const dpr = window.devicePixelRatio
|
||||
const markerX = this.canvasPanel.width - 5 * dpr
|
||||
@ -723,6 +678,14 @@ class BesService {
|
||||
this.ctx.stroke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the missing comma sign
|
||||
*
|
||||
* @param {Number} x Sign center [px]
|
||||
* @param {Number} y Sign bottom [px]
|
||||
* @param {Number} scale Sign scale
|
||||
* @param {String} comment Text to display above the marker
|
||||
*/
|
||||
drawMissingComma(x, y, scale, comment) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
@ -739,6 +702,14 @@ class BesService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the wrong spacing sign. Control direction of chevrons by reversing y1 and y2.
|
||||
*
|
||||
* @param {Number} x Sign center [px]
|
||||
* @param {Number} y1 Sign top/bottom [px]
|
||||
* @param {Number} y2 Sign bottom/top [px]
|
||||
* @param {Number} scale Sign scale
|
||||
*/
|
||||
drawWrongSpacing(x, y1, y2, scale) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
@ -753,6 +724,14 @@ class BesService {
|
||||
this.ctx.stroke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Strikes out the excessive text
|
||||
*
|
||||
* @param {Number} x1 Strike line start X [px]
|
||||
* @param {Number} y1 Strike line start Y [px]
|
||||
* @param {Number} x2 Strike line end X [px]
|
||||
* @param {Number} y2 Strike line end Y [px]
|
||||
*/
|
||||
drawExcessiveText(x1, y1, x2, y2) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
@ -761,6 +740,16 @@ class BesService {
|
||||
this.ctx.stroke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Strikes out the text and draws the replacement text above
|
||||
*
|
||||
* @param {Number} x1 Strike line start X [px]
|
||||
* @param {Number} y1 Strike line start Y [px]
|
||||
* @param {Number} x2 Strike line end X [px]
|
||||
* @param {Number} y2 Strike line end Y [px]
|
||||
* @param {Number} scale Sign scale
|
||||
* @param {String} text Text to display above
|
||||
*/
|
||||
drawWrongText(x1, y1, x2, y2, scale, text) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
@ -785,6 +774,15 @@ class BesService {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the sign some text is missing
|
||||
*
|
||||
* @param {Number} x Sign center [px]
|
||||
* @param {Number} y1 Sign bottom [px]
|
||||
* @param {Number} y2 Sign top [px]
|
||||
* @param {Number} scale Sign scale
|
||||
* @param {String} text Text to display above
|
||||
*/
|
||||
drawMissingText(x, y1, y2, scale, text) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
@ -811,6 +809,14 @@ class BesService {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws zig-zag line
|
||||
*
|
||||
* @param {Number} x1 Sign left [px]
|
||||
* @param {Number} x2 Sign right [px]
|
||||
* @param {Number} y Sign baseline [px]
|
||||
* @param {Number} scale Sign scale
|
||||
*/
|
||||
drawAttentionRequired(x1, x2, y, scale) {
|
||||
const dpr = window.devicePixelRatio
|
||||
this.ctx.beginPath()
|
||||
@ -824,6 +830,35 @@ class BesService {
|
||||
this.ctx.stroke()
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates common string prefix length
|
||||
*
|
||||
* @param {String} s1 First string
|
||||
* @param {String} s2 Second string
|
||||
* @returns Number of characters the beginnings of the strings are equal
|
||||
*/
|
||||
static commonPrefixLength(s1, s2) {
|
||||
let i = 0
|
||||
let len = Math.min(s1.length, s2.length)
|
||||
while (i < len && s1[i] === s2[i]) i++
|
||||
return i
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates common string suffix length
|
||||
*
|
||||
* @param {String} s1 First string
|
||||
* @param {String} s2 Second string
|
||||
* @returns Number of characters the endings of the strings are equal
|
||||
*/
|
||||
static commonSuffixLength(s1, s2) {
|
||||
let i = 0
|
||||
let i1 = s1.length
|
||||
let i2 = s2.length
|
||||
while (0 < i1-- && 0 < i2-- && s1[i1] === s2[i2]) i++
|
||||
return i
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if given coordinate is inside of a rectangle.
|
||||
*
|
||||
@ -840,21 +875,21 @@ class BesService {
|
||||
* Creates auxiliary DOM elements for text adornments.
|
||||
*/
|
||||
createCorrectionPanel() {
|
||||
this.panelParent = document.createElement('div')
|
||||
this.panelParent.classList.add('bes-correction-panel-parent')
|
||||
|
||||
this.correctionPanel = document.createElement('div')
|
||||
this.correctionPanel.classList.add('bes-correction-panel')
|
||||
|
||||
this.scrollPanel = document.createElement('div')
|
||||
this.scrollPanel.classList.add('bes-scroll-panel')
|
||||
|
||||
this.canvasPanel = document.createElement('canvas')
|
||||
this.canvasPanel.classList.add('bes-canvas')
|
||||
this.ctx = this.canvasPanel.getContext('2d')
|
||||
this.ctx.scale(1, 1)
|
||||
|
||||
this.panelParent.appendChild(this.correctionPanel)
|
||||
this.correctionPanel.appendChild(this.canvasPanel)
|
||||
this.correctionPanel.appendChild(this.scrollPanel)
|
||||
this.scrollPanel.appendChild(this.canvasPanel)
|
||||
this.textElement.parentElement.insertBefore(
|
||||
this.panelParent,
|
||||
this.correctionPanel,
|
||||
this.textElement
|
||||
)
|
||||
this.setCorrectionPanelSize()
|
||||
@ -864,7 +899,7 @@ class BesService {
|
||||
* Clears auxiliary DOM elements for text adornments.
|
||||
*/
|
||||
clearCorrectionPanel() {
|
||||
this.panelParent.remove()
|
||||
this.correctionPanel.remove()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -872,15 +907,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.correctionPanel.style.marginLeft = styles.marginLeft
|
||||
this.correctionPanel.style.marginTop = styles.marginTop
|
||||
this.correctionPanel.style.marginRight = styles.marginRight
|
||||
this.correctionPanel.style.marginBottom = styles.marginBottom
|
||||
this.correctionPanel.style.boxSizing = styles.boxSizing
|
||||
this.correctionPanel.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
|
||||
@ -893,8 +924,16 @@ class BesService {
|
||||
) {
|
||||
this.canvasPanel.width = newCanvasWidth
|
||||
this.canvasPanel.height = newCanvasHeight
|
||||
this.repositionAllMarkup()
|
||||
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) +
|
||||
@ -902,12 +941,14 @@ class BesService {
|
||||
parseFloat(styles.width) +
|
||||
parseFloat(styles.marginRight) +
|
||||
parseFloat(styles.paddingRight)
|
||||
this.correctionPanel.style.width = `${totalWidth}px`
|
||||
this.correctionPanel.style.height = styles.height
|
||||
this.scrollPanel.style.width = `${totalWidth}px`
|
||||
this.scrollPanel.style.height = styles.height
|
||||
} else {
|
||||
this.correctionPanel.style.width = `${hostRect.width}px`
|
||||
this.correctionPanel.style.height = `${hostRect.height}px`
|
||||
const hostRect = this.hostElement.getBoundingClientRect()
|
||||
this.scrollPanel.style.width = `${hostRect.width}px`
|
||||
this.scrollPanel.style.height = `${hostRect.height}px`
|
||||
}
|
||||
|
||||
this.enableMutationObserver()
|
||||
}
|
||||
|
||||
@ -929,11 +970,12 @@ class BesService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes previously highlighted grammar mistake and highlights new one.
|
||||
* Highlights given grammar mistake.
|
||||
*
|
||||
* @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 +984,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)
|
||||
@ -975,12 +1017,12 @@ class BesService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all grammar mistake markup positions.
|
||||
* Redraws all grammar mistake markup.
|
||||
*/
|
||||
repositionAllMarkup() {
|
||||
redrawAllMistakeMarkup() {
|
||||
this.ctx.clearRect(0, 0, this.canvasPanel.width, this.canvasPanel.height)
|
||||
this.results.forEach(result => {
|
||||
result.matches.forEach(match => this.addMistakeMarkup(match))
|
||||
result.matches.forEach(match => this.drawMistakeMarkup(match))
|
||||
})
|
||||
}
|
||||
|
||||
@ -1136,7 +1178,7 @@ class BesTreeService extends BesService {
|
||||
),
|
||||
match: match
|
||||
}
|
||||
this.addMistakeMarkup(m)
|
||||
this.drawMistakeMarkup(m)
|
||||
matches.push(m)
|
||||
})
|
||||
this.markProofed(node, matches)
|
||||
@ -1221,7 +1263,7 @@ class BesTreeService extends BesService {
|
||||
this.results = this.results.filter(
|
||||
result => !BesTreeService.isSameParagraph(result.element, el)
|
||||
)
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1357,12 +1399,16 @@ class BesTreeService extends BesService {
|
||||
const source = event?.detail !== 1 ? event?.detail : event
|
||||
const el = this.getBlockParent(source.targetElement || source.target)
|
||||
if (!el) return
|
||||
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 })
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1452,7 +1498,7 @@ class BesDOMService extends BesTreeService {
|
||||
*/
|
||||
onInput() {
|
||||
// Now that the text is done changing, we can correctly calculate markup position.
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
this.dismissPopup()
|
||||
// Defer grammar-checking to reduce stress on grammar-checking server.
|
||||
this.scheduleProofing(1000)
|
||||
@ -1534,7 +1580,7 @@ class BesCKService extends BesTreeService {
|
||||
// element, it will not be updated immediately.
|
||||
setTimeout(() => {
|
||||
// Now that the text is done changing, we can correctly calculate markup position.
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
|
||||
// Defer grammar-checking to reduce stress on grammar-checking server.
|
||||
this.scheduleProofing(1000)
|
||||
@ -1701,7 +1747,7 @@ class BesQuillService extends BesTreeService {
|
||||
this.clearProofing(domElement)
|
||||
|
||||
setTimeout(() => {
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
this.scheduleProofing(1000)
|
||||
}, 0)
|
||||
}
|
||||
@ -1887,7 +1933,7 @@ class BesPlainTextService extends BesService {
|
||||
),
|
||||
match: match
|
||||
}
|
||||
this.addMistakeMarkup(m)
|
||||
this.drawMistakeMarkup(m)
|
||||
matches.push(m)
|
||||
})
|
||||
this.markProofed(paragraphRange, matches)
|
||||
@ -1978,7 +2024,7 @@ class BesPlainTextService extends BesService {
|
||||
this.results = this.results.filter(
|
||||
result => !BesPlainTextService.isSameParagraph(result.range, range)
|
||||
)
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2021,12 +2067,16 @@ class BesPlainTextService extends BesService {
|
||||
const source = event?.detail !== 1 ? event?.detail : event
|
||||
const el = source.targetElement || source.target || this.hostElement
|
||||
if (!el) return
|
||||
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 })
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2146,7 +2196,7 @@ class BesDOMPlainTextService extends BesPlainTextService {
|
||||
delete this.textBeforeChange
|
||||
|
||||
// Now that the text is done changing, we can correctly calculate markup position.
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
this.dismissPopup()
|
||||
// Defer grammar-checking to reduce stress on grammar-checking server.
|
||||
this.scheduleProofing(1000)
|
||||
@ -2224,9 +2274,6 @@ class BesTAService extends BesPlainTextService {
|
||||
*/
|
||||
constructor(hostElement, eventSink) {
|
||||
super(hostElement, BesTAService.createTextElement(hostElement), eventSink)
|
||||
this.textElement.replaceChildren(
|
||||
document.createTextNode(this.hostElement.value)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2266,6 +2313,7 @@ class BesTAService extends BesPlainTextService {
|
||||
static createTextElement(hostElement) {
|
||||
const textElement = document.createElement('div')
|
||||
textElement.classList.add('bes-text-panel')
|
||||
textElement.replaceChildren(document.createTextNode(hostElement.value))
|
||||
BesTAService.setTextElementSize(hostElement, textElement)
|
||||
hostElement.parentNode.insertBefore(textElement, hostElement)
|
||||
return textElement
|
||||
@ -2415,7 +2463,7 @@ class BesTAService extends BesPlainTextService {
|
||||
})
|
||||
|
||||
// Now that the text is done changing, we can correctly calculate markup position.
|
||||
this.repositionAllMarkup()
|
||||
this.redrawAllMistakeMarkup()
|
||||
|
||||
// Defer grammar-checking to reduce stress on grammar-checking server.
|
||||
this.scheduleProofing(1000)
|
||||
|
40
styles.css
40
styles.css
@ -22,14 +22,8 @@
|
||||
background: rgb(255, 115, 0);
|
||||
}
|
||||
|
||||
.bes-canvas {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* Styles required to ensure full functionality and optimal user experience. */
|
||||
.bes-correction-panel-parent {
|
||||
.bes-correction-panel {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
float: left;
|
||||
@ -40,7 +34,7 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bes-correction-panel {
|
||||
.bes-scroll-panel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-color: transparent;
|
||||
@ -48,6 +42,12 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bes-canvas {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.bes-text-panel {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
@ -56,27 +56,3 @@
|
||||
border-color: transparent;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* TODO: Styles below should be removed after testing period is over */
|
||||
.resizable {
|
||||
overflow-x: scroll;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
border-radius: 3px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.mock-content {
|
||||
width: 1000px;
|
||||
height: 600px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user