diff --git a/index.html b/index.html index 2215911..4faf85c 100644 --- a/index.html +++ b/index.html @@ -9,8 +9,10 @@ -
Tukaj vpišite besedilo ki ga želite popraviti.
- + +
Popravite kar želite.
Na mizo nisem položil knjigo.
diff --git a/online-editor.js b/online-editor.js index ced3bc1..6e356ea 100644 --- a/online-editor.js +++ b/online-editor.js @@ -1,22 +1,21 @@ +let editors = {} // Collection of all editors on page + window.onload = () => { - const btnCheck = document.getElementById('btn-check') - btnCheck.addEventListener('click', checkText) + // Search and prepare all our editors found in the document. + document.querySelectorAll('.online-editor').forEach(ed => { + let editor = { + ignoreInput: false, + timer: null + } + editors[ed.id] = editor + checkText(ed.id) - const textArea = document.getElementById('besana-editor') - textArea.addEventListener('click', e => { - handleClick(e) + ed.addEventListener('beforeinput', e => beforeTextChange(ed.id, e), false) + + ed.addEventListener('click', e => { + handleClick(e) + }) }) - - let timerId = null - - // textArea.addEventListener('focus', () => { - // timerId = setTimeout(checkText, 2000) - // }) - - // textArea.addEventListener('input', () => { - // clearTimeout(timerId) - // timerId = setTimeout(checkText, 2000) - // }) } function handleClick(e) { @@ -31,16 +30,88 @@ function handleClick(e) { } } -function checkText() { - const textArea = document.getElementById('besana-editor') - const textAreaContent = textArea?.innerHTML - const text = createFirstParagraph(textAreaContent) - const paragraphs = separateParagraphs(text) - const modifiedParagraphs = paragraphs.map( - async paragraph => await ajaxCheck(paragraph) - ) - console.log(modifiedParagraphs) - textArea.innerHTML = modifiedParagraphs.join('') +async function checkText(editorId) { + let text = '' + let editor = editors[editorId] + let ed = document.getElementById(editorId) + let paragraphs = [] + let divElements = ed.getElementsByTagName('div') + if (divElements.length === 0) { + // Editor is empty or has plain text only + text = ed.textContent + } else { + // Editor contains
paragraphs + for (const para of divElements) { + if (para.getAttribute('data-info') === 'checked') continue + let p = { start: text.length } + text += para.textContent.replace(/\r?\n/g, ' ') + text += '\n\n' + p.end = text.length + paragraphs.push(p) + } + } + let result = await ajaxCheck(text) + result.matches.sort((a, b) => a.offset < b.offset ? -1 : a.offset > b.offset ? +1 : 0) + if (divElements.length === 0) { + // Editor is empty or has plain text only + let textOut = '' + let offset = 0 + for (var mistakeIdx = 0; mistakeIdx < result.matches.length; ++mistakeIdx) { + let mistakeStart = result.matches[mistakeIdx].offset + let mistakeEnd = mistakeStart + result.matches[mistakeIdx].length + textOut += text.substring(offset, mistakeStart) + textOut += '' + text.substring(mistakeStart, mistakeEnd) + '' + offset = mistakeEnd + } + textOut += text.substring(offset) + editor.ignoreInput = true + ed.innerHTML = textOut + editor.ignoreInput = false + } else { + // Editor contains
paragraphs + let idx = 0 + let mistakeIdx = 0 + for (const para of divElements) { + if (para.getAttribute('data-info') === 'checked') continue + let p = paragraphs[idx++] + let textOut = '' + let offset = p.start + for (; mistakeIdx < result.matches.length && result.matches[mistakeIdx].offset < p.end; ++mistakeIdx) { + let mistakeStart = result.matches[mistakeIdx].offset + let mistakeEnd = mistakeStart + result.matches[mistakeIdx].length + textOut += text.substring(offset, mistakeStart) + textOut += '' + text.substring(mistakeStart, mistakeEnd) + '' + offset = mistakeEnd + } + textOut += text.substring(offset, p.end - 2 /* Compensate for '\n\n' we appended to each paragraph. */) + editor.ignoreInput = true + para.innerHTML = textOut + editor.ignoreInput = false + para.setAttribute('data-info', 'checked') + } + } +} + +function beforeTextChange(editorId, event) +{ + let editor = editors[editorId] + if (editor.ignoreInput) return + + if (editor.timer) clearTimeout(editor.timer) + editor.timer = setTimeout(function(){ checkText(editorId) }, 1000) + + let ed = document.getElementById(editorId) + event.getTargetRanges().forEach(range => { + if (range.startContainer === ed) + return + for (var el = range.startContainer; el ; el = el.nextSibling) { + for (var el2 = el; el2 && el2 !== ed; el2 = el2.parentElement) { + if (!(el2 instanceof HTMLElement) || el2.tagName !== 'DIV') continue + el2.removeAttribute('data-info') + } + if (el === range.endContainer) break + } + }) } function createFirstParagraph(text) { @@ -61,7 +132,7 @@ function separateParagraphs(text) { async function ajaxCheck(paragraph) { const url = 'http://localhost:225/api/v2/check' const data = { - format: 'html', + format: 'plain', text: paragraph, language: 'sl', level: 'picky' @@ -73,20 +144,18 @@ async function ajaxCheck(paragraph) { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData }) - fetch(request) + return fetch(request) .then(response => { - console.log(response.status, response.statusText) if (!response.ok) { - throw new Error('Network response was not ok') + throw new Error('Backend server response was not OK') } - console.log(response) return response.json() }) + .then(data => { + return data + }) .catch(error => { - console.error( - 'Napaka pri pošiljanju zahteve za preverjanje besedila', - error - ) + throw new Error('Request to backend server failed: ' + error) }) }