Tukaj vpišite besedilo ki ga želite popraviti.
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.
diff --git a/service2.js b/service2.js
index 2ca3ed3..b51f7d1 100644
--- a/service2.js
+++ b/service2.js
@@ -25,6 +25,7 @@ window.addEventListener('scroll', () =>
class BesService {
constructor(hostElement) {
this.hostElement = hostElement
+ this.results = [] // Results of grammar-checking, one per each block/paragraph of text
this.createCorrectionPanel()
// Disable browser built-in spell-checker to prevent collision with our grammar markup.
@@ -52,7 +53,7 @@ class BesService {
* Called initially when grammar-checking run is started
*/
onStartProofing() {
- this.proofingCount = 0 // Ref-count how many grammar-checking blocks of text are active
+ this.proofingCount = 1 // Ref-count how many grammar-checking blocks of text are active
this.proofingError = null // The first non-fatal error in grammar-checking run
this.proofingMatches = 0 // Number of grammar mistakes detected in entire grammar-checking run
this.updateStatusIcon('bes-status-loading', 'Besana preverja pravopis.')
@@ -126,6 +127,15 @@ class BesService {
// Scroll panel is "position: absolute", we need to keep it aligned with the host element.
this.scrollPanel.style.top = `${-this.hostElement.scrollTop}px`
this.scrollPanel.style.left = `${-this.hostElement.scrollLeft}px`
+
+ // Markup is in a "position:absolute"
element requiring repositioning when scrolling host element or window.
+ // It is defered to reduce stress in a flood of scroll events.
+ // TODO: We could technically just update scrollTop and scrollLeft of all markup rects for even better performance?
+ if (this.scrollTimeout) clearTimeout(this.scrollTimeout)
+ this.scrollTimeout = setTimeout(() => {
+ this.repositionAllMarkup()
+ delete this.scrollTimeout
+ }, 500)
}
/**
@@ -134,6 +144,46 @@ class BesService {
onResize() {
this.setCorrectionPanelSize()
this.setStatusDivPosition()
+
+ // When window is resized, host element might resize too.
+ // This may cause text to re-wrap requiring markup repositioning.
+ this.repositionAllMarkup()
+ }
+
+ /**
+ * Creates grammar mistake markup in DOM.
+ *
+ * @param {Range} range Grammar mistake range
+ * @returns {Object} Client rectangles and grammar mistake highlight elements
+ */
+ addMistakeMarkup(range) {
+ const clientRects = range.getClientRects()
+ const scrollPanelRect = this.scrollPanel.getBoundingClientRect()
+ let highlights = []
+ for (let i = 0, n = clientRects.length; i < n; ++i) {
+ const rect = clientRects[i]
+ const highlight = document.createElement('div')
+ highlight.classList.add('bes-typo-mistake')
+ highlight.style.left = `${rect.left - scrollPanelRect.left}px`
+ highlight.style.top = `${rect.top - scrollPanelRect.top}px`
+ highlight.style.width = `${rect.width}px`
+ highlight.style.height = `${rect.height}px`
+ this.scrollPanel.appendChild(highlight)
+ highlights.push(highlight)
+ }
+ return { clientRects, highlights }
+ }
+
+ /**
+ * Tests if given coordinate is inside of a rectangle.
+ *
+ * @param {Number} x X coordinate
+ * @param {Number} y Y coordinate
+ * @param {DOMRect} rect Rectangle
+ * @returns
+ */
+ static isPointInRect(x, y, rect) {
+ return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom
}
/**
@@ -239,7 +289,6 @@ class BesService {
class BesDOMService extends BesService {
constructor(hostElement) {
super(hostElement)
- this.results = [] // Results of grammar-checking, one per each block of text
this.onBeforeInput = this.onBeforeInput.bind(this)
this.hostElement.addEventListener('beforeinput', this.onBeforeInput)
this.onInput = this.onInput.bind(this)
@@ -271,33 +320,6 @@ class BesDOMService extends BesService {
super.unregister()
}
- /**
- * Called to report scrolling
- */
- onScroll() {
- super.onScroll()
-
- // Markup is in a "position:absolute"
element requiring repositioning when scrolling host element or window.
- // It is defered to reduce stress in a flood of scroll events.
- // TODO: We could technically just update scrollTop and scrollLeft of all markup rects for even better performance?
- if (this.scrollTimeout) clearTimeout(this.scrollTimeout)
- this.scrollTimeout = setTimeout(() => {
- this.repositionAllMarkup()
- delete this.scrollTimeout
- }, 500)
- }
-
- /**
- * Called to report resizing
- */
- onResize() {
- super.onResize()
-
- // When window is resized, host element might resize too.
- // This may cause text to re-wrap requiring markup re
- this.repositionAllMarkup()
- }
-
/**
* Called to report the text is about to change
*
@@ -312,13 +334,9 @@ class BesDOMService extends BesService {
// Remove markup of all blocks of text that are about to change.
let blockElements = new Set()
event.getTargetRanges().forEach(range => {
- BesDOMService.getNodesInRange(range).forEach(el => {
- if (
- el === this.hostElement ||
- Array.from(this.hostElement.childNodes).includes(el)
- )
- blockElements.add(this.getBlockParent(el))
- })
+ BesDOMService.getNodesInRange(range).forEach(el =>
+ blockElements.add(this.getBlockParent(el))
+ )
})
blockElements.forEach(block => this.clearProofing(block))
}
@@ -343,11 +361,7 @@ class BesDOMService extends BesService {
proofAll() {
this.onStartProofing()
this.proofNode(this.hostElement, this.abortController)
- if (this.proofingCount == 0) {
- // No text blocks were discovered for proofing. onProofingProgress() will not be called
- // and we need to notify manually.
- this.onEndProofing()
- }
+ this.onProofingProgress(0)
}
/**
@@ -365,15 +379,18 @@ class BesDOMService extends BesService {
case Node.ELEMENT_NODE:
if (this.isBlockElement(node)) {
// Block elements are grammar-checked independently.
- if (this.isProofed(node))
+ this.onProofing()
+ let result = this.getProofing(node)
+ if (result != null) {
+ this.onProofingProgress(result.matches.length)
return [{ text: `<${node.tagName}/>`, node: node, markup: true }]
+ }
let data = []
for (const el2 of node.childNodes)
data = data.concat(this.proofNode(el2, abortController))
if (data.some(x => !x.markup && !/^\s*$/.test(x.text))) {
// Block element contains some text.
- this.onProofing()
const signal = abortController.signal
fetch(
new Request(besUrl + '/check', {
@@ -477,10 +494,12 @@ class BesDOMService extends BesService {
* Tests if given block element has already been grammar-checked.
*
* @param {Element} el DOM element to check
- * @returns {Boolean} true if the element has already been grammar-checked; false otherwise.
+ * @returns {*} Result of grammar check if the element has already been grammar-checked; null otherwise.
*/
- isProofed(el) {
- return this.results?.find(result => result.element === el) != null
+ getProofing(el) {
+ return this.results.find(result =>
+ BesDOMService.isSameParagraph(result.element, el)
+ )
}
/**
@@ -504,51 +523,9 @@ class BesDOMService extends BesService {
*/
clearProofing(el) {
this.clearMarkup(el)
- this.results = this.results?.filter(result => result.element !== el)
- }
-
- /**
- * Creates grammar mistake markup in DOM.
- *
- * @param {Range} range Grammar mistake range
- * @returns {Object} Client rectangles and grammar mistake highlight elements
- */
- addMistakeMarkup(range) {
- const clientRects = range.getClientRects()
- const scrollPanelRect = this.scrollPanel.getBoundingClientRect()
- let highlights = []
- for (let i = 0, n = clientRects.length; i < n; ++i) {
- const rect = clientRects[i]
- const highlight = document.createElement('div')
- highlight.classList.add('bes-typo-mistake')
- const topPosition = rect.top - scrollPanelRect.top
- const leftPosition = rect.left - scrollPanelRect.left
- highlight.style.left = `${leftPosition}px`
- highlight.style.top = `${topPosition}px`
- highlight.style.width = `${rect.width}px`
- highlight.style.height = `${rect.height}px`
- this.scrollPanel.appendChild(highlight)
- highlights.push(highlight)
- }
- return { clientRects, highlights }
- }
-
- /**
- * Updates grammar mistake markup positions.
- *
- * @param {Element} el DOM element we want to update markup for
- *
- * TODO: Unused
- */
- repositionMarkup(el) {
- let result = this.results?.find(result => result.element === el)
- if (!result) return
- result.matches.forEach(match => {
- const { clientRects, highlights } = this.addMistakeMarkup(match.range)
- match.rects = clientRects
- if (match.highlights) match.highlights.forEach(h => h.remove())
- match.highlights = highlights
- })
+ this.results = this.results.filter(
+ result => !BesDOMService.isSameParagraph(result.element, el)
+ )
}
/**
@@ -571,30 +548,27 @@ class BesDOMService extends BesService {
* @param {Element} el DOM element we want to clean markup for
*/
clearMarkup(el) {
- let result = this.results?.find(result => result.element === el)
- if (!result) return
- result.matches.forEach(match => {
- if (match.highlights) {
- match.highlights.forEach(h => h.remove())
- delete match.highlights
- }
- })
+ this.results
+ .filter(result => BesDOMService.isSameParagraph(result.element, el))
+ .forEach(result =>
+ result.matches.forEach(match => {
+ if (match.highlights) {
+ match.highlights.forEach(h => h.remove())
+ delete match.highlights
+ }
+ })
+ )
}
/**
- * Clears all grammar mistake markup.
+ * Tests if given block elements represent the same block of text
*
- * TODO: Unused
+ * @param {Element} el1 DOM element
+ * @param {Element} el2 DOM element
+ * @returns {Boolean} true if block elements are the same
*/
- clearAllMarkup() {
- this.results.forEach(result => {
- result.matches.forEach(match => {
- if (match.highlights) {
- match.highlights.forEach(h => h.remove())
- delete match.highlights
- }
- })
- })
+ static isSameParagraph(el1, el2) {
+ return el1 === el2
}
/**
@@ -714,23 +688,21 @@ class BesDOMService extends BesService {
*/
onClick(event) {
const source = event?.detail !== 1 ? event?.detail : event
- const target = this.getBlockParent(source.targetElement || source.target)
- if (!target) return
+ const el = this.getBlockParent(source.targetElement || source.target)
+ if (!el) return
- const matches = this.results?.find(
- child => child.element === target
+ const matches = this.results.find(child =>
+ BesDOMService.isSameParagraph(child.element, el)
)?.matches
if (matches) {
- const popup = document.querySelector('bes-popup-el')
for (let m of matches) {
if (m.rects) {
for (let r of m.rects) {
- if (
- BesDOMService.isPointInRect(source.clientX, source.clientY, r)
- ) {
+ if (BesService.isPointInRect(source.clientX, source.clientY, r)) {
+ const popup = document.querySelector('bes-popup-el')
popup.changeMessage(m.match.message)
popup.appendReplacements(
- target,
+ el,
m,
this,
this.hostElement.contentEditable !== 'false'
@@ -745,18 +717,6 @@ class BesDOMService extends BesService {
BesPopup.hide()
}
- /**
- * Tests if given coordinate is inside of a rectangle.
- *
- * @param {Number} x X coordinate
- * @param {Number} y Y coordinate
- * @param {DOMRect} rect Rectangle
- * @returns
- */
- static isPointInRect(x, y, rect) {
- return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom
- }
-
/**
* Replaces grammar checking match with a suggestion provided by grammar checking service.
*
@@ -770,13 +730,7 @@ class BesDOMService extends BesService {
this.clearProofing(el)
match.range.deleteContents()
match.range.insertNode(document.createTextNode(replacement))
- this.onStartProofing()
- this.proofNode(el, this.abortController)
- if (this.proofingCount == 0) {
- // No text blocks were discovered for proofing. onProofingProgress() will not be called
- // and we need to notify manually.
- this.onEndProofing()
- }
+ this.proofAll()
}
}
@@ -919,7 +873,7 @@ class BesPopup extends HTMLElement {
/**
* Adds a grammar mistake suggestion.
*
- * @param {Element} el Block element containing the grammar mistake
+ * @param {*} el Block element/paragraph containing the grammar mistake
* @param {*} match Grammar checking rule match
* @param {BesService} service Grammar checking service
* @param {Boolean} allowReplacements Host element is mutable and grammar mistake may be replaced by suggestion