Add alternative/lite Markdown editor
родител
26232618d4
ревизия
1b6e731c89
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 = "<i class=\"" + buttons[i]['icon'] + " fa-fw\"></i>";
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Toggle the setting to use the alternate note editor.
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function toggleeditor() {
|
||||
var toggle = app.toggle.get('.item-content[data-setting=editor] .toggle');
|
||||
console.log(toggle.checked);
|
||||
localStorage.setItem("alternateeditor", toggle.checked);
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
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/.
|
||||
-->
|
||||
<title>Editor</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../node_modules/@fortawesome/fontawesome-free/css/all.min.css">
|
||||
<script src="../js/markdowneditor.js"></script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0px;
|
||||
font-family: Roboto, Noto, Helvetica, Arial, sans-serif;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.editor-toolbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: 2.5rem;
|
||||
z-index: 99999;
|
||||
background-color: white;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
/* Following lines are from Framework7 .elevation-2 */
|
||||
-webkit-box-shadow: 0px 3px 1px -2px rgba(0,0,0,.2),0px 2px 2px 0px rgba(0,0,0,.14),0px 1px 5px 0px rgba(0,0,0,.12);
|
||||
box-shadow: 0px 3px 1px -2px rgba(0,0,0,.2),0px 2px 2px 0px rgba(0,0,0,.14),0px 1px 5px 0px rgba(0,0,0,.12);
|
||||
/* end Framework7 code */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
cursor: pointer;
|
||||
line-height: 2.5rem;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.toolbar-spacer {
|
||||
line-height: 2.5rem;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
color: rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
#note {
|
||||
width: 100%;
|
||||
height: calc(100% - 2rem);
|
||||
margin-top: 2rem;
|
||||
resize: none;
|
||||
border: none;
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
font-size: 1rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="editor-toolbar" id="toolbar">
|
||||
<!--<div class="toolbar-button" data-before="**" data-after="**">
|
||||
<i class="fas fa-bold fa-fw"></i>
|
||||
</div>-->
|
||||
</div>
|
||||
|
||||
<textarea id="note"></textarea>
|
||||
|
||||
<script>
|
||||
var editor;
|
||||
function initEditor(markdown) {
|
||||
document.getElementById('note').value = markdown;
|
||||
editor = new MarkdownEditor(
|
||||
document.getElementById('note'),
|
||||
document.getElementById("toolbar"),
|
||||
[
|
||||
{
|
||||
label: "Bold",
|
||||
icon: "fas fa-bold",
|
||||
before: "**",
|
||||
after: "**"
|
||||
},
|
||||
{
|
||||
label: "Italic",
|
||||
icon: "fas fa-italic",
|
||||
before: "*",
|
||||
after: "*"
|
||||
},
|
||||
{
|
||||
label: "Heading",
|
||||
icon: "fas fa-heading",
|
||||
linestart: "#",
|
||||
padspace: true,
|
||||
maximum: 6
|
||||
},
|
||||
{
|
||||
label: "Strikethrough",
|
||||
icon: "fas fa-strikethrough",
|
||||
before: "~~",
|
||||
after: "~~"
|
||||
},
|
||||
{
|
||||
spacer: true
|
||||
},
|
||||
{
|
||||
label: "Quote",
|
||||
icon: "fas fa-quote-left",
|
||||
linestart: "> ",
|
||||
padspace: false,
|
||||
maximum: 6
|
||||
},
|
||||
{
|
||||
label: "Checklist",
|
||||
icon: "fas fa-tasks",
|
||||
linestart: "- [ ]",
|
||||
padspace: true,
|
||||
maximum: 1
|
||||
},
|
||||
{
|
||||
label: "List",
|
||||
icon: "fas fa-list-ul",
|
||||
linestart: "-",
|
||||
padspace: true,
|
||||
maximum: 1
|
||||
}
|
||||
]);
|
||||
|
||||
window.addEventListener('keydown', function (event) {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
switch (String.fromCharCode(event.which).toLowerCase()) {
|
||||
case 's':
|
||||
event.preventDefault();
|
||||
window.parent.sync();
|
||||
window.parent.saveme();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getMarkdown() {
|
||||
return document.getElementById('note').value;
|
||||
}
|
||||
</script>
|
Зареждане…
Reference in New Issue