From b062d9fa64c0a243aaf0468147a866012435c41d Mon Sep 17 00:00:00 2001 From: Eragon Date: Thu, 17 Nov 2022 22:00:44 +0100 Subject: [PATCH] editor: Fix bullet list creation if the line is empty --- app/static/scripts/editor.js | 222 +++++++++++++++++------------------ 1 file changed, 111 insertions(+), 111 deletions(-) diff --git a/app/static/scripts/editor.js b/app/static/scripts/editor.js index ec3b790..decaebe 100644 --- a/app/static/scripts/editor.js +++ b/app/static/scripts/editor.js @@ -5,153 +5,153 @@ Returns [the div.editor, the button, the textarea] */ function editor_event_source(event) { - let button = undefined; - let editor = undefined; + let button = undefined; + let editor = undefined; - /* Grab the button and the parent editor block. The onclick event itself - usually reports the SVG in the button as the source */ - let node = event.target || event.srcElement; - while(node != document.body) { - if(node.tagName == "BUTTON" && !button) { - button = node; - } - if(node.classList.contains("editor") && !editor) { - editor = node; - break; - } - node = node.parentNode; - } - if(!button || !editor) return; + /* Grab the button and the parent editor block. The onclick event itself + usually reports the SVG in the button as the source */ + let node = event.target || event.srcElement; + while(node != document.body) { + if(node.tagName == "BUTTON" && !button) { + button = node; + } + if(node.classList.contains("editor") && !editor) { + editor = node; + break; + } + node = node.parentNode; + } + if(!button || !editor) return; - const ta = editor.querySelector("textarea"); - return [editor, button, ta]; + const ta = editor.querySelector("textarea"); + return [editor, button, ta]; } /* Replace the range [start:end) with the new contents, and returns the new interval [start:end) (ie. the range where the contents are now located). */ function editor_replace_range(textarea, start, end, contents) { - ta.value = ta.value.substring(0, start) - + contents - + ta.value.substring(end); + ta.value = ta.value.substring(0, start) + + contents + + ta.value.substring(end); - return [start, start + contents.length]; + return [start, start + contents.length]; } /* Event handler that inserts the button's data-before and data-after attributes around the selection. */ function editor_insert_around(event) { - const [editor, button, ta] = editor_event_source(event); - ta.focus(); - let indexStart = ta.selectionStart; - let indexEnd = ta.selectionEnd; + const [editor, button, ta] = editor_event_source(event); + ta.focus(); + let indexStart = ta.selectionStart; + let indexEnd = ta.selectionEnd; - const before = button.dataset.before || ""; - const after = button.dataset.after || ""; + const before = button.dataset.before || ""; + const after = button.dataset.after || ""; - let [start, end] = editor_replace_range(ta, indexStart, indexEnd, - before + ta.value.substring(indexStart, indexEnd) + after); + let [start, end] = editor_replace_range(ta, indexStart, indexEnd, + before + ta.value.substring(indexStart, indexEnd) + after); - /* Restore selection */ - if(indexStart != indexEnd) { - ta.selectionStart = start; - ta.selectionEnd = end; - } - else { - ta.selectionStart = ta.selectionEnd =start + before.length; - } + /* Restore selection */ + if(indexStart != indexEnd) { + ta.selectionStart = start; + ta.selectionEnd = end; + } + else { + ta.selectionStart = ta.selectionEnd =start + before.length; + } } /* Event handler that modifies each line within the selection through a generic function. */ function editor_act_on_lines(event, fn) { - const [editor, button, ta] = editor_event_source(event); - ta.focus(); - let indexStart = ta.selectionStart; - let indexEnd = ta.selectionEnd; + const [editor, button, ta] = editor_event_source(event); + ta.focus(); + let indexStart = ta.selectionStart; + let indexEnd = ta.selectionEnd; - let firstLineIndex = ta.value.substring(0, indexStart).lastIndexOf('\n'); - if(firstLineIndex < 0) - firstLineIndex = 0; - else - firstLineIndex += 1; + let firstLineIndex = ta.value.substring(0, indexStart).lastIndexOf('\n'); + if(firstLineIndex < 0) + firstLineIndex = 0; + else + firstLineIndex += 1; - let lastLineIndex = ta.value.substring(indexEnd).indexOf('\n'); - if(lastLineIndex < 0) - lastLineIndex = ta.value.length; - else - lastLineIndex += indexEnd; + let lastLineIndex = ta.value.substring(indexEnd).indexOf('\n'); + if(lastLineIndex < 0) + lastLineIndex = ta.value.length; + else + lastLineIndex += indexEnd; - let lines = ta.value.substring(firstLineIndex, lastLineIndex).split('\n'); + let lines = ta.value.substring(firstLineIndex, lastLineIndex).split('\n'); - for(let i = 0; i < lines.length; i++) - lines[i] = fn(lines[i]); + for(let i = 0; i < lines.length; i++) + lines[i] = fn(lines[i]); - let [start, end] = editor_replace_range(ta, firstLineIndex, lastLineIndex, - lines.join('\n')); + let [start, end] = editor_replace_range(ta, firstLineIndex, lastLineIndex, + lines.join('\n')); - ta.selectionStart = start; - ta.selectionEnd = end; + ta.selectionStart = start; + ta.selectionEnd = end; } function editor_set_title(event, level, diff) { - editor_act_on_lines(event, function(line) { - /* Strip all the initial # (and count them) */ - let count = 0; - while(count < line.length && line[count] == '#') count++; + editor_act_on_lines(event, function(line) { + /* Strip all the initial # (and count them) */ + let count = 0; + while(count < line.length && line[count] == '#') count++; - let contents_index = count; - if(count < line.length && line[count] == ' ') contents_index++; - let contents = line.slice(contents_index); + let contents_index = count; + if(count < line.length && line[count] == ' ') contents_index++; + let contents = line.slice(contents_index); - if(level > 0 || count == 1 && diff == -1) { - /* Remove the title if the corresponding level is re-requested */ - if(count == level || count == 1 && diff == -1) - return contents; - /* Otherwise, add it */ - else - return '#'.repeat(level) + ' ' + contents; - } - else if(count > 0) { - /* Apply the difference */ - let new_level = Math.max(1, Math.min(6, count + diff)); - return '#'.repeat(new_level) + ' ' + contents; - } - return line; - }); + if(level > 0 || count == 1 && diff == -1) { + /* Remove the title if the corresponding level is re-requested */ + if(count == level || count == 1 && diff == -1) + return contents; + /* Otherwise, add it */ + else + return '#'.repeat(level) + ' ' + contents; + } + else if(count > 0) { + /* Apply the difference */ + let new_level = Math.max(1, Math.min(6, count + diff)); + return '#'.repeat(new_level) + ' ' + contents; + } + return line; + }); } function editor_quote(event) { - editor_act_on_lines(event, function(line) { + editor_act_on_lines(event, function(line) { /* Strip all the initial > (and count them) */ - let count = 0; + let count = 0; while(count < line.length && line[count] == '>') count++; - let contents_index = count; - if(count < line.length && line[count] == ' ') contents_index++; - let contents = line.slice(contents_index); + let contents_index = count; + if(count < line.length && line[count] == ' ') contents_index++; + let contents = line.slice(contents_index); - /* Apply the difference */ + /* Apply the difference */ return '>'.repeat(count + 1) + ' ' + contents; - }); + }); } function editor_bullet_list(event) { - editor_act_on_lines(event, function(line) { + editor_act_on_lines(event, function(line) { let ident_match = line.match(/^[\t]+/m) ?? ['']; let ident = ident_match[0]; let count = ident.length; const contents = line.slice(count); - if(count < line.length && line[count] != '-') return '- ' + contents; + if((count < line.length || count == 0) && line[count] != '-') return '- ' + contents; return ident + "\t" + contents; - }); + }); } previewTimeout = null; @@ -159,28 +159,28 @@ ta = document.querySelector(".editor textarea"); ta.addEventListener('keydown', function(e) { // Tab insert some spaces // Ctrl+Enter send the form - let keyCode = e.keyCode || e.which; - if (keyCode == 9) { + let keyCode = e.keyCode || e.which; + if (keyCode == 9) { // TODO Add one tab to selected text without replacing it - e.preventDefault(); + e.preventDefault(); - let start = e.target.selectionStart; - let end = e.target.selectionEnd; - // set textarea value to: text before caret + tab + text after caret - e.target.value = e.target.value.substring(0, start) + "\t" + e.target.value.substring(end); - e.target.selectionEnd = start + 1; - } - if (e.ctrlKey && keyCode == 13) { - let t = e.target; - while(! (t instanceof HTMLFormElement)) { - t = t.parentNode; - } - try { - t.submit(); - } catch(exception) { - t.submit.click(); - } - } + let start = e.target.selectionStart; + let end = e.target.selectionEnd; + // set textarea value to: text before caret + tab + text after caret + e.target.value = e.target.value.substring(0, start) + "\t" + e.target.value.substring(end); + e.target.selectionEnd = start + 1; + } + if (e.ctrlKey && keyCode == 13) { + let t = e.target; + while(! (t instanceof HTMLFormElement)) { + t = t.parentNode; + } + try { + t.submit(); + } catch(exception) { + t.submit.click(); + } + } // Set a timeout for refreshing the preview if (previewTimeout != null) {