Browse Source

Add alternative/lite Markdown editor

tags/v1.2.0
Skylar Ittner 9 months ago
parent
commit
1b6e731c89

+ 143
- 0
www/js/markdowneditor.js View File

@@ -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;
}

}

+ 16
- 0
www/js/settings.js View File

@@ -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);
}

+ 1
- 1
www/pages/editnote.html View File

@@ -30,7 +30,7 @@
<textarea id="note_content" style="display: none;" data-noteid="{{noteid}}">{{content}}</textarea>
<textarea id="orig_content" style="display: none;">{{content}}</textarea>

<iframe id="noteframe" src="pages/editor.html" style="width: 100%; height: 98%; border: 0px; padding: 0px; margin: 0px;"></iframe>
<iframe id="noteframe" src="{{editorframe}}" style="width: 100%; height: 98%; border: 0px; padding: 0px; margin: 0px;"></iframe>

</div>


www/pages/editor.html → www/pages/editor_full.html View File

@@ -56,6 +56,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
"bold",
"italic",
"heading",
"strikethrough",
"|",
"quote",
"unordered-list",

+ 152
- 0
www/pages/editor_lite.html View File

@@ -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>

+ 28
- 5
www/pages/settings.html View File

@@ -20,17 +20,40 @@
<div class="list media-list">
<ul>
{{#each settings}}
<li class="item-content" data-setting="{{setting}}" onclick="{{onclick}}">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">{{title}}</div>
<li>
{{#if toggle}}
<div class="item-content" data-setting="{{setting}}">
<div class="item-inner">
<div style="display: flex; justify-content: between;">
<div class="item-title">
{{title}}
</div>
<div class="item-after" onclick="{{onclick}}">
<label class="toggle toggle-init">
<input type="checkbox" {{#if checked}}checked{{/if}}>
<span class="toggle-icon"></span>
</label>
</div>
</div>
<div class="item-text">{{text}}</div>
</div>
<div class="item-text">{{text}}</div>
</div>
{{else}}
<div class="item-content" data-setting="{{setting}}" onclick="{{onclick}}">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">{{title}}</div>
</div>
<div class="item-text">{{text}}</div>
</div>
</div>
{{/if}}
</li>
{{/each}}
</ul>
</div>
</div>

<script src="js/settings.js"></script>

</div>

+ 20
- 2
www/routes.js View File

@@ -83,6 +83,14 @@ var routes = [
title: "Sign in to a different account",
onclick: "router.navigate('/setup/0')"
},
{
setting: "editor",
title: "Use alternative editor",
text: "Turn on if you're having issues editing notes.",
toggle: true,
checked: localStorage.getItem("alternateeditor") == "true",
onclick: "toggleeditor();"
},
{
setting: "versions",
title: "NotePost app v1.1.0",
@@ -112,7 +120,17 @@ var routes = [
},
{
path: '/editnote',
templateUrl: './pages/editnote.html',
name: 'editnote'
name: 'editnote',
async: function (routeTo, routeFrom, resolve, reject) {
var editor = "pages/editor_full.html";
var alternative = "pages/editor_lite.html";
resolve({
templateUrl: './pages/editnote.html'
}, {
context: {
editorframe: localStorage.getItem("alternateeditor") == "true" ? alternative : editor
}
});
}
}
];

Loading…
Cancel
Save