/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ class MarkdownEditor { constructor(textarea, toolbar, buttons) { this.textarea = textarea; this.toolbar = toolbar; if (typeof buttons != "undefined") { for (var i = 0; i < buttons.length; i++) { var div = document.createElement('div'); if (buttons[i]['spacer']) { div.className = "toolbar-spacer"; div.innerHTML = "|"; } else { div.className = "toolbar-button"; if (typeof buttons[i]['linestart'] == "string") { div.setAttribute("data-linestart", buttons[i]['linestart']); div.setAttribute("data-padspace", buttons[i]['padspace'] ? 1 : 0); div.setAttribute("data-maximum", buttons[i]['maximum']); } else { div.setAttribute("data-before", buttons[i]['before']); div.setAttribute("data-after", buttons[i]['after']); } div.innerHTML = ""; } toolbar.appendChild(div); } } var btns = toolbar.getElementsByClassName("toolbar-button"); var editorobj = this; for (var i = 0; i < btns.length; i++) { btns[i].addEventListener('click', function () { if (editorobj.textarea.value.length == editorobj.getCursorPosition()[0] && editorobj.textarea.value.length == editorobj.getCursorPosition()[1]) { //return; } if (typeof this.dataset.linestart == "string") { editorobj.formatline(this.dataset.linestart, this.dataset.padspace, this.dataset.maximum); } else { editorobj.format(this.dataset.before, this.dataset.after); } editorobj.textarea.focus(); }, false); } } formatline(start, padspace, maximum) { var text = this.getText(); var cursor = this.getCursorPosition(); var startofline = cursor[0]; while (startofline - 1 > 0 && text[startofline - 1] != "\n") { startofline--; } console.log("startofline", startofline, text[startofline - 1]); // Check if the line is already formatted and count how many times var falsestart = startofline; var count = 0; while (falsestart != text.length && text.slice(falsestart, falsestart + start.length) == start) { falsestart += start.length; count++; } console.log("falsestart", falsestart); // Check if we're allowed to add another formatting mark if (count > 0) { if (maximum <= count) { return; } } // If it's the first one and a space is needed after if (count == 0 && padspace == 1) { start += " "; } text = [text.slice(0, startofline), start, text.slice(startofline)].join(''); this.textarea.value = text; this.textarea.selectionStart = cursor[0] + start.length; this.textarea.selectionEnd = cursor[0] + start.length; } format(before, after) { var text = this.getText(); var cursor = this.getCursorPosition(); var origcursor = this.getCursorPosition(); if (cursor[0] == cursor[1]) { // Walk backwards and forwards to get the whole word while (cursor[0] - 1 >= 0 && text[cursor[0] - 1] != " " && text[cursor[0] - 1] != "\n") { cursor[0]--; } while (cursor[1] < text.length && text[cursor[1]] != " " && text[cursor[1]] != "\n") { cursor[1]++; } } var subject = text.substring(cursor[0], cursor[1]); if (subject.startsWith(before) && subject.endsWith(after)) { // Don't do anything return; } if (subject == "") { subject = " "; origcursor[0]++; origcursor[1]++; } subject = before + subject + after; text = [text.slice(0, cursor[0]), subject, text.slice(cursor[1])].join(''); this.textarea.value = text; this.textarea.selectionStart = origcursor[0] + before.length; this.textarea.selectionEnd = origcursor[1] + before.length; } getCursorPosition() { var start = this.textarea.selectionStart; var end = this.textarea.selectionEnd; console.log([start, end], this.textarea.value.length); return [start, end]; } /** * Get the textarea value, with an extra newline if needed. * @returns string */ getText() { var text = this.textarea.value; // if (text[text.length - 1] != "\n") { // text += "\n"; // } return text; } }