From 0d8d6e165a7842377ee25653dd602c73a0284edb Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Thu, 1 Feb 2024 09:43:18 +0100 Subject: [PATCH] Separate internal and LanguageTool data formats This allows a bit simpler code and less clutter in the LanguageTool communication. --- online-editor.js | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/online-editor.js b/online-editor.js index 7dbee7c..7f4d776 100644 --- a/online-editor.js +++ b/online-editor.js @@ -24,7 +24,7 @@ async function besCheckText(el) { switch (el.nodeType) { case Node.TEXT_NODE: - return [{ text: el.textContent, el: el }] + return [{ text: el.textContent, el: el, markup: false }] case Node.ELEMENT_NODE: let data = [] @@ -36,15 +36,15 @@ async function besCheckText(el) { case 'inline': case 'inline-block': - data.splice(0, 0, { markup: '<'+el.tagName+'>', el: el }) - data.splice(data.length, 0, { markup: '' }) + data.splice(0, 0, { text: '<'+el.tagName+'>', el: el, markup: true }) + data.splice(data.length, 0, { text: '', markup: true }) return data; default: let regAllWhitespace = /^\s*$/ - if (data.some(x => 'text' in x && !regAllWhitespace.test(x.text))) { + if (data.some(x => !x.markup && !regAllWhitespace.test(x.text))) { const requestData = { format: 'plain', - data: JSON.stringify({annotation: data}), + data: JSON.stringify({annotation: data.map(x => x.markup ? { markup: x.text } : { text: x.text })}), language: 'sl', level: 'picky' } @@ -62,34 +62,27 @@ async function besCheckText(el) return response.json() }) .then(responseData => { - // responseData.matches.sort((a, b) => a.offset < b.offset ? -1 : a.offset > b.offset ? +1 : 0) + // Reverse sort grammar mistakes for easier markup insertion later. + // When we start inserting grammar mistakes at the back, indexes before that remain valid. responseData.matches.sort((a, b) => a.offset < b.offset ? +1 : a.offset > b.offset ? -1 : 0); responseData.matches.forEach(match => { let range = document.createRange() // Locate start of the grammar mistake. - for (let idx = 0, startingOffset = 0; ; ) { - if ('text' in data[idx]) { - if (startingOffset <= match.offset && match.offset < startingOffset + data[idx].text.length) { - range.setStart(data[idx].el, match.offset - startingOffset) - break - } - startingOffset += data[idx++].text.length + for (let idx = 0, startingOffset = 0; ; startingOffset += data[idx++].text.length) { + if (!data[idx].markup && /*startingOffset <= match.offset &&*/ match.offset < startingOffset + data[idx].text.length) { + range.setStart(data[idx].el, match.offset - startingOffset) + break } - else startingOffset += data[idx++].markup.length } // Locate end of the grammar mistake. let endOffset = match.offset + match.length - for (let idx = 0, startingOffset = 0; ; ) { - if ('text' in data[idx]) { - if (startingOffset <= endOffset && endOffset <= startingOffset + data[idx].text.length) { - range.setEnd(data[idx].el, endOffset - startingOffset) - break - } - startingOffset += data[idx++].text.length + for (let idx = 0, startingOffset = 0; ; startingOffset += data[idx++].text.length) { + if (!data[idx].markup && /*startingOffset <= endOffset &&*/ endOffset <= startingOffset + data[idx].text.length) { + range.setEnd(data[idx].el, endOffset - startingOffset) + break } - else startingOffset += data[idx++].markup.length } const span = document.createElement('span') @@ -98,7 +91,7 @@ async function besCheckText(el) // Dirty hack, copied from: https://stackoverflow.com/questions/67634286/invalidstateerror-failed-to-execute-surroundcontents-on-range-the-range-ha span.appendChild(range.extractContents()); range.insertNode(span); - + // This is a better way to apply span elements, // but it doesnt work when the range has partially selected a non-Text node. // range.surroundContents(span) @@ -106,14 +99,14 @@ async function besCheckText(el) }) .catch(error => { // TODO: Make parsing issues non-fatal. - throw new Error('Request to backend server failed: ' + error) + throw new Error('Parsing backend server response failed: ' + error) }) } - return [{ markup: '<'+el.tagName+'/>', el: el }] + return [{ text: '<'+el.tagName+'/>', el: el, markup: true }] } default: - return [{ markup: '', el: el }] + return [{ text: '', el: el, markup: true }] } }