diff --git a/samples/div-contenteditable.html b/samples/div-contenteditable.html index 1a5bc4b..750b464 100644 --- a/samples/div-contenteditable.html +++ b/samples/div-contenteditable.html @@ -10,8 +10,8 @@ - - + +

This is an example of a simple <div contenteditable="true"> edit control. Edit the text, resize the control or browser window, scroll around, click...

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/service.js b/service.js index aee50e4..0e0b581 100644 --- a/service.js +++ b/service.js @@ -279,6 +279,7 @@ 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` + if (this.hostElement !== this.textElement) { this.textElement.scrollTop = this.hostElement.scrollTop this.textElement.scrollLeft = this.hostElement.scrollLeft @@ -314,11 +315,7 @@ class BesService { rect.left !== this.hostBoundingClientRect.left ) this.onReposition() - if ( - rect.width !== this.hostBoundingClientRect.width || - rect.height !== this.hostBoundingClientRect.height - ) - this.onResize() + this.onResize() this.hostBoundingClientRect = rect } @@ -330,62 +327,29 @@ class BesService { * @returns {Array} Grammar mistake highlight elements */ addMistakeMarkup(range, ruleId) { - const canvasPanelRect = this.canvasPanel.getBoundingClientRect() - const highlights = [] - this.canvasPanel.classList.add('bes-canvas') - - this.ctx.lineWidth = 1 + const scrollPanelRect = this.scrollPanel.getBoundingClientRect() + let highlights = [] + const dpr = window.devicePixelRatio + this.ctx.lineWidth = 1 * dpr this.ctx.strokeStyle = ruleId.startsWith('MORFOLOGIK_RULE') ? '#e91313' : '#269b26' - for (let rect of range.getClientRects()) { - const x = rect.left - canvasPanelRect.left - const y = rect.top - canvasPanelRect.top + rect.height - const width = rect.width - const height = rect.height - - const globalX = rect.left + window.scrollX - const globalY = rect.top + window.scrollY + const x = (rect.left - scrollPanelRect.left) * dpr + const y = (rect.top - scrollPanelRect.top) * dpr + const width = rect.width * dpr + const height = rect.height * dpr // Draw the underline this.ctx.beginPath() - this.ctx.moveTo(x, y) - this.ctx.lineTo(x + width, y) + this.ctx.moveTo(x, y + height) + this.ctx.lineTo(x + width, y + height) this.ctx.stroke() - const rectCoords = { x, y, width, height, globalX, globalY } - highlights.push(rectCoords) + highlights.push(rect) } - return highlights } - // addMistakeMarkup(range, ruleId) { - // const scrollPanelRect = this.scrollPanel.getBoundingClientRect() - // let highlights = [] - // for (let rect of range.getClientRects()) { - // const highlight = document.createElement('div') - // highlight.classList.add( - // ruleId.startsWith('MORFOLOGIK_RULE') - // ? 'bes-spelling-mistake' - // : 'bes-grammar-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 highlights - // } - // 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) - /** * Tests if given coordinate is inside of a rectangle. * @@ -394,28 +358,8 @@ class BesService { * @param {DOMRect} rect Rectangle * @returns */ - static isPointInRect(x, y, rect, canvasPanel) { - const canvasRect = canvasPanel.getBoundingClientRect() - const globalWidth = rect.x + rect.width - const globalHeight = rect.y - rect.height - - const newX = x - canvasRect.left - const newY = y - canvasRect.top - console.log( - 'x:', - newX, - 'y:', - newY, - 'globalWidth:', - globalWidth, - 'globalHeight:', - globalHeight - ) - console.log(rect) - return ( - rect.x <= newX && newX < globalWidth && globalHeight <= newY && newY < y - ) - // return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom + static isPointInRect(x, y, rect) { + return rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom } /** @@ -432,6 +376,9 @@ class BesService { this.scrollPanel.classList.add('bes-correction-panel-scroll') this.canvasPanel = document.createElement('canvas') + this.canvasPanel.classList.add('bes-canvas') + this.ctx = this.canvasPanel.getContext('2d') + this.ctx.scale(1, 1) panelParent.appendChild(this.correctionPanel) this.correctionPanel.appendChild(this.scrollPanel) @@ -446,6 +393,7 @@ class BesService { clearCorrectionPanel() { this.correctionPanel.remove() this.scrollPanel.remove() + this.canvasPanel.remove() } /** @@ -465,8 +413,16 @@ class BesService { this.scrollPanel.style.height = `${this.hostElement.scrollHeight}px` this.canvasPanel.style.width = `${this.hostElement.scrollWidth}px` this.canvasPanel.style.height = `${this.hostElement.scrollHeight}px` - this.ctx = this.canvasPanel.getContext('2d') - this.setCanvasDpr() + const dpr = window.devicePixelRatio + const canvasPanelRect = this.canvasPanel.getBoundingClientRect() + if ( + this.canvasPanel.width !== canvasPanelRect.width * dpr || + this.canvasPanel.height !== canvasPanelRect.height * dpr + ) { + this.canvasPanel.width = canvasPanelRect.width * dpr + this.canvasPanel.height = canvasPanelRect.height * dpr + this.repositionAllMarkup() + } if (this.isHostElementInline()) { const totalWidth = parseFloat(styles.paddingLeft) + @@ -482,21 +438,6 @@ class BesService { } } - /** - * Sets canvas panel device pixel ratio. - */ - setCanvasDpr() { - const dpr = window.devicePixelRatio || 1 - const canvasPanelRect = this.canvasPanel.getBoundingClientRect() - this.canvasPanel.width = canvasPanelRect.width * dpr - this.canvasPanel.height = canvasPanelRect.height * dpr - this.ctx.scale(dpr, dpr) - if (!this.ctx) { - this.ctx = this.canvasPanel.getContext('2d') - } - this.ctx.scale(dpr, dpr) - } - /** * Displays correction panel. * @@ -544,16 +485,16 @@ class BesService { * Updates all grammar mistake markup positions. */ repositionAllMarkup() { + const dpr = window.devicePixelRatio + this.ctx.clearRect( + 0, + 0, + this.canvasPanel.width * dpr, + this.canvasPanel.height * dpr + ) this.results.forEach(result => { result.matches.forEach(match => { - if (match.highlights) { - match.highlights.forEach(h => { - this.ctx.clearRect(h.x - 2, h.y - 2, h.width + 4, h.height) - }) - - delete match.highlights - // match.highlights.forEach(h => h.remove()) - } + if (match.highlights) delete match.highlights match.highlights = this.addMistakeMarkup( match.range, match.match.rule.id @@ -812,22 +753,22 @@ class BesTreeService extends BesService { * @param {Element} el DOM element we want to clean markup for */ clearMarkup(el) { + const dpr = window.devicePixelRatio this.results .filter(result => BesTreeService.isSameParagraph(result.element, el)) - .forEach(result => - result.matches.forEach(match => { - console.log(match) - if (match.highlights) { - // match.highlights.forEach(h => h.remove()) - match.highlights.forEach(h => { - console.log(h) - // Figure out why i need to add 2px to width - this.ctx.clearRect(h.x - 2, h.y - 2, h.width + 4, h.height) - }) - delete match.highlights - } - }) - ) + .forEach(result => { + let sourceRect = result.element.getBoundingClientRect() + let targetRect = this.canvasPanel.getBoundingClientRect() + let newX = sourceRect.left - targetRect.left + let newY = sourceRect.top - targetRect.top + this.ctx.clearRect( + newX * dpr, + newY * dpr, + sourceRect.width * dpr, + sourceRect.height * dpr + ) + delete result.matches + }) } /** @@ -967,14 +908,7 @@ class BesTreeService extends BesService { for (let result of this.results) { for (let m of result.matches) { for (let h of m.highlights) { - if ( - BesService.isPointInRect( - source.clientX, - source.clientY, - h, - this.canvasPanel - ) - ) { + if (BesService.isPointInRect(source.clientX, source.clientY, h)) { this.popupCorrectionPanel(el, m, source) return } @@ -1647,13 +1581,7 @@ class BesPlainTextService extends BesService { for (let result of this.results) { for (let m of result.matches) { for (let h of m.highlights) { - if ( - BesService.isPointInRect( - source.clientX, - source.clientY, - h.getBoundingClientRect() - ) - ) { + if (BesService.isPointInRect(source.clientX, source.clientY, h)) { this.popupCorrectionPanel(result.range, m, source) return } diff --git a/styles.css b/styles.css index 45341b8..8159993 100644 --- a/styles.css +++ b/styles.css @@ -8,6 +8,7 @@ cursor: text; } +/* TODO: Cleanup */ .bes-grammar-mistake { border-bottom: 2px solid #007bff; position: absolute; @@ -21,11 +22,13 @@ cursor: text; } +/* TODO: Cleanup */ .bes-spelling-mistake.bes-mistake-highlight-selected { background: #cc7024; opacity: 0.5; } +/* TODO: Cleanup */ .bes-grammar-mistake.bes-mistake-highlight-selected { background: #3691f3; opacity: 0.5;