diff --git a/images/checkmark-svgrepo-com.svg b/images/checkmark-svgrepo-com.svg new file mode 100644 index 0000000..e745874 --- /dev/null +++ b/images/checkmark-svgrepo-com.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/images/error-svgrepo-com.svg b/images/error-svgrepo-com.svg new file mode 100644 index 0000000..1c0b29e --- /dev/null +++ b/images/error-svgrepo-com.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/images/loading-svgrepo-com.svg b/images/loading-svgrepo-com.svg new file mode 100644 index 0000000..9e6f7e6 --- /dev/null +++ b/images/loading-svgrepo-com.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/images/mistake-svgrepo-com.svg b/images/mistake-svgrepo-com.svg new file mode 100644 index 0000000..cb27ec4 --- /dev/null +++ b/images/mistake-svgrepo-com.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/service.js b/service.js index cdcc0f6..3ac0f15 100644 --- a/service.js +++ b/service.js @@ -12,10 +12,11 @@ class BesService { this.hostElement = hostElement this.timer = null this.children = [] - const { correctionPanel, scrollPanel } = + const { correctionPanel, scrollPanel, statusIcon } = this.createCorrectionPanel(hostElement) this.correctionPanel = correctionPanel this.scrollPanel = scrollPanel + this.statusIcon = statusIcon this.offsetTop = null this.originalSpellcheck = hostElement.spellcheck this.abortController = new AbortController() @@ -39,6 +40,9 @@ class BesService { static register(hostElement) { let service = new BesService(hostElement) service.proof(hostElement) + if (service.statusIcon.classList.contains('bes-status-loading')) { + service.updateStatusIcon('bes-status-success') + } return service } @@ -68,6 +72,8 @@ class BesService { * @returns {Array} Markup of text to proof using BesStr */ async proof(node) { + this.updateStatusIcon('bes-status-loading') + let mistakesCounter = 0 switch (node.nodeType) { case Node.TEXT_NODE: return [{ text: node.textContent, node: node, markup: false }] @@ -105,13 +111,14 @@ class BesService { fetch(request, { signal }) .then(response => { if (!response.ok) { - // TODO: Make connectivity and BesStr issues non-fatal. But show an error sign somewhere in the UI. + this.updateStatusIcon('bes-status-error') throw new Error('Backend server response was not OK') } return response.json() }) .then(responseData => { let matches = [] + mistakesCounter += responseData.matches.length responseData.matches.forEach(match => { let range = document.createRange() @@ -160,11 +167,11 @@ class BesService { match: match }) }) - this.markProofed(node, matches) + this.markProofed(node, matches, mistakesCounter) }) .catch(error => { if (error.name === 'AbortError') return - // TODO: Make parsing issues non-fatal. But show an error sign somewhere in the UI. + this.updateStatusIcon('bes-status-error') throw new Error( 'Parsing backend server response failed: ' + error ) @@ -204,7 +211,11 @@ class BesService { panelParent.appendChild(correctionPanel) hostElement.parentElement.insertBefore(panelParent, hostElement) - return { correctionPanel, scrollPanel } + const statusIcon = document.createElement('div') + statusIcon.classList.add('bes-status-icon') + correctionPanel.appendChild(statusIcon) + + return { correctionPanel, scrollPanel, statusIcon } } /** @@ -256,13 +267,16 @@ class BesService { * @param {Element} el DOM element that was checked * @param {Array} matches Grammar mistakes */ - markProofed(el, matches) { + markProofed(el, matches, mistakesCounter) { this.removeChild(el) this.children.push({ isProofed: true, element: el, matches: matches }) + + if (mistakesCounter > 0) this.updateStatusIcon('bes-status-mistakes') + else this.updateStatusIcon('bes-status-success') } /** @@ -331,6 +345,19 @@ class BesService { return { clientRects, highlights } } + updateStatusIcon(status) { + const statuses = [ + 'bes-status-loading', + 'bes-status-success', + 'bes-status-mistakes', + 'bes-status-error' + ] + statuses.forEach(statusClass => { + this.statusIcon.classList.remove(statusClass) + }) + this.statusIcon.classList.add(status) + } + /** * Tests if given element is block element. * @@ -536,12 +563,7 @@ class BesService { setCorrectionPanelSize(hostElement, correctionPanel, scrollPanel) { const styles = window.getComputedStyle(hostElement) - const totalWidth = - parseFloat(styles.width) + - parseFloat(styles.marginLeft) + - parseFloat(styles.marginRight) + - parseFloat(styles.paddingLeft) + - parseFloat(styles.paddingRight) + const totalWidth = parseFloat(styles.width) const totalHeight = parseFloat(styles.height) + parseFloat(styles.marginTop) + @@ -550,6 +572,10 @@ class BesService { parseFloat(styles.paddingBottom) correctionPanel.style.width = totalWidth + 'px' correctionPanel.style.height = totalHeight + 'px' + correctionPanel.style.marginLeft = styles.marginLeft + correctionPanel.style.marginRight = styles.marginRight + correctionPanel.style.paddingLeft = styles.paddingLeft + correctionPanel.style.paddingRight = styles.paddingRight scrollPanel.style.height = hostElement.scrollHeight + 'px' } diff --git a/styles.css b/styles.css index 2c76b72..b92c621 100644 --- a/styles.css +++ b/styles.css @@ -64,3 +64,29 @@ outline: initial; padding: 0px; } + +.bes-status-icon { + position: absolute; + right: 5px; + bottom: 5px; + width: 30px; + height: 30px; + background-size: contain; + background-repeat: no-repeat; +} + +.bes-status-icon.bes-status-success { + background-image: url('/images/checkmark-svgrepo-com.svg'); +} + +.bes-status-icon.bes-status-loading { + background-image: url('/images/loading-svgrepo-com.svg'); +} + +.bes-status-icon.bes-status-error { + background-image: url('/images/error-svgrepo-com.svg'); +} + +.bes-status-icon.bes-status-mistakes { + background-image: url('/images/mistake-svgrepo-com.svg'); +}