2023-01-26 12:01:15 +01:00
|
|
|
var defaultsettings =
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-11-08 08:56:38 +01:00
|
|
|
fontsize: "16px",
|
|
|
|
lineheight: "24px",
|
2023-10-10 17:11:39 +02:00
|
|
|
margins: "20%",
|
2024-01-09 11:09:57 +01:00
|
|
|
fontfamily: "helvetica,system-ui",
|
2023-01-25 21:40:34 +01:00
|
|
|
savedelay: 2000,
|
2023-01-18 12:34:55 +01:00
|
|
|
defaultpreviewinsplit: false,
|
2023-01-25 09:32:44 +01:00
|
|
|
tagautocomplete: false,
|
2023-10-10 17:11:39 +02:00
|
|
|
enablenetwork: true,
|
2023-05-05 16:36:02 +02:00
|
|
|
titlebydefault: false,
|
2023-09-23 09:02:02 +02:00
|
|
|
linksinnewtab: true,
|
2023-10-09 12:45:25 +02:00
|
|
|
colors: true,
|
2023-10-27 16:59:14 +02:00
|
|
|
password: "",
|
2023-11-06 09:59:01 +01:00
|
|
|
sync: false,
|
2023-11-07 15:28:32 +01:00
|
|
|
tagsinlists: true,
|
2023-12-12 09:57:29 +01:00
|
|
|
uselinkpopup: true,
|
|
|
|
autosorttodo: true
|
2023-01-18 12:34:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
//builtin
|
2024-01-16 15:15:23 +01:00
|
|
|
var markerslist = ["* ", "- ", " * ", " - ", ">> ", "> ", "=> ", "— ", "[ ] ", " ", "• ", "- [ ]", "[x] ", "- [x]"];
|
2023-01-18 12:34:55 +01:00
|
|
|
var codelanguages = ["xml", "js", "sql"];
|
2023-11-09 22:46:16 +01:00
|
|
|
var tagmark = "+";
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
// globals
|
|
|
|
var currentnote = null;
|
|
|
|
var fileindex = 0;
|
2023-01-22 21:17:23 +01:00
|
|
|
var workerid = null;
|
2023-01-18 12:34:55 +01:00
|
|
|
var backup = "";
|
|
|
|
var localdata = null;
|
2023-01-25 15:41:21 +01:00
|
|
|
var saved = true;
|
2023-10-27 12:43:03 +02:00
|
|
|
var lastsaved = "";
|
2023-01-25 21:40:34 +01:00
|
|
|
var pending = false;
|
2023-01-18 12:34:55 +01:00
|
|
|
var settings = null;
|
2023-01-21 16:07:14 +01:00
|
|
|
var tags = null;
|
2023-01-18 12:34:55 +01:00
|
|
|
|
2023-01-26 12:01:15 +01:00
|
|
|
var stat =
|
2023-01-26 12:00:32 +01:00
|
|
|
{
|
|
|
|
ses:
|
|
|
|
{
|
|
|
|
q: 0,
|
2023-02-03 12:56:31 +01:00
|
|
|
t: timestamp(),
|
|
|
|
d: 0
|
2023-01-26 12:00:32 +01:00
|
|
|
},
|
|
|
|
cur:
|
|
|
|
{
|
|
|
|
q: 0,
|
2023-02-03 12:56:31 +01:00
|
|
|
t: timestamp(),
|
|
|
|
d: 0
|
2023-01-26 12:00:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
var commands = [
|
|
|
|
{
|
|
|
|
hint: "Close menu"
|
|
|
|
},
|
2023-11-13 15:23:59 +01:00
|
|
|
{
|
|
|
|
shortcut: "ctrl+shift+P",
|
|
|
|
hint: "Command palette",
|
|
|
|
allowunsaved: true,
|
|
|
|
action: commandpalette,
|
|
|
|
excludepalette: true
|
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
shortcut: "ctrl+p",
|
|
|
|
hint: "Show notes list",
|
|
|
|
action: searchandloadnote
|
|
|
|
},
|
2023-11-13 15:23:59 +01:00
|
|
|
{
|
|
|
|
shortcut: "ctrl+n",
|
|
|
|
hint: "New note",
|
|
|
|
action: startnewnote
|
|
|
|
},
|
2023-11-15 08:43:01 +01:00
|
|
|
{
|
|
|
|
shortcut: "ctrl+shift+N",
|
|
|
|
hint: "Quick new note",
|
|
|
|
action: quicknewnote
|
|
|
|
},
|
2023-11-13 15:23:59 +01:00
|
|
|
{
|
|
|
|
hint: "Force save",
|
|
|
|
action: save,
|
|
|
|
shortcut: "ctrl+s",
|
|
|
|
allowunsaved: true
|
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
hint: "Share note",
|
2023-01-27 09:05:22 +01:00
|
|
|
action: share,
|
|
|
|
allowunsaved: true
|
2023-01-27 09:22:09 +01:00
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
hint: "Share note (html)",
|
|
|
|
action: sharehtml
|
2023-01-27 09:22:09 +01:00
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-21 21:05:39 +01:00
|
|
|
shortcut: "ctrl+g",
|
2023-01-18 12:34:55 +01:00
|
|
|
hint: "Find in notes",
|
|
|
|
action: showgrep
|
|
|
|
},
|
|
|
|
{
|
|
|
|
shortcut: "ctrl+i",
|
|
|
|
hint: "Toggle title",
|
2023-01-27 09:05:22 +01:00
|
|
|
action: toggletitle,
|
|
|
|
allowunsaved: true
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
shortcut: "ctrl+m",
|
|
|
|
hint: "Toggle preview",
|
2023-01-27 09:05:22 +01:00
|
|
|
action: togglepreview,
|
|
|
|
allowunsaved: true
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
2023-02-05 10:04:07 +01:00
|
|
|
{
|
|
|
|
shortcut: "ctrl+shift+M",
|
|
|
|
hint: "Toggle preview with merged subnotes",
|
|
|
|
action: togglepreviewwithsubs,
|
|
|
|
allowunsaved: true
|
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
shortcut: "ctrl+d",
|
|
|
|
hint: "Delete note",
|
2023-02-01 13:54:49 +01:00
|
|
|
action: deletecurrentnote
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
2023-09-29 17:57:22 +02:00
|
|
|
hint: "Restore current note",
|
2023-01-18 12:34:55 +01:00
|
|
|
action: restore
|
|
|
|
},
|
2023-07-20 09:52:17 +02:00
|
|
|
{
|
|
|
|
hint: "Insert markdown header",
|
|
|
|
action: insertheader,
|
|
|
|
allowunsaved: true
|
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
hint: "Show help",
|
|
|
|
action: showhelp
|
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Search tags",
|
|
|
|
action: searchtags,
|
|
|
|
shortcut: "ctrl+shift+T"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Toggle split view",
|
|
|
|
action: togglesplit
|
|
|
|
},
|
|
|
|
{
|
2023-01-21 16:07:14 +01:00
|
|
|
hint: "Load previous note",
|
|
|
|
action: loadprevious,
|
2023-12-06 09:26:08 +01:00
|
|
|
shortcut: "alt+ArrowLeft"
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
2023-07-05 13:40:13 +02:00
|
|
|
{
|
|
|
|
hint: "Load next note",
|
|
|
|
action: loadnext,
|
2023-12-06 09:26:08 +01:00
|
|
|
shortcut: "alt+ArrowRight"
|
2023-07-05 13:40:13 +02:00
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
hint: "Settings",
|
2023-01-26 12:01:15 +01:00
|
|
|
action: editsettings
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
2023-09-23 23:00:39 +02:00
|
|
|
{
|
|
|
|
hint: "Change a setting",
|
|
|
|
action: changesetting
|
|
|
|
},
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
hint: "Restore default settings",
|
2023-01-26 12:01:15 +01:00
|
|
|
action: restoresettings
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
2023-01-21 16:07:14 +01:00
|
|
|
hint: "Note outline",
|
|
|
|
action: showoutline,
|
2023-01-27 09:05:22 +01:00
|
|
|
shortcut: "ctrl+o",
|
|
|
|
allowunsaved: true
|
2023-01-18 12:34:55 +01:00
|
|
|
},
|
|
|
|
{
|
2023-01-30 10:01:14 +01:00
|
|
|
hint: "Show connected notes",
|
|
|
|
action: shownotelinks,
|
2023-01-30 08:48:15 +01:00
|
|
|
shortcut: "ctrl+l"
|
2023-01-21 16:07:14 +01:00
|
|
|
},
|
2023-01-24 22:17:48 +01:00
|
|
|
{
|
2023-11-09 09:57:24 +01:00
|
|
|
hint: "Show stats",
|
2023-01-24 22:17:48 +01:00
|
|
|
action: showinfo,
|
2023-01-26 08:36:12 +01:00
|
|
|
shortcut: "ctrl+w",
|
|
|
|
allowunsaved: true
|
2023-01-25 23:50:48 +01:00
|
|
|
},
|
2023-01-27 15:46:25 +01:00
|
|
|
{
|
|
|
|
hint: "Toggle spell check",
|
|
|
|
action: togglespellcheck,
|
|
|
|
allowunsaved: true,
|
|
|
|
shortcut: "F7"
|
2023-01-30 10:01:14 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Create subnote from selection",
|
|
|
|
action: createsubnote
|
|
|
|
},
|
|
|
|
{
|
2023-02-01 13:54:49 +01:00
|
|
|
hint: "Merge subnote",
|
2023-01-30 10:01:14 +01:00
|
|
|
action: includesub
|
2023-01-30 10:16:07 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Comment selection",
|
|
|
|
action: comment
|
2023-02-01 13:54:49 +01:00
|
|
|
},
|
|
|
|
{
|
2023-02-03 12:56:31 +01:00
|
|
|
hint: "Download current note",
|
2023-02-01 13:54:49 +01:00
|
|
|
action: downloadnote
|
|
|
|
},
|
|
|
|
{
|
2023-02-03 12:56:31 +01:00
|
|
|
hint: "Download current note with merged subnotes",
|
2023-02-01 13:54:49 +01:00
|
|
|
action: downloadnotewithsubs
|
|
|
|
},
|
2023-02-21 12:05:04 +01:00
|
|
|
{
|
2023-11-06 11:49:45 +01:00
|
|
|
hint: "Download all notes (md files in zip archive)",
|
2023-10-23 14:46:35 +02:00
|
|
|
action: downloadnotes,
|
|
|
|
shortcut: "ctrl+shift+S"
|
2023-02-21 12:05:04 +01:00
|
|
|
},
|
2023-11-06 11:49:45 +01:00
|
|
|
{
|
|
|
|
hint: "Download all notes (html files in zip archive)",
|
|
|
|
action: downloadhtmlnotes
|
|
|
|
},
|
2023-02-01 13:54:49 +01:00
|
|
|
{
|
2023-10-27 16:59:14 +02:00
|
|
|
hint: "Download all notes (json file)",
|
|
|
|
action: downloadnotesjson
|
2023-02-03 12:56:31 +01:00
|
|
|
},
|
|
|
|
{
|
2023-10-27 16:59:14 +02:00
|
|
|
hint: "Download all notes (encrypted json file)",
|
|
|
|
action: downloadencrypted,
|
|
|
|
remoteonly: true
|
2023-05-15 14:49:52 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Insert text in todo",
|
2024-01-17 09:09:25 +01:00
|
|
|
action: promptinserttodo
|
2023-06-19 14:10:23 +02:00
|
|
|
},
|
2023-07-13 13:55:52 +02:00
|
|
|
{
|
|
|
|
hint: "Edit pgp keys",
|
|
|
|
action: editpgpkeys
|
2023-09-21 20:56:13 +02:00
|
|
|
},
|
|
|
|
{
|
2023-09-21 21:29:08 +02:00
|
|
|
hint: "Decrypt note",
|
|
|
|
action: decryptnote
|
2023-09-27 09:05:45 +02:00
|
|
|
},
|
2023-09-29 17:57:22 +02:00
|
|
|
{
|
|
|
|
hint: "Restore deleted note",
|
|
|
|
action: restoredeleted
|
2023-10-01 10:21:41 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Notes by size",
|
|
|
|
action: notesbysize
|
2023-10-09 12:45:50 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Replace",
|
|
|
|
shortcut: "ctrl+h",
|
|
|
|
action: searchandreplace
|
2023-10-25 11:28:12 +02:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Sort todo.txt list",
|
2023-12-12 09:57:29 +01:00
|
|
|
action: sortcurrentastodo
|
2023-11-09 09:57:24 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Sort text",
|
|
|
|
action: sortselection,
|
|
|
|
allowunsaved: true
|
2023-11-13 18:09:46 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Show backlinks",
|
|
|
|
action: backlinks
|
2023-12-12 17:40:42 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
hint: "Remove completed tasks",
|
|
|
|
action: purgetodo,
|
|
|
|
allowunsaved: true
|
2023-01-25 23:50:48 +01:00
|
|
|
}];
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
var snippets = [
|
|
|
|
{
|
|
|
|
command: "/code",
|
|
|
|
hint: "Code block",
|
|
|
|
insert: "```\n\n```",
|
|
|
|
cursor: -4
|
|
|
|
},
|
|
|
|
{
|
|
|
|
command: "/date",
|
|
|
|
hint: "Current date",
|
2023-07-05 09:07:25 +02:00
|
|
|
insert: (new Date).toISOString().substring(0, 10),
|
2023-01-18 12:34:55 +01:00
|
|
|
cursor: 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
command: "/bonjour",
|
|
|
|
hint: "Standard answer (fr)",
|
|
|
|
insert: "Bonjour ,\n\n\n\nBien cordialement,\nSimon",
|
|
|
|
cursor: -29
|
|
|
|
},
|
|
|
|
{
|
|
|
|
command: "/hello",
|
|
|
|
hint: "Standard answer (en)",
|
|
|
|
insert: "Hello ,\n\n\n\nKind regards,\nSimon",
|
|
|
|
cursor: -24
|
2023-01-19 14:06:19 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
command: "/-",
|
|
|
|
hint: "Dialog mark",
|
|
|
|
insert: "— ",
|
|
|
|
cursor: 0
|
2023-02-02 14:49:04 +01:00
|
|
|
},
|
2023-02-28 10:04:46 +01:00
|
|
|
{
|
2023-09-25 13:22:22 +02:00
|
|
|
command: "/comment",
|
2023-09-29 11:38:13 +02:00
|
|
|
hint: "Comment",
|
2023-02-28 10:04:46 +01:00
|
|
|
insert: "<!--\n\n-->",
|
|
|
|
cursor: -4
|
2023-11-29 12:10:07 +01:00
|
|
|
},
|
|
|
|
{
|
2023-11-30 12:28:18 +01:00
|
|
|
command: "/x",
|
2023-11-29 12:10:07 +01:00
|
|
|
hint: "Mark todo entry done",
|
|
|
|
insert: "x " + (new Date).toISOString().substring(0, 10) + " "
|
2023-01-18 12:34:55 +01:00
|
|
|
}];
|
|
|
|
|
2024-01-12 13:46:48 +01:00
|
|
|
function purgetodo() {
|
2023-12-12 17:40:42 +01:00
|
|
|
if (currentistodo() && confirm("Remove completed tasks?"))
|
|
|
|
{
|
|
|
|
seteditorcontent(currentnote.content.replace(/\nx .*/g, ""));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-11 21:11:27 +02:00
|
|
|
function seteditorcontent(content, silent)
|
2023-09-24 22:00:20 +02:00
|
|
|
{
|
|
|
|
md.value = content;
|
2023-10-12 14:21:55 +02:00
|
|
|
applycolors();
|
2023-10-11 21:11:27 +02:00
|
|
|
if (!silent)
|
|
|
|
{
|
|
|
|
datachanged();
|
|
|
|
}
|
2023-12-20 08:39:41 +01:00
|
|
|
resize();
|
2023-09-24 22:00:20 +02:00
|
|
|
}
|
|
|
|
|
2023-09-21 21:29:08 +02:00
|
|
|
function encryptstring(str)
|
|
|
|
{
|
|
|
|
var key = localStorage.getItem("pgpkeys").split("-----BEGIN PGP PRIVATE KEY BLOCK-----")[0];
|
|
|
|
var publicKey = null;
|
|
|
|
return openpgp.readKey({ armoredKey: key })
|
|
|
|
.then(res =>
|
|
|
|
{
|
|
|
|
publicKey = res;
|
|
|
|
return openpgp.createMessage({ text: str });
|
|
|
|
})
|
|
|
|
.then(message =>
|
|
|
|
{
|
|
|
|
return openpgp.encrypt({
|
|
|
|
message: message,
|
|
|
|
encryptionKeys: publicKey });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function decryptstring(str)
|
|
|
|
{
|
2023-09-21 21:45:09 +02:00
|
|
|
if (!str.startsWith("-----BEGIN PGP MESSAGE-----"))
|
|
|
|
{
|
2023-09-21 21:55:59 +02:00
|
|
|
// console.log(str + ": string is not encrypted");
|
2023-09-21 21:45:09 +02:00
|
|
|
return Promise.resolve(str);
|
|
|
|
}
|
2024-01-03 14:33:42 +01:00
|
|
|
|
2023-09-21 21:29:08 +02:00
|
|
|
var key = localStorage.getItem("pgpkeys").split("-----END PGP PUBLIC KEY BLOCK-----")[1];
|
|
|
|
var privateKey = null;
|
|
|
|
return openpgp.readKey({ armoredKey: key })
|
|
|
|
.then(res =>
|
|
|
|
{
|
|
|
|
privateKey = res;
|
|
|
|
return openpgp.readMessage({ armoredMessage: str })
|
|
|
|
})
|
|
|
|
.then(message =>
|
|
|
|
{
|
|
|
|
return openpgp.decrypt({
|
|
|
|
message: message,
|
|
|
|
decryptionKeys: privateKey });
|
|
|
|
})
|
|
|
|
.then(decrypted =>
|
|
|
|
{
|
|
|
|
const chunks = [];
|
2023-10-19 15:28:53 +02:00
|
|
|
for (const chunk of decrypted.data) {
|
|
|
|
chunks.push(chunk);
|
|
|
|
}
|
|
|
|
return chunks.join('');
|
2023-09-21 21:29:08 +02:00
|
|
|
})
|
|
|
|
}
|
2023-07-04 17:15:34 +02:00
|
|
|
|
2023-01-30 10:01:14 +01:00
|
|
|
function getnote(title)
|
|
|
|
{
|
|
|
|
return localdata.find(note => note.title == title);
|
|
|
|
}
|
|
|
|
|
2023-03-06 09:51:44 +01:00
|
|
|
function getrangecontent(range)
|
|
|
|
{
|
|
|
|
return md.value.substring(range.start, range.end);
|
|
|
|
}
|
|
|
|
|
2023-12-04 10:40:28 +01:00
|
|
|
function currentrange()
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
start: md.selectionStart,
|
|
|
|
end: md.selectionEnd
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-11-07 11:48:37 +01:00
|
|
|
function createsubnote()
|
2023-01-30 10:01:14 +01:00
|
|
|
{
|
2023-11-07 11:48:37 +01:00
|
|
|
var title = prompt("Subnote tite:");
|
|
|
|
if (!title)
|
2023-02-01 13:54:49 +01:00
|
|
|
{
|
2023-11-07 11:48:37 +01:00
|
|
|
showtemporaryinfo("No title provided");
|
|
|
|
setpos(md.selectionStart);
|
|
|
|
md.focus();
|
2023-02-01 13:54:49 +01:00
|
|
|
}
|
2023-11-07 11:48:37 +01:00
|
|
|
else if (getnote(title))
|
2023-01-30 10:01:14 +01:00
|
|
|
{
|
2023-11-07 11:48:37 +01:00
|
|
|
showtemporaryinfo("'" + title + "' already exists");
|
|
|
|
setpos(md.selectionStart);
|
|
|
|
md.focus();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-12-04 10:40:57 +01:00
|
|
|
var range = currentrange();
|
2023-11-07 11:48:37 +01:00
|
|
|
var content = getrangecontent(range);
|
|
|
|
var newnote =
|
2023-01-30 10:01:14 +01:00
|
|
|
{
|
2023-11-07 11:48:37 +01:00
|
|
|
title: title,
|
|
|
|
content: content
|
2023-01-30 10:01:14 +01:00
|
|
|
}
|
2023-11-07 11:48:37 +01:00
|
|
|
localdata.unshift(newnote);
|
|
|
|
seteditorcontent(md.value.substring(0, range.start)
|
|
|
|
+ "[[" + title + "]]"
|
|
|
|
+ md.value.substring(range.end));
|
|
|
|
}
|
2023-01-30 10:16:07 +01:00
|
|
|
}
|
|
|
|
|
2023-11-07 11:48:37 +01:00
|
|
|
|
2023-01-30 10:16:07 +01:00
|
|
|
function comment()
|
|
|
|
{
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(md.value.substring(0, md.selectionStart)
|
|
|
|
+ "<!-- "
|
|
|
|
+ md.value.substring(md.selectionStart, md.selectionEnd)
|
|
|
|
+ " -->"
|
|
|
|
+ md.value.substring(md.selectionEnd));
|
2023-01-30 10:01:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function includesub()
|
|
|
|
{
|
|
|
|
var range = linkrangeatpos();
|
|
|
|
if (range)
|
|
|
|
{
|
|
|
|
var title = linkatpos();
|
2023-02-02 08:50:17 +01:00
|
|
|
if (confirm("Replace [[" + title + "]] by its content?"))
|
2023-01-30 10:01:14 +01:00
|
|
|
{
|
2023-02-01 13:54:49 +01:00
|
|
|
var subnote = getnote(title);
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(md.value.substring(0, range.start)
|
|
|
|
+ subnote.content
|
|
|
|
+ md.value.substring(range.end));
|
2023-01-30 10:01:14 +01:00
|
|
|
|
2023-02-02 08:50:17 +01:00
|
|
|
if (confirm("Delete '" + title + "'?"))
|
2023-02-01 13:54:49 +01:00
|
|
|
{
|
|
|
|
deletenote(subnote);
|
2023-02-02 08:43:30 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-30 10:01:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-27 15:46:25 +01:00
|
|
|
function togglespellcheck()
|
|
|
|
{
|
|
|
|
md.spellcheck = !md.spellcheck;
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:56:31 +01:00
|
|
|
function formatsize(size)
|
|
|
|
{
|
|
|
|
var unit = "b";
|
|
|
|
if (size > 1024)
|
|
|
|
{
|
|
|
|
size /= 1024;
|
|
|
|
unit = "kb";
|
|
|
|
}
|
|
|
|
if (size > 1024)
|
|
|
|
{
|
|
|
|
size /= 1024;
|
|
|
|
unit = "mb";
|
|
|
|
}
|
2023-10-19 15:28:53 +02:00
|
|
|
return size.toFixed(2) + " " + unit;
|
2023-02-03 12:56:31 +01:00
|
|
|
}
|
|
|
|
|
2023-08-28 11:21:39 +02:00
|
|
|
function pospercent()
|
|
|
|
{
|
|
|
|
return md.value.length > 0 ?(100 * md.selectionStart / md.value.length).toFixed(2) : 100;
|
|
|
|
}
|
|
|
|
|
2023-01-24 22:17:48 +01:00
|
|
|
function showinfo()
|
|
|
|
{
|
|
|
|
var tags = gettags(currentnote);
|
2023-01-26 12:00:32 +01:00
|
|
|
showtemporaryinfo(
|
2023-01-26 12:01:15 +01:00
|
|
|
[
|
2023-11-19 21:41:44 +01:00
|
|
|
"saved: " + saved + (lastsaved? " (" + lastsaved + ")": ""),
|
2023-10-27 16:59:14 +02:00
|
|
|
"sync: " + (settings.sync ? "en" : "dis") + "abled",
|
2023-01-26 12:00:32 +01:00
|
|
|
"title: " + currentnote.title,
|
2023-10-27 12:43:03 +02:00
|
|
|
"line count: " + md.value.split("\n").length,
|
|
|
|
"word count: " + getwords(),
|
2023-08-28 11:21:39 +02:00
|
|
|
"cursor position: " + md.selectionStart + " (" + pospercent() + "%)",
|
2023-01-26 12:00:32 +01:00
|
|
|
(tags ? "tags: " + tags : ""),
|
|
|
|
"current note start: " + stat.cur.t,
|
|
|
|
"current note queries: " + stat.cur.q,
|
2023-02-03 12:56:31 +01:00
|
|
|
"current note data sent: " + formatsize(stat.cur.d),
|
2023-01-26 12:00:32 +01:00
|
|
|
"session start: " + stat.ses.t,
|
2023-02-03 12:56:31 +01:00
|
|
|
"session queries: " + stat.ses.q,
|
2023-10-27 12:43:03 +02:00
|
|
|
"session data sent: " + formatsize(stat.ses.d),
|
|
|
|
"notes count: " + localdata.length,
|
|
|
|
"spell check: " + (md.spellcheck ? "en" : "dis") + "abled"
|
2023-05-15 15:20:36 +02:00
|
|
|
].join("\n"));
|
2023-01-24 22:17:48 +01:00
|
|
|
}
|
|
|
|
|
2023-01-23 12:50:52 +01:00
|
|
|
function savesettings()
|
|
|
|
{
|
|
|
|
window.localStorage.setItem("settings", JSON.stringify(settings));
|
|
|
|
}
|
|
|
|
|
2023-01-30 08:48:15 +01:00
|
|
|
function descendants(note)
|
|
|
|
{
|
2023-02-04 16:13:55 +01:00
|
|
|
var list = [note];
|
|
|
|
var result = [];
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-02-04 16:13:55 +01:00
|
|
|
while (list.length)
|
2023-01-30 08:48:15 +01:00
|
|
|
{
|
2023-02-04 16:13:55 +01:00
|
|
|
var current = list.shift();
|
|
|
|
if (result.indexOf(current) == -1)
|
2023-01-30 09:18:23 +01:00
|
|
|
{
|
2023-02-04 16:13:55 +01:00
|
|
|
result.push(current);
|
|
|
|
list = list.concat(children(current));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2023-01-30 08:48:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function children(note)
|
|
|
|
{
|
|
|
|
return (note.content
|
|
|
|
.match(/\[\[([^\]]*)\]\]/g) || [])
|
2023-02-04 16:13:55 +01:00
|
|
|
.map(l => l.replace("[[", "").replace("]]", ""))
|
2023-10-26 10:13:33 +02:00
|
|
|
.filter(l => !l.includes("(deleted)"))
|
2023-02-04 16:13:55 +01:00
|
|
|
.map(l => getnote(l));
|
2023-01-30 08:48:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function parents(note)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-30 08:48:15 +01:00
|
|
|
return localdata
|
2023-02-04 16:13:55 +01:00
|
|
|
.filter(n => n.content.indexOf("[[" + note.title + "]]") != -1);
|
2023-01-30 08:48:15 +01:00
|
|
|
}
|
2023-01-27 09:22:09 +01:00
|
|
|
|
2023-02-04 16:13:55 +01:00
|
|
|
function connected(note)
|
2023-01-30 08:48:15 +01:00
|
|
|
{
|
2023-02-04 16:13:55 +01:00
|
|
|
var list = [note];
|
|
|
|
var result = [];
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-02-04 16:13:55 +01:00
|
|
|
while (list.length)
|
2023-01-30 09:18:23 +01:00
|
|
|
{
|
2023-02-04 16:13:55 +01:00
|
|
|
var current = list.shift();
|
|
|
|
if (result.indexOf(current) == -1)
|
|
|
|
{
|
|
|
|
result.push(current);
|
|
|
|
list = list.concat(children(current)).concat(parents(current));
|
|
|
|
}
|
2023-01-30 09:18:23 +01:00
|
|
|
}
|
2023-02-04 16:13:55 +01:00
|
|
|
return result;
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-09-24 21:54:12 +02:00
|
|
|
function toggleeditor(hidden)
|
|
|
|
{
|
|
|
|
md.hidden = hidden;
|
|
|
|
|
|
|
|
if (settings.colors)
|
|
|
|
{
|
|
|
|
colored.hidden = hidden;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-19 15:28:53 +02:00
|
|
|
function id(note)
|
|
|
|
{
|
|
|
|
return localdata.indexOf(note);
|
|
|
|
}
|
|
|
|
|
2023-02-04 16:13:55 +01:00
|
|
|
function shownotelinks()
|
|
|
|
{
|
2023-02-05 10:04:07 +01:00
|
|
|
if (settings.enablenetwork)
|
|
|
|
{
|
|
|
|
networkpage.hidden = false;
|
2023-09-24 21:54:12 +02:00
|
|
|
toggleeditor(true);
|
2023-02-05 10:04:07 +01:00
|
|
|
|
|
|
|
var nodes = [];
|
|
|
|
var edges = [];
|
|
|
|
|
|
|
|
var list = [currentnote];
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-02-05 10:04:07 +01:00
|
|
|
while (list.length)
|
|
|
|
{
|
|
|
|
var current = list.shift();
|
|
|
|
if (!nodes.find(n => n.id == id(current)))
|
|
|
|
{
|
|
|
|
nodes.push(
|
|
|
|
{
|
|
|
|
id: id(current),
|
|
|
|
label: current.title
|
|
|
|
});
|
|
|
|
|
|
|
|
var buddies = children(current).concat(parents(current));
|
|
|
|
|
|
|
|
list = list.concat(buddies);
|
|
|
|
|
|
|
|
buddies.
|
|
|
|
forEach(buddy => {
|
|
|
|
if (!edges.find(edge => (edge.to == id(current) && edge.from == id(buddy)) || (edge.to == id(buddy) && edge.from == id(current))))
|
|
|
|
{
|
|
|
|
edges.push({
|
|
|
|
from: id(current),
|
|
|
|
to: id(buddy)
|
|
|
|
});
|
2023-09-11 09:57:00 +02:00
|
|
|
}
|
2023-02-05 10:04:07 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var data = {
|
|
|
|
nodes: nodes,
|
|
|
|
edges: edges
|
|
|
|
};
|
|
|
|
|
2023-11-15 21:45:45 +01:00
|
|
|
// todo: use theme colors
|
2023-09-11 09:57:00 +02:00
|
|
|
var options =
|
2023-02-05 10:04:07 +01:00
|
|
|
{
|
|
|
|
nodes:
|
|
|
|
{
|
|
|
|
color:
|
|
|
|
{
|
2023-11-15 21:24:38 +01:00
|
|
|
background: "white",
|
2023-11-15 21:45:45 +01:00
|
|
|
border: "black",
|
2023-02-05 10:04:07 +01:00
|
|
|
},
|
|
|
|
font:
|
|
|
|
{
|
2023-11-15 21:45:45 +01:00
|
|
|
color: "black",
|
2023-11-10 10:12:29 +01:00
|
|
|
size: 16
|
2023-02-05 10:04:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-02-05 10:04:07 +01:00
|
|
|
var graph = new vis.Network(network, data, options);
|
|
|
|
graph.on("click", function(event)
|
|
|
|
{
|
|
|
|
networkpage.hidden = true;
|
2023-09-24 21:54:12 +02:00
|
|
|
toggleeditor(false);
|
2023-02-05 10:20:27 +01:00
|
|
|
loadnote(nodes.find(n => n.id == event.nodes[0]).label);
|
2023-02-05 10:04:07 +01:00
|
|
|
});
|
2023-11-10 10:13:26 +01:00
|
|
|
graph.setSelection(
|
|
|
|
{
|
|
|
|
nodes : [id(currentnote)]
|
|
|
|
});
|
2023-02-05 10:04:07 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
searchinlist(connected(currentnote).map(n => n.title))
|
|
|
|
.then(loadnote);
|
|
|
|
}
|
2023-02-04 16:13:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function showoutline()
|
|
|
|
{
|
|
|
|
var outline = {};
|
|
|
|
var pos = 0;
|
2023-07-17 11:25:08 +02:00
|
|
|
md.value.split("\n").forEach((line, index, lines) =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
pos += line.length + 1;
|
2023-01-30 12:16:59 +01:00
|
|
|
if (line.startsWith("#"))
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
line = line
|
|
|
|
.replace("# ", "")
|
2023-01-27 09:22:09 +01:00
|
|
|
.replace(/#/g, "\xa0".repeat(4));
|
2023-01-18 12:34:55 +01:00
|
|
|
outline[line] = pos;
|
2023-01-26 12:01:15 +01:00
|
|
|
}
|
2023-02-02 14:49:04 +01:00
|
|
|
else if (line == "---" && index != 0 && index != 3)
|
|
|
|
{
|
2023-10-20 11:40:16 +02:00
|
|
|
var next = lines.find((current, i) =>
|
2023-02-02 14:49:04 +01:00
|
|
|
{
|
|
|
|
return i > index && current != "";
|
2023-10-20 11:40:16 +02:00
|
|
|
});
|
|
|
|
if (next)
|
2023-02-02 14:49:04 +01:00
|
|
|
{
|
2023-07-07 10:17:49 +02:00
|
|
|
var nbcar = 80;
|
2023-02-02 14:49:04 +01:00
|
|
|
next = next.length < nbcar ? next : next.substring(0, nbcar) + "...";
|
2023-07-07 10:17:49 +02:00
|
|
|
outline[next] = pos;
|
2023-02-02 14:49:04 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
});
|
2023-01-30 10:36:43 +01:00
|
|
|
|
|
|
|
var keys = Object
|
|
|
|
.keys(outline)
|
|
|
|
.sort((a,b) =>
|
|
|
|
{
|
|
|
|
return outline[a] - outline[b];
|
|
|
|
});
|
|
|
|
|
|
|
|
searchinlist(keys)
|
2023-01-18 12:34:55 +01:00
|
|
|
.then(line =>
|
|
|
|
{
|
|
|
|
md.setSelectionRange(outline[line], outline[line]);
|
|
|
|
md.focus();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-01-30 10:01:14 +01:00
|
|
|
function linkrangeatpos()
|
2023-01-30 08:48:15 +01:00
|
|
|
{
|
2023-01-30 09:18:23 +01:00
|
|
|
var start = md.value.lastIndexOf("[[", md.selectionStart);
|
2023-01-30 10:01:14 +01:00
|
|
|
if (start == -1 || md.value.substring(start, md.selectionStart).indexOf("\n") != -1) return null
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-01-30 09:18:23 +01:00
|
|
|
var end = md.value.indexOf("]]", md.selectionStart);
|
2023-01-30 10:01:14 +01:00
|
|
|
if (end == -1 || md.value.substring(md.selectionStart, end).indexOf("\n") != -1) return null;
|
|
|
|
|
|
|
|
return {
|
|
|
|
start: start,
|
|
|
|
end: end + 2
|
2023-09-11 09:57:00 +02:00
|
|
|
};
|
2023-01-30 10:01:14 +01:00
|
|
|
}
|
2023-01-30 08:48:15 +01:00
|
|
|
|
2023-01-30 10:01:14 +01:00
|
|
|
function linkatpos()
|
|
|
|
{
|
|
|
|
var range = linkrangeatpos();
|
|
|
|
if (range)
|
|
|
|
{
|
|
|
|
return md.value.substring(range.start + 2, range.end - 2);
|
|
|
|
}
|
|
|
|
return null;
|
2023-01-21 16:07:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function tagatpos()
|
|
|
|
{
|
2023-01-30 14:53:42 +01:00
|
|
|
if (md.value.lastIndexOf("tags: ", md.selectionStart) < md.value.lastIndexOf("\n", md.selectionStart) || md.selectionStart < 6)
|
2023-01-30 12:16:59 +01:00
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-01-30 09:18:23 +01:00
|
|
|
var start = md.value.lastIndexOf(" ", md.selectionStart);
|
|
|
|
if (start == -1 || md.value.substring(start, md.selectionStart).indexOf("\n") != -1) return "";
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-01-30 14:53:42 +01:00
|
|
|
var eol = md.value.indexOf("\n", md.selectionStart);
|
2023-01-30 12:16:59 +01:00
|
|
|
var end = md.value.indexOf(",", md.selectionStart);
|
2023-01-30 14:53:42 +01:00
|
|
|
|
|
|
|
if (end == -1 || eol < end)
|
2023-01-30 12:16:59 +01:00
|
|
|
{
|
2023-01-30 14:53:42 +01:00
|
|
|
end = eol;
|
2023-01-30 12:16:59 +01:00
|
|
|
}
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-01-30 09:18:23 +01:00
|
|
|
return md.value.substring(start + 1, end);
|
2023-01-21 16:07:14 +01:00
|
|
|
}
|
|
|
|
|
2023-11-13 17:17:38 +01:00
|
|
|
function removelinkdialog()
|
|
|
|
{
|
|
|
|
if (typeof linkdialog != "undefined")
|
|
|
|
{
|
|
|
|
notepage.removeChild(linkdialog);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function showlinkdialog(link)
|
|
|
|
{
|
|
|
|
var div = document.createElement("div");
|
|
|
|
div.setAttribute("style", "top:" + event.pageY + "px;left:" + event.pageX + "px");
|
|
|
|
div.setAttribute("id", "linkdialog");
|
|
|
|
|
|
|
|
var a = document.createElement("a");
|
|
|
|
a.setAttribute("id", "linkelt");
|
|
|
|
|
2023-11-14 11:52:33 +01:00
|
|
|
if (link.startsWith("http"))
|
2023-11-13 17:17:38 +01:00
|
|
|
{
|
|
|
|
a.setAttribute("href", link);
|
|
|
|
a.setAttribute("target", "_blank");
|
|
|
|
div.onclick = removelinkdialog;
|
2024-01-31 13:55:25 +01:00
|
|
|
a.innerText = link;
|
2023-11-13 17:17:38 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
a.setAttribute("href", "#");
|
|
|
|
a.innerText = link;
|
|
|
|
div.onclick = function()
|
|
|
|
{
|
|
|
|
removelinkdialog();
|
|
|
|
loadnote(link);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
div.appendChild(a);
|
|
|
|
|
|
|
|
notepage.appendChild(div);
|
|
|
|
}
|
|
|
|
|
2024-01-16 15:15:23 +01:00
|
|
|
function checkatpos(pos)
|
2023-01-21 16:07:14 +01:00
|
|
|
{
|
2024-01-16 15:15:23 +01:00
|
|
|
if (pos > 0 && md.value[pos - 1] == "[" && md.value[pos + 1] == "]")
|
2023-07-03 09:17:20 +02:00
|
|
|
{
|
2024-01-16 15:15:23 +01:00
|
|
|
return {
|
|
|
|
pos: pos,
|
|
|
|
val: md.value[pos]
|
|
|
|
};
|
2023-07-03 09:17:20 +02:00
|
|
|
}
|
2024-01-16 15:15:23 +01:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function clickedcheck()
|
|
|
|
{
|
|
|
|
return checkatpos(md.selectionStart) || checkatpos(md.selectionStart + 1) || checkatpos(md.selectionStart - 1);
|
|
|
|
}
|
2023-11-13 17:17:38 +01:00
|
|
|
|
2024-01-16 15:15:23 +01:00
|
|
|
function clickeditor()
|
|
|
|
{
|
2024-01-12 13:46:48 +01:00
|
|
|
var word, link;
|
2023-01-21 16:07:14 +01:00
|
|
|
if (event.ctrlKey)
|
|
|
|
{
|
2024-01-16 15:15:23 +01:00
|
|
|
if (!saved)
|
|
|
|
{
|
|
|
|
console.log("Not saved, ctrl+click ignored.");
|
|
|
|
return;
|
|
|
|
}
|
2024-01-12 13:46:48 +01:00
|
|
|
link = linkatpos();
|
2023-01-21 16:07:14 +01:00
|
|
|
var tag = tagatpos();
|
2024-01-12 13:46:48 +01:00
|
|
|
word = wordatpos();
|
2023-01-21 16:07:14 +01:00
|
|
|
if (link)
|
|
|
|
{
|
|
|
|
loadnote(link);
|
|
|
|
}
|
|
|
|
else if (tag)
|
|
|
|
{
|
|
|
|
tagslist();
|
2023-01-23 12:59:46 +01:00
|
|
|
searchinlist(tags[tag.toLowerCase()])
|
2023-01-21 16:07:14 +01:00
|
|
|
.then(loadnote);
|
|
|
|
}
|
2023-11-14 11:52:33 +01:00
|
|
|
else if (word.startsWith("http"))
|
2023-10-03 12:11:37 +02:00
|
|
|
{
|
|
|
|
window.open(word, '_blank');
|
|
|
|
}
|
2023-01-21 16:07:14 +01:00
|
|
|
}
|
2024-01-16 15:15:23 +01:00
|
|
|
else if (clickedcheck())
|
|
|
|
{
|
|
|
|
var res = clickedcheck();
|
|
|
|
seteditorcontent(md.value.substring(0, res.pos)
|
|
|
|
+ (res.val == " " ? "x" : " ")
|
|
|
|
+ md.value.substring(res.pos + 1));
|
|
|
|
setpos(res.pos);
|
|
|
|
}
|
2023-11-13 17:17:38 +01:00
|
|
|
else if (settings.uselinkpopup)
|
|
|
|
{
|
|
|
|
removelinkdialog();
|
2024-01-12 13:46:48 +01:00
|
|
|
link = linkatpos();
|
2023-11-13 17:17:38 +01:00
|
|
|
if (link)
|
|
|
|
{
|
|
|
|
showlinkdialog(link);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-01-12 13:46:48 +01:00
|
|
|
word = wordatpos();
|
2023-11-14 11:52:33 +01:00
|
|
|
if (word.startsWith("http"))
|
2023-11-13 17:17:38 +01:00
|
|
|
{
|
|
|
|
showlinkdialog(word);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-21 16:07:14 +01:00
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function restoresettings()
|
|
|
|
{
|
|
|
|
if (confirm("Restore default settings?"))
|
|
|
|
{
|
2023-01-23 12:50:52 +01:00
|
|
|
settings = defaultsettings;
|
|
|
|
savesettings();
|
2023-01-18 12:34:55 +01:00
|
|
|
loadsettings();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function editsettings()
|
|
|
|
{
|
|
|
|
bindfile(
|
|
|
|
{
|
|
|
|
title: "settings.json",
|
|
|
|
content: JSON.stringify(settings, null, " ")
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-25 14:08:57 +02:00
|
|
|
function editsetting(name)
|
2023-09-23 23:00:39 +02:00
|
|
|
{
|
2023-10-03 13:57:20 +02:00
|
|
|
if (typeof settings[name] != "undefined")
|
2023-09-23 23:00:39 +02:00
|
|
|
{
|
2023-09-24 15:19:39 +02:00
|
|
|
var value = settings[name];
|
|
|
|
var type = typeof value;
|
|
|
|
if (type != "undefined")
|
2023-09-23 23:00:39 +02:00
|
|
|
{
|
2023-09-24 15:19:39 +02:00
|
|
|
value = prompt(name, value);
|
2023-09-27 09:09:16 +02:00
|
|
|
if (value !== null)
|
2023-09-23 23:09:09 +02:00
|
|
|
{
|
2023-09-27 09:09:16 +02:00
|
|
|
if (type == "number")
|
|
|
|
{
|
|
|
|
value = parseInt(value);
|
|
|
|
}
|
|
|
|
else if (type == "boolean")
|
|
|
|
{
|
|
|
|
value = value === "true";
|
|
|
|
}
|
|
|
|
settings[name] = value;
|
|
|
|
savesettings();
|
|
|
|
loadsettings();
|
2023-09-23 23:09:09 +02:00
|
|
|
}
|
2023-09-23 23:00:39 +02:00
|
|
|
}
|
2023-09-25 14:08:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-23 23:00:39 +02:00
|
|
|
function changesetting()
|
|
|
|
{
|
|
|
|
searchinlist(Object.keys(settings).map(name => name + ": " + settings[name]))
|
|
|
|
.then(setting =>
|
|
|
|
{
|
2023-09-25 14:08:57 +02:00
|
|
|
editsetting(setting.split(":").shift());
|
2023-09-23 23:00:39 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-09-21 21:29:08 +02:00
|
|
|
function decryptnote()
|
2023-09-21 20:56:13 +02:00
|
|
|
{
|
2023-09-21 21:29:08 +02:00
|
|
|
decryptstring(md.value)
|
|
|
|
.then(decrypted =>
|
|
|
|
{
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(decrypted);
|
2023-09-21 21:29:08 +02:00
|
|
|
resize();
|
|
|
|
});
|
2023-09-21 20:56:13 +02:00
|
|
|
}
|
|
|
|
|
2023-07-13 13:55:52 +02:00
|
|
|
function editpgpkeys()
|
|
|
|
{
|
|
|
|
bindfile(
|
|
|
|
{
|
|
|
|
title: "pgpkeys",
|
2023-10-27 16:59:14 +02:00
|
|
|
content: localStorage.getItem("pgpkeys") || ""
|
2023-07-13 13:55:52 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-05-15 15:20:36 +02:00
|
|
|
function showtemporaryinfo(info)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-05-15 15:20:36 +02:00
|
|
|
alert(info);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-01-24 22:17:48 +01:00
|
|
|
function getwords()
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-07-17 11:25:08 +02:00
|
|
|
return md.value.split(/\s+\b/).length;
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function issplit()
|
|
|
|
{
|
|
|
|
return window.location !== window.parent.location;
|
|
|
|
}
|
|
|
|
|
|
|
|
function togglesplit()
|
|
|
|
{
|
|
|
|
if (issplit())
|
|
|
|
{
|
|
|
|
window.parent.location = "index.html";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
window.location = "split.html";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-21 16:07:14 +01:00
|
|
|
function tagslist()
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-21 16:07:14 +01:00
|
|
|
tags = {};
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
localdata
|
2023-01-26 12:01:15 +01:00
|
|
|
.forEach(n =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
var ts = gettags(n);
|
2023-01-26 12:01:15 +01:00
|
|
|
ts.forEach(t =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
tags[t] = tags[t] || [];
|
|
|
|
tags[t].push(n.title);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-01-21 16:07:14 +01:00
|
|
|
return searchinlist(Object.keys(tags).sort());
|
|
|
|
}
|
|
|
|
|
|
|
|
function searchtags()
|
|
|
|
{
|
|
|
|
tagslist()
|
2023-01-18 12:34:55 +01:00
|
|
|
.then(tag => searchinlist(tags[tag]))
|
2023-01-21 16:07:14 +01:00
|
|
|
.then(loadnote);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function gettags(note)
|
|
|
|
{
|
|
|
|
var i = note.content.indexOf("tags: ");
|
|
|
|
if (i > -1)
|
|
|
|
{
|
|
|
|
var j = note.content.indexOf("\n", i);
|
2023-11-06 09:59:01 +01:00
|
|
|
return note.content.substring(i + 6, j)
|
|
|
|
.split(",")
|
|
|
|
.map(t => t.toLowerCase().trim())
|
|
|
|
.filter(t => t.length);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2023-01-27 09:22:09 +01:00
|
|
|
function share()
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
if (navigator.share)
|
|
|
|
{
|
|
|
|
navigator.share(
|
|
|
|
{
|
2023-07-17 11:25:08 +02:00
|
|
|
text: md.value,
|
2023-01-18 12:34:55 +01:00
|
|
|
title: currentnote.title
|
2023-01-26 12:01:15 +01:00
|
|
|
});
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function sharehtml()
|
|
|
|
{
|
2023-01-27 09:22:09 +01:00
|
|
|
if (navigator.share)
|
|
|
|
{
|
2023-07-17 11:25:08 +02:00
|
|
|
var file = new File(['<html><body>' + md2html(md.value) + '</body></html>'],
|
2023-01-27 09:22:09 +01:00
|
|
|
currentnote.title + ".html",
|
|
|
|
{
|
2023-10-19 15:28:53 +02:00
|
|
|
type: "text/html",
|
2023-01-27 09:22:09 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
navigator.share(
|
|
|
|
{
|
2023-10-19 15:28:53 +02:00
|
|
|
title: currentnote.title,
|
|
|
|
files: [file]
|
2023-01-27 09:22:09 +01:00
|
|
|
});
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-09-01 10:40:28 +02:00
|
|
|
function getfilename(title)
|
|
|
|
{
|
2023-10-20 14:18:51 +02:00
|
|
|
return title.replace(/[\?\"<>|\*:\/\\]/g, "_") + ".md";
|
2023-09-01 10:40:28 +02:00
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function download(filename, content)
|
|
|
|
{
|
|
|
|
var element = document.createElement('a');
|
2023-02-21 12:05:04 +01:00
|
|
|
element.setAttribute('href', 'data:text/markdown;charset=utf-8,' + encodeURIComponent(content));
|
2023-01-18 12:34:55 +01:00
|
|
|
element.setAttribute('download', filename);
|
|
|
|
element.style.display = 'none';
|
|
|
|
document.body.appendChild(element);
|
|
|
|
element.click();
|
|
|
|
document.body.removeChild(element);
|
2023-02-21 12:05:04 +01:00
|
|
|
element = null;
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function downloadnotes()
|
|
|
|
{
|
2023-09-01 10:40:28 +02:00
|
|
|
var zip = new JSZip();
|
|
|
|
localdata.forEach(note =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-09-01 10:40:28 +02:00
|
|
|
zip.file(getfilename(note.title), note.content);
|
|
|
|
});
|
|
|
|
zip.generateAsync({type:"blob"})
|
|
|
|
.then(function(content)
|
|
|
|
{
|
2023-10-27 16:59:14 +02:00
|
|
|
saveAs(content, "notes-" + timestamp() + ".zip");
|
2023-09-01 10:40:28 +02:00
|
|
|
});
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-11-06 11:49:45 +01:00
|
|
|
function downloadhtmlnotes()
|
|
|
|
{
|
|
|
|
var zip = new JSZip();
|
|
|
|
localdata.forEach(note =>
|
|
|
|
{
|
|
|
|
zip.file(getfilename(note.title).replace(".md", ".html"), md2html(note.content));
|
|
|
|
});
|
|
|
|
zip.generateAsync({type:"blob"})
|
|
|
|
.then(function(content)
|
|
|
|
{
|
|
|
|
saveAs(content, "notes-html-" + timestamp() + ".zip");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-10-23 12:14:01 +02:00
|
|
|
function headerandtext(note)
|
|
|
|
{
|
|
|
|
var content = note.content;
|
|
|
|
var result =
|
|
|
|
{
|
|
|
|
header: "",
|
|
|
|
text: content
|
|
|
|
};
|
|
|
|
if (content.startsWith("---\n"))
|
|
|
|
{
|
|
|
|
var end = content.indexOf("---\n", 4);
|
|
|
|
if (end > -1)
|
|
|
|
{
|
|
|
|
result.header = content.substring(0, end + 4);
|
|
|
|
result.text = content.substring(end + 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-17 09:09:25 +01:00
|
|
|
function inserttodo(text)
|
|
|
|
{
|
|
|
|
var todo = getorcreate("todo", "");
|
|
|
|
var split = headerandtext(todo);
|
|
|
|
todo.content = split.header + text + "\n" + split.text;
|
|
|
|
if (todo == currentnote)
|
|
|
|
{
|
|
|
|
seteditorcontent(todo.content, true);
|
|
|
|
}
|
|
|
|
return datachanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
function promptinserttodo()
|
2023-05-15 14:49:52 +02:00
|
|
|
{
|
2023-10-19 12:24:44 +02:00
|
|
|
var text = prompt("Text:");
|
|
|
|
if (text)
|
2023-05-15 14:49:52 +02:00
|
|
|
{
|
2024-01-17 09:09:25 +01:00
|
|
|
inserttodo(text);
|
2023-05-15 14:49:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-27 16:59:14 +02:00
|
|
|
function downloadnotesjson()
|
2023-02-03 12:56:31 +01:00
|
|
|
{
|
2023-10-27 16:59:14 +02:00
|
|
|
download("notes-" + timestamp() + ".json", window.localStorage.getItem("data"));
|
2023-02-03 12:56:31 +01:00
|
|
|
}
|
|
|
|
|
2023-10-27 12:54:01 +02:00
|
|
|
function downloadencrypted()
|
|
|
|
{
|
|
|
|
encryptstring(JSON.stringify(localdata))
|
|
|
|
.then(encrypted =>
|
|
|
|
{
|
2023-10-27 16:59:14 +02:00
|
|
|
download("notes-encrypted-" + timestamp() + ".acs", encrypted);
|
2023-10-27 12:54:01 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-01-30 10:01:14 +01:00
|
|
|
function downloadnotewithsubs()
|
|
|
|
{
|
2023-02-05 10:04:07 +01:00
|
|
|
var note = withsubs();
|
|
|
|
if (note)
|
2023-01-30 10:01:14 +01:00
|
|
|
{
|
2023-09-11 09:57:00 +02:00
|
|
|
download(note.title + ".md", note.content);
|
|
|
|
}
|
2023-01-30 10:01:14 +01:00
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function downloadnote()
|
|
|
|
{
|
2023-07-17 11:25:08 +02:00
|
|
|
download(currentnote.title + ".md", md.value);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function remotecallfailed(error)
|
|
|
|
{
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
console.warn(error);
|
2023-05-15 15:20:36 +02:00
|
|
|
showtemporaryinfo("Error: " + error);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
2023-10-19 12:33:17 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
console.warn("remotecallfailed without details");
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-09-06 21:29:32 +02:00
|
|
|
function gotoline(line)
|
|
|
|
{
|
|
|
|
var i = 0;
|
|
|
|
var pos = 0;
|
|
|
|
while (i < line && pos > -1)
|
|
|
|
{
|
|
|
|
pos = currentnote.content.indexOf("\n", pos + 1);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (pos > -1)
|
|
|
|
{
|
|
|
|
setpos(pos + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function loadstorage()
|
|
|
|
{
|
2023-10-27 16:59:14 +02:00
|
|
|
var item = window.localStorage.getItem("data");
|
2023-01-18 12:34:55 +01:00
|
|
|
localdata = item ? JSON.parse(item) : [];
|
|
|
|
|
2023-09-06 21:29:32 +02:00
|
|
|
var params = new URLSearchParams(window.location.search);
|
2024-01-24 11:07:39 +01:00
|
|
|
var title = params.get("n") || params.get("name");
|
2023-09-06 21:29:32 +02:00
|
|
|
var line = params.get("l");
|
2023-09-21 22:16:12 +02:00
|
|
|
var tags = params.get("t");
|
2024-01-08 10:55:12 +01:00
|
|
|
var clip = params.get("c");
|
2024-01-05 14:12:08 +01:00
|
|
|
|
|
|
|
if (clip)
|
|
|
|
{
|
2024-01-17 09:09:25 +01:00
|
|
|
settings.savedelay = 0;
|
2024-01-07 16:54:28 +01:00
|
|
|
colored.hidden = true;
|
|
|
|
md.hidden = true;
|
|
|
|
var msg = document.createElement("div");
|
|
|
|
msg.innerText = "Clipping...";
|
|
|
|
notepage.appendChild(msg);
|
|
|
|
|
2024-01-24 11:07:39 +01:00
|
|
|
inserttodo("@clip " + clip).then(window.close);
|
2024-01-05 14:12:08 +01:00
|
|
|
}
|
2023-05-22 14:04:35 +02:00
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
if (currentnote)
|
|
|
|
{
|
2023-05-22 14:04:35 +02:00
|
|
|
currentnote = getnote(currentnote.title);
|
|
|
|
}
|
2023-09-06 21:29:32 +02:00
|
|
|
else if (title)
|
2023-05-22 14:04:35 +02:00
|
|
|
{
|
2023-09-06 21:29:32 +02:00
|
|
|
currentnote = getnote(title);
|
2023-05-22 14:04:35 +02:00
|
|
|
if (!currentnote)
|
|
|
|
{
|
2024-01-24 11:07:39 +01:00
|
|
|
var newcontent = params.get("description") || defaultheaders(tags);
|
2023-10-02 12:50:41 +02:00
|
|
|
currentnote = {title: title, content: newcontent, pos: newcontent.length};
|
2023-05-22 14:04:35 +02:00
|
|
|
localdata.unshift(currentnote);
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (currentnote)
|
|
|
|
{
|
|
|
|
bindfile(currentnote);
|
2023-09-06 21:29:32 +02:00
|
|
|
if (line)
|
|
|
|
{
|
|
|
|
gotoline(line);
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
loadlast();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadsettings()
|
|
|
|
{
|
|
|
|
settings = {...defaultsettings};
|
|
|
|
var item = window.localStorage.getItem("settings");
|
|
|
|
if (item)
|
|
|
|
{
|
|
|
|
item = JSON.parse(item);
|
2023-01-22 21:24:09 +01:00
|
|
|
for (var key in settings)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-25 21:40:34 +01:00
|
|
|
if (typeof item[key] !== "undefined")
|
2023-01-22 21:24:09 +01:00
|
|
|
{
|
2023-01-26 12:01:15 +01:00
|
|
|
settings[key] = item[key];
|
2023-01-22 21:24:09 +01:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-16 10:50:29 +01:00
|
|
|
document.body.style.fontSize = settings.fontsize;
|
|
|
|
document.body.style.lineHeight = settings.lineheight;
|
|
|
|
document.body.style.marginLeft = settings.margins;
|
|
|
|
document.body.style.marginRight = settings.margins;
|
2024-01-09 11:09:57 +01:00
|
|
|
document.body.style.fontFamily = settings.fontfamily;
|
2023-01-18 12:34:55 +01:00
|
|
|
|
2023-07-21 10:58:13 +02:00
|
|
|
if (settings.titlebydefault && title.hidden)
|
2023-03-03 09:58:56 +01:00
|
|
|
{
|
|
|
|
toggletitle();
|
|
|
|
}
|
2023-09-23 09:02:02 +02:00
|
|
|
|
|
|
|
colored.hidden = !settings.colors;
|
|
|
|
md.style.color = settings.colors ? "transparent" : "inherit";
|
|
|
|
md.style.background = settings.colors ? "transparent" : "inherit";
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function checksaved()
|
|
|
|
{
|
2023-01-25 15:41:21 +01:00
|
|
|
if (!saved)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
return "not saved";
|
2023-01-25 09:32:44 +01:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-01-19 14:06:19 +01:00
|
|
|
function initsnippets()
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-19 14:06:19 +01:00
|
|
|
// code languages
|
2023-01-18 12:34:55 +01:00
|
|
|
codelanguages.forEach(lang =>
|
|
|
|
{
|
2023-01-21 16:07:14 +01:00
|
|
|
if (!snippets.find(s => s.command == "/" + lang))
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
snippets.push(
|
|
|
|
{
|
|
|
|
command: "/" + lang,
|
|
|
|
hint: lang + " code block",
|
|
|
|
insert: "```" + lang + "\n\n```",
|
|
|
|
cursor: -4
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2023-01-19 14:06:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function init()
|
|
|
|
{
|
|
|
|
loadsettings();
|
2023-01-21 16:07:14 +01:00
|
|
|
|
2023-01-19 14:06:19 +01:00
|
|
|
window.onbeforeunload = checksaved;
|
|
|
|
window.onclick = focuseditor;
|
2023-01-26 12:01:15 +01:00
|
|
|
|
2023-01-19 14:06:19 +01:00
|
|
|
initsnippets();
|
|
|
|
|
2023-11-09 09:57:24 +01:00
|
|
|
if (settings.sync)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-07-17 09:16:10 +02:00
|
|
|
if (localStorage.getItem("pgpkeys") && localStorage.getItem("pgpkeys").startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----"))
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-07-17 09:16:10 +02:00
|
|
|
queryremote({action: "fetch"})
|
|
|
|
.then(data =>
|
|
|
|
{
|
2023-11-03 14:59:37 +01:00
|
|
|
if (data.length)
|
|
|
|
{
|
|
|
|
window.localStorage.setItem("data", JSON.stringify(data));
|
|
|
|
}
|
2023-11-08 16:24:39 +01:00
|
|
|
loadstorage();
|
2023-07-17 09:16:10 +02:00
|
|
|
})
|
2023-10-27 13:31:32 +02:00
|
|
|
.catch(err =>
|
|
|
|
{
|
2023-12-14 09:54:33 +01:00
|
|
|
if (err == "Authent failed")
|
|
|
|
{
|
|
|
|
settings.password = prompt("Password: ", settings.password);
|
|
|
|
savesettings();
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
showtemporaryinfo(err);
|
|
|
|
}
|
2023-10-27 13:31:32 +02:00
|
|
|
});
|
2023-07-17 09:16:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-05-05 10:57:27 +02:00
|
|
|
loadstorage();
|
2023-10-27 16:59:14 +02:00
|
|
|
editpgpkeys();
|
|
|
|
showtemporaryinfo("Pgp key empty or invalid. Enter PGP keys and refresh.");
|
2023-07-17 09:16:10 +02:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
loadstorage();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (issplit())
|
|
|
|
{
|
|
|
|
if (settings.defaultpreviewinsplit && name == "right")
|
|
|
|
{
|
2023-01-26 12:01:15 +01:00
|
|
|
togglepreview();
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
else if (name == "left")
|
|
|
|
{
|
2023-01-26 12:01:15 +01:00
|
|
|
md.focus();
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-06 09:26:08 +01:00
|
|
|
function getorcreate(title, content)
|
2023-07-17 09:16:10 +02:00
|
|
|
{
|
|
|
|
var note = getnote(title);
|
|
|
|
if (!note)
|
|
|
|
{
|
2023-09-14 11:54:09 +02:00
|
|
|
note = {title: title, content: content, pos: content.length};
|
2023-07-17 09:16:10 +02:00
|
|
|
localdata.push(note)
|
|
|
|
}
|
|
|
|
|
|
|
|
return note;
|
|
|
|
}
|
|
|
|
|
2023-09-21 21:45:09 +02:00
|
|
|
function queryremote(params)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
return new Promise( (apply, failed) => {
|
|
|
|
|
2023-01-26 12:00:32 +01:00
|
|
|
stat.cur.q++;
|
|
|
|
stat.ses.q++;
|
|
|
|
|
2023-10-27 13:31:32 +02:00
|
|
|
params.password = settings.password;
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
var paramlist = [];
|
|
|
|
for (var i in params)
|
|
|
|
{
|
|
|
|
paramlist.push(i + "=" + encodeURIComponent(params[i]));
|
|
|
|
}
|
|
|
|
|
2023-02-03 12:56:31 +01:00
|
|
|
stat.cur.d += paramlist.join("&").length;
|
|
|
|
stat.ses.d += paramlist.join("&").length;
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
var xhr = new XMLHttpRequest();
|
|
|
|
xhr.open("POST", "handler.php");
|
|
|
|
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
|
|
|
|
|
|
xhr.onerror = function()
|
|
|
|
{
|
|
|
|
failed("XMLHttpRequest error");
|
|
|
|
}
|
|
|
|
|
2023-09-21 21:45:09 +02:00
|
|
|
xhr.onload = function()
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
if (xhr.status !== 200)
|
|
|
|
{
|
|
|
|
failed("Http status " + xhr.status);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var data = {};
|
2023-09-21 21:55:59 +02:00
|
|
|
|
|
|
|
decryptstring(xhr.responseText)
|
|
|
|
.then(decrypted =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-09-21 21:55:59 +02:00
|
|
|
data = JSON.parse(decrypted);
|
2023-01-18 12:34:55 +01:00
|
|
|
|
2023-09-21 21:55:59 +02:00
|
|
|
if (data.error)
|
|
|
|
{
|
|
|
|
if (data.error == "authent")
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-10-27 13:31:32 +02:00
|
|
|
failed("Authent failed");
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-09-21 21:55:59 +02:00
|
|
|
failed("Remote handler returned an error: " + data.error);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
2023-09-21 21:55:59 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
apply(data);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch( error =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-12-14 09:54:33 +01:00
|
|
|
failed("Could not decrypt or parse data file.");
|
|
|
|
console.error(error);
|
2023-09-21 21:55:59 +02:00
|
|
|
});
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
2023-09-21 21:47:48 +02:00
|
|
|
|
2024-01-03 14:33:42 +01:00
|
|
|
var paramstring = paramlist.join("&");
|
|
|
|
console.log("http request length: " + formatsize(paramstring.length));
|
|
|
|
xhr.send(paramstring);
|
2023-01-18 12:34:55 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getlinesrange()
|
|
|
|
{
|
|
|
|
var start = md.selectionStart;
|
|
|
|
var end = md.selectionEnd;
|
|
|
|
|
|
|
|
while (start > 0 && md.value[start - 1] != "\n") start--;
|
|
|
|
while (end < md.value.length && md.value[end] != "\n") end++;
|
|
|
|
|
|
|
|
return {
|
|
|
|
start: start,
|
|
|
|
end: end
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-11-13 18:09:46 +01:00
|
|
|
function backlinks()
|
|
|
|
{
|
|
|
|
searchinlist(localdata
|
|
|
|
.filter(n => n.content.includes("[[" + currentnote.title + "]]"))
|
|
|
|
.map(n => n.title))
|
|
|
|
.then(loadnote);
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function sortselection()
|
|
|
|
{
|
2023-07-17 11:25:08 +02:00
|
|
|
var content = md.value;
|
2023-01-18 12:34:55 +01:00
|
|
|
var range = {start: 0, end: content.length};
|
|
|
|
if (md.selectionStart != md.selectionEnd)
|
|
|
|
{
|
|
|
|
range = getlinesrange();
|
|
|
|
}
|
|
|
|
|
|
|
|
var selection = content.substring(range.start, range.end);
|
|
|
|
var sorted = selection.split("\n").sort().join("\n");
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(content.substring(0, range.start) + sorted + content.substring(range.end));
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-10-03 12:11:37 +02:00
|
|
|
function wordatpos()
|
|
|
|
{
|
|
|
|
var words = md.value.split(/\s/);
|
2023-10-19 15:28:53 +02:00
|
|
|
var i = 0;
|
|
|
|
var word = "";
|
2023-10-03 12:11:37 +02:00
|
|
|
while (i < md.selectionStart)
|
2023-10-19 15:28:53 +02:00
|
|
|
{
|
2023-10-03 12:11:37 +02:00
|
|
|
word = words.shift();
|
2023-10-19 15:28:53 +02:00
|
|
|
i += word.length + 1;
|
2023-10-03 12:11:37 +02:00
|
|
|
}
|
|
|
|
return word;
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function ontopbarclick()
|
|
|
|
{
|
|
|
|
if (title.hidden)
|
|
|
|
{
|
|
|
|
commandpalette();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function md2html(content)
|
|
|
|
{
|
|
|
|
var converter = new showdown.Converter();
|
|
|
|
converter.setOption("simplifiedAutoLink", true);
|
|
|
|
converter.setOption("simpleLineBreaks", true);
|
|
|
|
converter.setOption("metadata", true);
|
2023-06-21 13:28:24 +02:00
|
|
|
converter.setOption("tasklists", true);
|
2023-07-12 16:28:21 +02:00
|
|
|
converter.setOption("literalMidWordUnderscores", true);
|
2023-01-18 12:34:55 +01:00
|
|
|
|
2023-05-11 10:49:36 +02:00
|
|
|
if (settings.linksinnewtab)
|
|
|
|
{
|
|
|
|
converter.setOption("openLinksInNewWindow", true);
|
|
|
|
}
|
2023-09-11 09:57:00 +02:00
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
var html = converter.makeHtml(content);
|
|
|
|
|
|
|
|
// internal links
|
2023-01-21 16:07:14 +01:00
|
|
|
html = html.replace(/\[\[([^\]]*)\]\]/g, "<a href='#' onclick='loadnote(\"$1\");'>$1</a>");
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
return html;
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadlast()
|
|
|
|
{
|
2023-11-08 11:56:34 +01:00
|
|
|
loadnote(localdata.length ? localdata[0].title : timestamp());
|
2023-01-21 16:07:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function loadprevious()
|
|
|
|
{
|
2023-07-05 09:42:33 +02:00
|
|
|
var index = localdata.indexOf(currentnote);
|
2023-07-05 13:40:13 +02:00
|
|
|
if (index > -1 && index < localdata.length - 1)
|
2023-07-05 09:42:33 +02:00
|
|
|
{
|
|
|
|
loadnote(localdata[index + 1].title);
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-07-05 13:40:13 +02:00
|
|
|
function loadnext()
|
|
|
|
{
|
|
|
|
var index = localdata.indexOf(currentnote);
|
2023-12-06 09:26:08 +01:00
|
|
|
if (index > -1 && index > 0)
|
2023-07-05 13:40:13 +02:00
|
|
|
{
|
|
|
|
loadnote(localdata[index - 1].title);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function grep(needle)
|
|
|
|
{
|
|
|
|
var result = {};
|
|
|
|
|
|
|
|
localdata
|
2023-05-22 14:07:04 +02:00
|
|
|
.filter(note => note.title != "events.json")
|
2023-01-18 12:34:55 +01:00
|
|
|
.forEach(note =>
|
|
|
|
{
|
|
|
|
if (note.title.toLowerCase().includes(needle.toLowerCase()))
|
|
|
|
{
|
|
|
|
result[note.title] = {};
|
|
|
|
}
|
|
|
|
note.content.split("\n")
|
|
|
|
.forEach((line, nb) => {
|
|
|
|
if (line.toLowerCase().includes(needle.toLowerCase()))
|
|
|
|
{
|
|
|
|
result[note.title] = result[note.title] || {};
|
|
|
|
result[note.title][nb] = line;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-11-15 22:08:52 +01:00
|
|
|
function showgrepresult(needle, grepresult)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-11-15 22:08:52 +01:00
|
|
|
var grepcontent = ["# Search results: \"" + needle + "\""];
|
2023-01-18 12:34:55 +01:00
|
|
|
for (var file in grepresult)
|
|
|
|
{
|
|
|
|
grepcontent.push("[[" + file + "]]");
|
|
|
|
for (var l in grepresult[file])
|
|
|
|
{
|
2023-09-06 21:29:32 +02:00
|
|
|
grepcontent.push("[<a href=?n=" + encodeURIComponent(file) + "&l=" + l + ">" + l + "</a>] " + grepresult[file][l]);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
grepcontent.push("");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grepcontent.length == 0)
|
|
|
|
{
|
|
|
|
grepcontent.push("No result.");
|
|
|
|
}
|
|
|
|
|
|
|
|
bindfile(
|
|
|
|
{
|
|
|
|
title: "Search result",
|
|
|
|
content: grepcontent.join("\n")
|
|
|
|
});
|
|
|
|
|
|
|
|
if (preview.hidden)
|
|
|
|
{
|
|
|
|
togglepreview();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function showgrep()
|
|
|
|
{
|
2023-12-06 09:25:29 +01:00
|
|
|
var text = prompt("Search:", md.selectionEnd > md.selectionStart ? md.value.substr(md.selectionStart, md.selectionEnd - md.selectionStart).trim() : "");
|
2023-10-23 13:27:38 +02:00
|
|
|
if (text)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-11-15 22:08:52 +01:00
|
|
|
showgrepresult(text, grep(text));
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function commandpalette()
|
|
|
|
{
|
|
|
|
searchinlist(commands
|
2023-11-15 17:57:11 +01:00
|
|
|
.filter(command => !command.excludepalette)
|
|
|
|
.map(command =>
|
|
|
|
{
|
|
|
|
return {
|
2024-01-12 13:46:48 +01:00
|
|
|
prefix: "command ",
|
2023-11-15 17:57:11 +01:00
|
|
|
text: command.hint,
|
2023-11-15 21:03:43 +01:00
|
|
|
suffix: command.shortcut ? [command.shortcut.toLowerCase()] : null
|
2023-11-15 17:57:11 +01:00
|
|
|
};
|
|
|
|
})
|
|
|
|
.concat(snippets.map(s =>
|
|
|
|
{
|
|
|
|
return {
|
2023-11-15 21:52:28 +01:00
|
|
|
prefix: "snippet ",
|
2023-11-15 21:03:43 +01:00
|
|
|
text: s.hint,
|
|
|
|
suffix: [s.command]
|
2023-11-15 17:57:11 +01:00
|
|
|
};
|
|
|
|
}))
|
|
|
|
.concat(localdata.map(n =>
|
|
|
|
{
|
|
|
|
return {
|
2024-01-12 13:46:48 +01:00
|
|
|
prefix: "note ",
|
2023-11-15 17:57:11 +01:00
|
|
|
text: n.title,
|
|
|
|
suffix: gettags(n).map(t => tagmark + t)
|
|
|
|
};
|
|
|
|
}))
|
|
|
|
.concat(Object.keys(settings).map(s =>
|
|
|
|
{
|
|
|
|
return {
|
2023-11-15 21:52:28 +01:00
|
|
|
prefix: "setting ",
|
2023-11-15 17:57:11 +01:00
|
|
|
text: s,
|
|
|
|
suffix: s == "password" ? null : [settings[s]]
|
|
|
|
};
|
|
|
|
})))
|
|
|
|
.then(selected =>
|
|
|
|
{
|
2023-11-15 21:52:28 +01:00
|
|
|
if (selected.prefix == "snippet ")
|
2023-11-15 17:57:11 +01:00
|
|
|
{
|
|
|
|
var snippet = snippets.find(s => s.hint == selected.text);
|
|
|
|
insert(snippet.insert, snippet.cursor);
|
|
|
|
md.focus();
|
|
|
|
}
|
2024-01-12 13:46:48 +01:00
|
|
|
else if (selected.prefix == "note ")
|
2023-11-15 17:57:11 +01:00
|
|
|
{
|
|
|
|
loadnote(selected.text);
|
|
|
|
}
|
2023-11-15 21:52:28 +01:00
|
|
|
else if (selected.prefix == "setting ")
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-11-15 17:57:11 +01:00
|
|
|
editsetting(selected.text);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-11-15 17:57:11 +01:00
|
|
|
var command = commands.find(c => c.hint == selected.text);
|
|
|
|
if (command)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-11-15 17:57:11 +01:00
|
|
|
executecommand(command);
|
2023-09-25 14:08:57 +02:00
|
|
|
}
|
2023-05-11 10:49:36 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// if unknown command, create a new note
|
2023-11-15 17:57:11 +01:00
|
|
|
loadnote(selected);
|
2023-05-11 10:49:36 +02:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function insert(text, cursoroffset = 0, nbtodelete = 0)
|
|
|
|
{
|
|
|
|
var pos = md.selectionStart;
|
|
|
|
var content = md.value;
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(
|
|
|
|
content.substring(0, pos - nbtodelete)
|
|
|
|
+ text
|
|
|
|
+ content.substring(pos));
|
2023-01-18 12:34:55 +01:00
|
|
|
setpos(pos - nbtodelete + text.length + cursoroffset);
|
|
|
|
}
|
|
|
|
|
2023-11-15 08:43:29 +01:00
|
|
|
function searchinlist(list)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
return new Promise(selectitem =>
|
|
|
|
{
|
|
|
|
fileindex = 0;
|
|
|
|
searchdialog.hidden = false;
|
|
|
|
filteredlist.hidden = false;
|
|
|
|
|
|
|
|
filteredlist.innerHTML = "";
|
|
|
|
filter.value = "";
|
|
|
|
|
|
|
|
list.forEach(item =>
|
|
|
|
{
|
|
|
|
var elt = document.createElement("div");
|
2023-11-15 17:57:11 +01:00
|
|
|
elt.tag = item;
|
|
|
|
|
|
|
|
if (typeof item === "string")
|
|
|
|
{
|
|
|
|
elt.textContent = item;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var ts = document.createElement("span");
|
2023-11-16 10:47:53 +01:00
|
|
|
ts.setAttribute("class", "searchlistprefix");
|
2023-11-15 17:57:11 +01:00
|
|
|
ts.innerHTML = item.prefix || "";
|
|
|
|
elt.appendChild(ts);
|
|
|
|
|
|
|
|
ts = document.createElement("span");
|
|
|
|
ts.innerHTML = item.text;
|
|
|
|
elt.appendChild(ts);
|
|
|
|
|
|
|
|
if (item.suffix)
|
|
|
|
{
|
|
|
|
item.suffix.forEach(t =>
|
|
|
|
{
|
|
|
|
ts = document.createElement("span");
|
2023-11-16 10:47:53 +01:00
|
|
|
ts.setAttribute("class", "searchlistsuffix");
|
2023-11-15 17:57:11 +01:00
|
|
|
ts.innerHTML = " " + t;
|
|
|
|
elt.appendChild(ts);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
elt.onclick = function()
|
|
|
|
{
|
|
|
|
searchdialog.hidden = true;
|
2023-11-15 17:57:11 +01:00
|
|
|
selectitem(elt.tag);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
filteredlist.appendChild(elt);
|
|
|
|
});
|
|
|
|
|
|
|
|
applyfilter();
|
|
|
|
|
|
|
|
filter.onkeydown = function()
|
|
|
|
{
|
|
|
|
// doesn't work if focus is lost.
|
|
|
|
if (event.key === "Enter")
|
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
searchdialog.hidden = true;
|
|
|
|
var selected = document.getElementsByClassName("selected")[0];
|
2023-11-15 17:57:11 +01:00
|
|
|
selectitem(selected ? selected.tag : filter.value);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
2023-01-21 21:05:39 +01:00
|
|
|
|
|
|
|
filter.focus();
|
2023-01-18 12:34:55 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function applyfileindex()
|
|
|
|
{
|
|
|
|
var i = 0;
|
|
|
|
[...filteredlist.children].forEach(child =>
|
|
|
|
{
|
|
|
|
if (child.nodeName == "DIV")
|
|
|
|
{
|
2023-10-25 11:12:20 +02:00
|
|
|
child.className = "searchitem";
|
2023-01-18 12:34:55 +01:00
|
|
|
if(!child.hidden)
|
|
|
|
{
|
|
|
|
if (i++ == fileindex)
|
|
|
|
{
|
|
|
|
child.className = "selected";
|
2023-01-23 12:50:52 +01:00
|
|
|
if (child.customevent)
|
|
|
|
{
|
|
|
|
child.customevent(child.textContent);
|
|
|
|
filter.focus();
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getpos()
|
|
|
|
{
|
|
|
|
return md.selectionStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setpos(pos)
|
|
|
|
{
|
|
|
|
md.setSelectionRange(pos, pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
function before(nb)
|
|
|
|
{
|
|
|
|
return md.value.substring(getpos() - nb, getpos());
|
|
|
|
}
|
|
|
|
|
|
|
|
function resize()
|
|
|
|
{
|
2023-01-26 15:55:21 +01:00
|
|
|
if (md.clientHeight < md.scrollHeight)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-26 15:55:21 +01:00
|
|
|
md.style.height = md.scrollHeight + 'px';
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function putontop()
|
|
|
|
{
|
|
|
|
if (localdata.find(n => n == currentnote))
|
|
|
|
{
|
|
|
|
localdata.splice(localdata.indexOf(currentnote), 1);
|
2023-01-26 12:01:15 +01:00
|
|
|
localdata.unshift(currentnote);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-25 15:41:21 +01:00
|
|
|
function postpone()
|
|
|
|
{
|
|
|
|
return new Promise(function(resolve)
|
|
|
|
{
|
|
|
|
clearTimeout(workerid);
|
|
|
|
workerid = setTimeout(resolve, settings.savedelay);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-10-02 12:33:45 +02:00
|
|
|
function setsaved()
|
|
|
|
{
|
2023-11-28 15:24:33 +01:00
|
|
|
unsavedmark.hidden = true;
|
2023-10-02 12:33:45 +02:00
|
|
|
saved = true;
|
2023-10-27 12:43:03 +02:00
|
|
|
lastsaved = timestamp();
|
2023-10-02 12:33:45 +02:00
|
|
|
}
|
|
|
|
|
2023-09-21 21:35:46 +02:00
|
|
|
function save()
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
return new Promise(function(resolve, reject)
|
2023-01-26 00:32:00 +01:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
clearTimeout(workerid);
|
2023-01-26 00:32:00 +01:00
|
|
|
|
2024-01-08 10:55:12 +01:00
|
|
|
if (currentnote.title == "settings.json")
|
2023-07-13 13:18:47 +02:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
settings = JSON.parse(md.value);
|
|
|
|
savesettings();
|
|
|
|
loadsettings();
|
|
|
|
setsaved();
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
else if (currentnote.title == "pgpkeys")
|
2023-01-26 00:32:00 +01:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
localStorage.setItem("pgpkeys", md.value);
|
2023-10-02 12:33:45 +02:00
|
|
|
setsaved();
|
2024-01-08 10:55:12 +01:00
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
else if (!localdata)
|
|
|
|
{
|
|
|
|
showtemporaryinfo("cannot push empty data");
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
else if (pending)
|
|
|
|
{
|
|
|
|
console.log("pending query: save cancelled");
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
else if (saved)
|
|
|
|
{
|
|
|
|
console.log("nothing to save");
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
else
|
2023-01-26 00:32:00 +01:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
var content = md.value;
|
|
|
|
if ((content == "" && backup != "") || content == "null" || content == "undefined")
|
2023-01-25 15:41:21 +01:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
showtemporaryinfo("Invalid content '" + content + "', file '" + currentnote.title + "' not saved");
|
|
|
|
reject();
|
2023-01-25 15:41:21 +01:00
|
|
|
}
|
2024-01-08 10:55:12 +01:00
|
|
|
else
|
2023-01-25 15:41:21 +01:00
|
|
|
{
|
2024-01-08 10:55:12 +01:00
|
|
|
currentnote.pos = md.selectionStart;
|
|
|
|
currentnote.content = content;
|
|
|
|
putontop();
|
|
|
|
|
|
|
|
window.localStorage.setItem("data", JSON.stringify(localdata));
|
|
|
|
|
|
|
|
if (settings.sync)
|
|
|
|
{
|
|
|
|
var datatosend = JSON.stringify(localdata);
|
|
|
|
return encryptstring(datatosend)
|
|
|
|
.then(encrypted =>
|
|
|
|
{
|
|
|
|
console.log("sending data to php server...");
|
|
|
|
pending = true;
|
|
|
|
return queryremote({action: "push", data: encrypted})
|
|
|
|
})
|
|
|
|
.then(() =>
|
|
|
|
{
|
|
|
|
console.log("...data saved on server");
|
|
|
|
setsaved();
|
|
|
|
})
|
|
|
|
.catch(remotecallfailed)
|
|
|
|
.finally(() =>
|
|
|
|
{
|
|
|
|
pending = false;
|
|
|
|
if (content != md.value)
|
|
|
|
{
|
|
|
|
console.log("but content changed: will save again");
|
|
|
|
return datachanged();
|
|
|
|
}
|
|
|
|
else if (!saved)
|
|
|
|
{
|
|
|
|
console.log("save failed. Data unsaved on server. Will retry.");
|
|
|
|
return datachanged();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setsaved();
|
|
|
|
resolve();
|
|
|
|
}
|
2023-01-25 15:41:21 +01:00
|
|
|
}
|
2024-01-08 10:55:12 +01:00
|
|
|
}
|
|
|
|
});
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-09-23 22:51:59 +02:00
|
|
|
function escapeHtml(unsafe) {
|
2023-10-19 15:28:53 +02:00
|
|
|
return unsafe
|
|
|
|
.replace(/&/g, "&")
|
|
|
|
.replace(/</g, "<")
|
|
|
|
.replace(/>/g, ">")
|
|
|
|
.replace(/"/g, """)
|
|
|
|
.replace(/'/g, "'");
|
2023-09-23 22:51:59 +02:00
|
|
|
}
|
|
|
|
|
2023-09-25 13:22:22 +02:00
|
|
|
var languagekeywords = {
|
|
|
|
"sql": ["select", "from", "where", "and", "or"],
|
2023-11-10 12:37:07 +01:00
|
|
|
"js": ["var", "for", "if", "else"],
|
|
|
|
"zsh": ["sudo"]
|
2023-09-25 13:22:22 +02:00
|
|
|
}
|
|
|
|
|
2023-10-10 13:08:56 +02:00
|
|
|
function currentline()
|
|
|
|
{
|
|
|
|
return (md.value.substring(0, md.selectionStart).match(/\n/g) || []).length;
|
|
|
|
}
|
|
|
|
|
2023-10-11 21:04:54 +02:00
|
|
|
function lineatpos(pos)
|
|
|
|
{
|
|
|
|
return (md.value.substring(0, pos).match(/\n/g) || []).length;
|
|
|
|
}
|
|
|
|
|
2023-10-10 15:19:48 +02:00
|
|
|
function currentcol()
|
|
|
|
{
|
|
|
|
return md.selectionStart - Math.max(0, md.value.lastIndexOf("\n", md.selectionStart - 1)) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
function rawline(index)
|
2023-10-10 13:08:56 +02:00
|
|
|
{
|
|
|
|
return md.value.split("\n")[index];
|
|
|
|
}
|
|
|
|
|
2023-10-20 11:26:40 +02:00
|
|
|
var emptyline = "<br>";
|
|
|
|
function rawline2html(line, index, options)
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
line = escapeHtml(line);
|
|
|
|
|
|
|
|
// headings
|
|
|
|
if (line.startsWith("#"))
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(/(#* )/, "<span class='color-heading-mark'>$1</span>");
|
|
|
|
line = "<span class='color-heading'>" + line + "</span>";
|
2023-09-23 09:02:02 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
// bold and italics
|
|
|
|
var temp = line;
|
|
|
|
if (line.startsWith("* "))
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
temp = line.substring(2);
|
|
|
|
}
|
2023-11-15 21:45:45 +01:00
|
|
|
temp = temp.replace(/\*\*([^\*]*)\*\*/g, "<span class='color-bold'>**$1**</span>");
|
2023-11-16 10:47:53 +01:00
|
|
|
temp = temp.replace(/\*([^\*]*)\*/g, "<span class='color-emphasis'>*$1*</span>");
|
2023-09-25 09:32:37 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
if (line.startsWith("* "))
|
|
|
|
{
|
|
|
|
line = "* " + temp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line = temp;
|
|
|
|
}
|
2023-09-25 09:32:37 +02:00
|
|
|
|
2023-10-19 14:15:39 +02:00
|
|
|
// lists
|
|
|
|
markerslist.forEach(marker =>
|
|
|
|
{
|
2023-11-13 17:18:08 +01:00
|
|
|
if (line.startsWith(marker) && marker.trim())
|
2023-10-19 14:15:39 +02:00
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(marker, "<span class='color-list-marker'>" + marker + "</span>");
|
2023-10-19 14:15:39 +02:00
|
|
|
}
|
|
|
|
});
|
2023-10-10 11:55:21 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
// md header
|
|
|
|
if (index == 0 && line == "---")
|
|
|
|
{
|
|
|
|
options.header = true;
|
|
|
|
}
|
|
|
|
if (options.header)
|
|
|
|
{
|
|
|
|
if (index > 0 && line == "---")
|
2023-09-29 11:39:02 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
options.header = false;
|
2023-09-29 11:39:02 +02:00
|
|
|
}
|
2023-11-07 11:35:32 +01:00
|
|
|
line = line || emptyline;
|
2023-11-16 10:47:53 +01:00
|
|
|
line = "<span class='color-header'>" + line + "</span>";
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
2023-09-29 11:39:02 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
// code blocks
|
|
|
|
if (line.startsWith("```") && !options.code)
|
|
|
|
{
|
|
|
|
options.code = true;
|
|
|
|
options.language = line.substring(3);
|
2023-11-16 10:47:53 +01:00
|
|
|
line = "<div class='color-code'>" + line.replace(new RegExp("(" + options.language + ")"), "<span class='color-code-language'>$1</span>") + "</div>";
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
|
|
|
else if (line == "```" && options.code)
|
|
|
|
{
|
|
|
|
options.code = false;
|
|
|
|
options.language = "";
|
2023-11-15 21:24:38 +01:00
|
|
|
line = "<div class='color-code'>" + line + "</div>";
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
|
|
|
else if (options.code)
|
|
|
|
{
|
2023-11-13 17:18:08 +01:00
|
|
|
var comment = false;
|
|
|
|
if (line.match(/^\s*\/\//))
|
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = "<span class='color-code-comment'>" + line + "</span>";
|
2023-11-13 17:18:08 +01:00
|
|
|
comment = true;
|
|
|
|
}
|
2023-11-15 21:24:38 +01:00
|
|
|
line = "<div class='color-code'>" + (line || emptyline) + "</div>";
|
2023-11-13 17:18:08 +01:00
|
|
|
if (!comment && languagekeywords[options.language])
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
var keywords = languagekeywords[options.language];
|
|
|
|
keywords.forEach(keyword =>
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(new RegExp("\\b(" + keyword + ")\\b", "ig"), "<span class='color-code-keyword'>$1</span>");
|
2023-10-12 14:21:55 +02:00
|
|
|
});
|
2023-09-23 09:02:02 +02:00
|
|
|
}
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// internal links
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(/\[\[(.*)\]\]/g, "[[<span class='color-link'>$1</span>]]");
|
2023-10-12 14:21:55 +02:00
|
|
|
|
|
|
|
// comments
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(/<\!--(.*)/g, "<span class='color-comment'><!--$1</span>");
|
2023-09-23 09:02:02 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
if (line.includes("<!--") && !line.includes("-->"))
|
|
|
|
{
|
|
|
|
options.comment = true;
|
|
|
|
}
|
|
|
|
else if (options.comment)
|
|
|
|
{
|
2023-10-20 11:26:40 +02:00
|
|
|
line = line || emptyline;
|
2023-11-16 10:47:53 +01:00
|
|
|
line = "<span class='color-comment'>" + line
|
2023-10-12 14:21:55 +02:00
|
|
|
if (line.includes("-->"))
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
options.comment = false;
|
2023-09-23 09:02:02 +02:00
|
|
|
}
|
2023-10-12 14:21:55 +02:00
|
|
|
else
|
2023-09-23 09:02:02 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
line += "</span>";
|
2023-09-25 13:22:22 +02:00
|
|
|
}
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
2023-09-23 09:02:02 +02:00
|
|
|
|
2023-10-20 14:16:29 +02:00
|
|
|
line = line.replace(/\-\->/g, "--></span>");
|
2023-09-25 09:32:37 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
if (line.startsWith("// "))
|
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = "<span class='color-comment'>" + line + "</span>";
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
2023-10-06 17:47:27 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
// autocomplete snippets
|
|
|
|
if (index == currentline())
|
|
|
|
{
|
|
|
|
var raw = rawline(index);
|
|
|
|
var pos = currentcol();
|
|
|
|
var slashpos = raw.substring(0, pos).lastIndexOf("/");
|
|
|
|
if (slashpos > -1)
|
2023-10-06 17:47:27 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
var spacepos = raw.substring(0, pos).lastIndexOf(" ");
|
|
|
|
if (slashpos > spacepos)
|
2023-10-06 17:47:27 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
var snippetpart = raw.substring(slashpos);
|
2023-10-17 17:11:04 +02:00
|
|
|
var matching = snippets
|
|
|
|
.filter(s => s.command.startsWith(snippetpart))
|
|
|
|
.map(s => s.command.substring(1));
|
|
|
|
|
2023-11-15 21:19:20 +01:00
|
|
|
if (matching.length)
|
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line += "<span class='color-autocomplete'>";
|
2023-11-15 21:19:20 +01:00
|
|
|
line += matching.join().substr(pos - slashpos - 1);
|
|
|
|
line += "</span>";
|
|
|
|
}
|
2023-10-06 17:47:27 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
2023-10-23 14:46:48 +02:00
|
|
|
|
|
|
|
// todo.txt
|
2023-10-25 11:28:12 +02:00
|
|
|
if (currentistodo())
|
2023-10-23 14:46:48 +02:00
|
|
|
{
|
|
|
|
if (line.startsWith("x "))
|
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = "<span class='color-todo-complete'>" + line + "</span>";
|
2023-10-23 14:46:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(/(\(\w\))/g, "<span class='color-todo-priority'>$1</span>");
|
|
|
|
line = line.replace(/(@\w*)/g, "<span class='color-todo-project'>$1</span>");
|
|
|
|
line = line.replace(/(\s\+\w*)/g, "<span class='color-todo-context'>$1</span>");
|
2023-10-23 14:46:48 +02:00
|
|
|
}
|
|
|
|
}
|
2023-11-15 21:19:20 +01:00
|
|
|
|
|
|
|
// inline code
|
|
|
|
line = line.replace(/`(.*)`/, "<span class='color-code'>`$1`</span>");
|
|
|
|
|
|
|
|
// links
|
2023-11-16 10:47:53 +01:00
|
|
|
line = line.replace(/(http[^\s]*)/, "<span class='color-link'>$1</span>");
|
2023-11-15 21:19:20 +01:00
|
|
|
|
2023-10-19 14:15:50 +02:00
|
|
|
return line;
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
2023-10-06 17:47:27 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
function applycolors(currentonly)
|
|
|
|
{
|
|
|
|
if (!settings.colors)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2023-10-06 17:47:27 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
var options =
|
|
|
|
{
|
|
|
|
header: false,
|
|
|
|
code: false,
|
|
|
|
comment: false,
|
|
|
|
language: ""
|
|
|
|
};
|
2023-10-10 15:19:48 +02:00
|
|
|
|
2023-10-20 11:40:16 +02:00
|
|
|
var linediv = null;
|
2023-10-12 14:21:55 +02:00
|
|
|
if (currentonly)
|
|
|
|
{
|
|
|
|
var index = currentline();
|
2023-10-20 11:40:16 +02:00
|
|
|
linediv = document.getElementById("line" + index);
|
2023-10-12 14:21:55 +02:00
|
|
|
options = JSON.parse(linediv.getAttribute("tag"));
|
2023-10-19 14:15:50 +02:00
|
|
|
var line = rawline(index);
|
2023-10-20 11:26:40 +02:00
|
|
|
line = rawline2html(line, index, options);
|
|
|
|
linediv.innerHTML = line || emptyline;
|
2023-10-12 14:21:55 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
console.log("redrawing all colored div");
|
|
|
|
var lines = md.value.split("\n");
|
|
|
|
var i = 0;
|
|
|
|
for (; i < lines.length; i++)
|
2023-10-10 15:19:48 +02:00
|
|
|
{
|
2023-10-20 11:40:16 +02:00
|
|
|
linediv = document.getElementById("line" + i);
|
2023-10-12 14:21:55 +02:00
|
|
|
if (!linediv)
|
2023-10-10 15:19:48 +02:00
|
|
|
{
|
2023-10-12 14:21:55 +02:00
|
|
|
linediv = document.createElement("div");
|
|
|
|
colored.appendChild(linediv);
|
2023-10-10 15:19:48 +02:00
|
|
|
}
|
2023-10-12 14:21:55 +02:00
|
|
|
linediv.setAttribute("id", "line" + i);
|
|
|
|
linediv.setAttribute("tag", JSON.stringify(options));
|
2023-10-20 11:26:40 +02:00
|
|
|
linediv.innerHTML = rawline2html(lines[i], i, options) || emptyline;
|
2023-10-20 11:40:16 +02:00
|
|
|
}
|
2023-10-10 15:19:48 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
// remove remanining
|
|
|
|
linediv = document.getElementById("line" + (i++));
|
|
|
|
while (linediv)
|
|
|
|
{
|
|
|
|
colored.removeChild(linediv);
|
|
|
|
linediv = document.getElementById("line" + (i++));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-23 09:02:02 +02:00
|
|
|
|
2023-10-12 14:21:55 +02:00
|
|
|
function editorinput()
|
|
|
|
{
|
2023-10-12 14:39:43 +02:00
|
|
|
// criteria to improve. Or redraw only after?
|
2023-10-12 14:21:55 +02:00
|
|
|
var multiline = md.value.substring(md.selectionStart, md.selectionEnd).includes("\n");
|
|
|
|
applycolors(!multiline && event.data && (event.inputType == "insertText" || event.inputType == "deleteContentBackward" || event.inputType == "deleteContentForward"));
|
|
|
|
datachanged();
|
2023-12-20 08:39:41 +01:00
|
|
|
resize();
|
2023-09-23 09:02:02 +02:00
|
|
|
}
|
|
|
|
|
2023-01-25 23:50:48 +01:00
|
|
|
function datachanged()
|
|
|
|
{
|
|
|
|
saved = false;
|
2023-11-29 10:44:10 +01:00
|
|
|
unsavedmark.hidden = !settings.sync;
|
2023-01-25 23:50:48 +01:00
|
|
|
|
2024-01-08 10:55:12 +01:00
|
|
|
return postpone()
|
2023-01-25 23:50:48 +01:00
|
|
|
.then(save);
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function timestamp()
|
|
|
|
{
|
2023-01-30 10:08:15 +01:00
|
|
|
var utc = new Date();
|
|
|
|
var loc = new Date(utc - utc.getTimezoneOffset() * 60 * 1000);
|
|
|
|
|
|
|
|
return loc.toISOString().replace("T", " ").replace(/\..*/, "").replace(/:/g, ".");
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-11-15 08:44:01 +01:00
|
|
|
function quicknewnote()
|
|
|
|
{
|
|
|
|
loadnote(timestamp());
|
|
|
|
datachanged();
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function startnewnote()
|
|
|
|
{
|
2023-10-04 08:44:10 +02:00
|
|
|
var title = prompt("Note title: ", timestamp());
|
|
|
|
if (title)
|
|
|
|
{
|
|
|
|
loadnote(title);
|
2023-10-09 12:46:01 +02:00
|
|
|
datachanged();
|
2023-10-04 08:44:10 +02:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function showhelp()
|
|
|
|
{
|
|
|
|
var help = ["# Notes"];
|
|
|
|
help.push("## Shortcuts");
|
|
|
|
|
|
|
|
commands
|
|
|
|
.filter(command => Boolean(command.shortcut))
|
2024-01-03 16:18:16 +01:00
|
|
|
.forEach(command => help.push(command.hint + ": " + command.shortcut.toLowerCase()));
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
help.push("## Snippets");
|
|
|
|
snippets.forEach(snippet =>
|
|
|
|
{
|
|
|
|
help.push(snippet.hint + ": " + snippet.command);
|
|
|
|
});
|
|
|
|
|
|
|
|
help.push("## Libs");
|
|
|
|
help.push("[Showdown](https://showdownjs.com/)");
|
2023-02-05 10:04:07 +01:00
|
|
|
help.push("[vis-network](https://visjs.org/)");
|
2023-09-01 10:40:28 +02:00
|
|
|
help.push("[openpgpjs](https://openpgpjs.org/)");
|
|
|
|
help.push("[jszip](https://stuk.github.io/jszip/)");
|
|
|
|
help.push("[FileSaver](http://eligrey.com)");
|
2023-01-26 08:45:56 +01:00
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
help.push("## Inspiration");
|
|
|
|
help.push("[rwtxt](https://rwtxt.com)");
|
|
|
|
help.push("[Offline Notepad](https://offlinenotepad.com/)");
|
|
|
|
help.push("[Writemonkey3](http://writemonkey.com/wm3/)");
|
|
|
|
help.push("[Sublime Text](https://www.sublimetext.com/)");
|
2023-01-26 08:45:56 +01:00
|
|
|
help.push("[Notion](https://www.notion.so/)");
|
|
|
|
help.push("[Calmly Writer](https://calmlywriter.com/)");
|
2023-01-30 08:48:15 +01:00
|
|
|
help.push("[Cryptee](https://crypt.ee/)");
|
2023-01-18 12:34:55 +01:00
|
|
|
|
2023-09-28 13:55:38 +02:00
|
|
|
help.push("##Sources");
|
|
|
|
help.push("https://github.com/quenousimporte/notes");
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
bindfile(
|
|
|
|
{
|
|
|
|
title: "Help",
|
|
|
|
content: help.join("\n")
|
|
|
|
});
|
|
|
|
|
|
|
|
if (preview.hidden)
|
|
|
|
{
|
|
|
|
togglepreview();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggletitle()
|
|
|
|
{
|
|
|
|
if (title.hidden)
|
|
|
|
{
|
|
|
|
title.hidden = false;
|
|
|
|
title.focus();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
title.hidden = true;
|
|
|
|
md.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function selectnote()
|
|
|
|
{
|
2023-11-07 09:13:45 +01:00
|
|
|
return searchinlist(
|
2023-11-15 17:57:11 +01:00
|
|
|
localdata.map(n =>
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
text: n.title,
|
|
|
|
suffix: gettags(n).map(t => tagmark + t)
|
|
|
|
}
|
|
|
|
}));
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function searchautocomplete()
|
|
|
|
{
|
2023-11-07 09:13:45 +01:00
|
|
|
selectnote().then(selected =>
|
|
|
|
{
|
2023-11-17 11:57:58 +01:00
|
|
|
insertautocomplete(selected.text || selected);
|
2023-11-07 09:13:45 +01:00
|
|
|
});
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function searchandloadnote()
|
|
|
|
{
|
2023-11-07 09:13:45 +01:00
|
|
|
selectnote().then(selected =>
|
|
|
|
{
|
2023-11-16 10:47:14 +01:00
|
|
|
loadnote(selected.text || selected);
|
2023-11-07 09:13:45 +01:00
|
|
|
});
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-12-12 09:57:29 +01:00
|
|
|
function istodo(note)
|
|
|
|
{
|
|
|
|
return note.title.includes("todo") || gettags(note).includes("todo");
|
|
|
|
}
|
|
|
|
|
2023-10-25 11:28:12 +02:00
|
|
|
function currentistodo()
|
|
|
|
{
|
2023-12-12 09:57:29 +01:00
|
|
|
return istodo(currentnote);
|
2023-10-25 11:28:12 +02:00
|
|
|
}
|
|
|
|
|
2023-12-12 09:57:29 +01:00
|
|
|
function sorttodotxt(note)
|
2023-10-25 11:28:12 +02:00
|
|
|
{
|
2023-12-12 09:57:29 +01:00
|
|
|
var hat = headerandtext(note);
|
|
|
|
var olditems = hat.text.split("\n");
|
|
|
|
var prio = [];
|
|
|
|
var std = [];
|
|
|
|
var done = [];
|
|
|
|
olditems.forEach(item =>
|
2023-10-25 11:28:12 +02:00
|
|
|
{
|
2023-12-12 09:57:29 +01:00
|
|
|
if (item)
|
2023-10-25 11:28:12 +02:00
|
|
|
{
|
2023-12-12 09:57:29 +01:00
|
|
|
if (item.startsWith("("))
|
2023-10-25 11:28:12 +02:00
|
|
|
{
|
2023-12-12 09:57:29 +01:00
|
|
|
item = item.substring(4);
|
|
|
|
var priority = String.fromCharCode(65 + prio.length);
|
|
|
|
prio.push(`(${priority}) ${item}`);
|
2023-10-25 11:28:12 +02:00
|
|
|
}
|
2023-12-12 09:57:29 +01:00
|
|
|
else if (item.startsWith("x "))
|
|
|
|
{
|
|
|
|
done.push(item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std.push(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
prio = prio.sort((a,b) => a.localeCompare(b));
|
|
|
|
done = done.sort((a,b) => a.localeCompare(b));
|
|
|
|
var all = prio.concat(std).concat(done);
|
|
|
|
note.content = hat.header + all.join("\n");
|
|
|
|
}
|
2023-10-25 11:48:08 +02:00
|
|
|
|
2023-12-12 09:57:29 +01:00
|
|
|
function sortcurrentastodo()
|
|
|
|
{
|
|
|
|
if (currentistodo())
|
|
|
|
{
|
|
|
|
sorttodotxt(currentnote);
|
|
|
|
seteditorcontent(currentnote.content);
|
2023-10-25 11:28:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-09 12:45:50 +02:00
|
|
|
function searchandreplace()
|
|
|
|
{
|
|
|
|
var oldvalue = prompt("Search:");
|
|
|
|
if (!oldvalue)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var newvalue = prompt("Replace by:");
|
|
|
|
if (!newvalue)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var doit = confirm(`Replace '${oldvalue}' by '${newvalue}'?`);
|
|
|
|
if (!doit)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
seteditorcontent(md.value.replaceAll(oldvalue, newvalue));
|
|
|
|
}
|
|
|
|
|
2023-10-01 10:21:41 +02:00
|
|
|
function notesbysize()
|
|
|
|
{
|
|
|
|
var sortedtitles = localdata.sort( (n1,n2) => { return n2.content.length - n1.content.length})
|
|
|
|
.map(n => n.title + ": " + formatsize(n.content.length));
|
|
|
|
|
|
|
|
searchinlist(sortedtitles)
|
|
|
|
.then(titlewithsize =>
|
|
|
|
{
|
|
|
|
var title = titlewithsize.substring(0, titlewithsize.lastIndexOf(": "));
|
|
|
|
loadnote(title);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-01-30 08:48:15 +01:00
|
|
|
function renamereferences(newname)
|
|
|
|
{
|
|
|
|
localdata
|
|
|
|
.filter(note => note != currentnote)
|
|
|
|
.forEach(note =>
|
|
|
|
{
|
|
|
|
note.content = note.content.replaceAll("[[" + currentnote.title + "]]", "[[" + newname + "]]");
|
2023-09-11 09:57:00 +02:00
|
|
|
});
|
2023-01-30 08:48:15 +01:00
|
|
|
}
|
|
|
|
|
2023-09-29 17:57:22 +02:00
|
|
|
function restoredeleted()
|
|
|
|
{
|
|
|
|
var trash = window.localStorage.getItem("trash");
|
|
|
|
if (trash)
|
|
|
|
{
|
|
|
|
trash = JSON.parse(window.localStorage.getItem("trash"));
|
|
|
|
searchinlist(trash.map(note => note.title + " - deleted on " + note.deletiondate))
|
|
|
|
.then(item =>
|
|
|
|
{
|
|
|
|
if (confirm("Restore " + item + "?"))
|
|
|
|
{
|
|
|
|
var title = item.split(" - deleted on ").shift();
|
|
|
|
var stamp = item.split(" - deleted on ").pop();
|
2023-09-29 22:51:07 +02:00
|
|
|
var index = trash.findIndex(n => n.title == title && (!n.deletiondate || n.deletiondate == stamp));
|
2023-09-29 17:57:22 +02:00
|
|
|
if (index > -1)
|
|
|
|
{
|
|
|
|
var notetorestore = trash.splice(index, 1).pop();
|
|
|
|
notetorestore.title += " - restored on " + timestamp();
|
|
|
|
delete notetorestore.deletiondate;
|
|
|
|
localdata.unshift(notetorestore);
|
|
|
|
loadnote(notetorestore.title);
|
|
|
|
datachanged();
|
2023-09-29 22:45:13 +02:00
|
|
|
window.localStorage.setItem("trash", JSON.stringify(trash));
|
2023-09-29 17:57:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-01 13:54:49 +01:00
|
|
|
function deletenote(note)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-09-29 11:40:00 +02:00
|
|
|
var trash = JSON.parse(window.localStorage.getItem("trash") || "[]");
|
2023-09-29 17:57:22 +02:00
|
|
|
note.deletiondate = timestamp();
|
2023-02-01 13:54:49 +01:00
|
|
|
trash.push(note);
|
|
|
|
window.localStorage.setItem("trash", JSON.stringify(trash));
|
2023-01-30 08:48:15 +01:00
|
|
|
|
2023-02-01 13:54:49 +01:00
|
|
|
localdata = localdata.filter(n => n != note);
|
2023-01-27 09:22:09 +01:00
|
|
|
|
2023-02-01 13:54:49 +01:00
|
|
|
renamereferences(note.title + " (deleted)");
|
2023-10-11 21:11:27 +02:00
|
|
|
datachanged();
|
2023-02-01 13:54:49 +01:00
|
|
|
}
|
2023-01-30 08:48:15 +01:00
|
|
|
|
2023-02-01 13:54:49 +01:00
|
|
|
function deletecurrentnote()
|
|
|
|
{
|
|
|
|
if (confirm('delete "' + currentnote.title + '"?'))
|
|
|
|
{
|
|
|
|
deletenote(currentnote);
|
2023-01-27 09:22:09 +01:00
|
|
|
loadlast();
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function restore()
|
|
|
|
{
|
|
|
|
if (confirm('restore "' + currentnote.title + '"?'))
|
|
|
|
{
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(backup);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-20 09:52:17 +02:00
|
|
|
function insertheader()
|
|
|
|
{
|
|
|
|
if (preview.hidden && !md.value.startsWith("---\n"))
|
|
|
|
{
|
2023-11-16 10:47:14 +01:00
|
|
|
var headers = defaultheaders();
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(headers + md.value);
|
2023-07-20 09:52:17 +02:00
|
|
|
setpos(27);
|
|
|
|
}
|
|
|
|
resize();
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function splitshortcut(s)
|
|
|
|
{
|
|
|
|
var r = {};
|
|
|
|
s = s.split("+");
|
|
|
|
r.key = s.pop();
|
|
|
|
s.forEach(e => {
|
|
|
|
r[e] = true;
|
|
|
|
})
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2023-10-03 13:37:30 +02:00
|
|
|
function shortcutmatches(event, shortcut)
|
|
|
|
{
|
|
|
|
var s = splitshortcut(shortcut);
|
2023-12-06 09:26:08 +01:00
|
|
|
return (event.key == s.key && !(s.ctrl && !event.ctrlKey && !event.altKey) && !(s.shift && !event.shiftKey) && !(s.alt && !event.altKey))
|
2023-10-03 13:37:30 +02:00
|
|
|
}
|
|
|
|
|
2023-01-26 08:36:12 +01:00
|
|
|
function executecommand(command)
|
|
|
|
{
|
|
|
|
if (!command.allowunsaved && !saved)
|
|
|
|
{
|
|
|
|
showtemporaryinfo("Cannot perform '" + command.hint + "' because current note is not saved.");
|
|
|
|
}
|
2023-11-09 09:57:24 +01:00
|
|
|
else if (command.remoteonly && !settings.sync)
|
2023-07-04 17:15:34 +02:00
|
|
|
{
|
|
|
|
showtemporaryinfo(command.hint + " is not available in local mode.");
|
|
|
|
}
|
2023-01-26 08:36:12 +01:00
|
|
|
else if (command.action)
|
|
|
|
{
|
|
|
|
command.action();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-04 10:22:57 +02:00
|
|
|
function esc(event)
|
|
|
|
{
|
|
|
|
if (!searchdialog.hidden)
|
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
searchdialog.hidden = true;
|
|
|
|
filter.placeholder = "Search...";
|
|
|
|
md.focus();
|
|
|
|
}
|
2023-11-14 11:52:33 +01:00
|
|
|
else if (settings.uselinkpopup && typeof linkdialog != "undefined")
|
|
|
|
{
|
|
|
|
removelinkdialog();
|
|
|
|
}
|
2023-07-04 10:22:57 +02:00
|
|
|
else if (currentnote.title == "Help" || currentnote.title == "Search result")
|
|
|
|
{
|
|
|
|
loadlast();
|
|
|
|
}
|
|
|
|
else if (networkpage.hidden == false)
|
|
|
|
{
|
|
|
|
networkpage.hidden = true;
|
2023-09-24 21:54:12 +02:00
|
|
|
toggleeditor(false);
|
2023-07-04 10:22:57 +02:00
|
|
|
}
|
|
|
|
else if (preview.hidden == false)
|
|
|
|
{
|
|
|
|
togglepreview();
|
|
|
|
}
|
2023-09-14 12:02:10 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
commandpalette();
|
|
|
|
}
|
2023-07-04 10:22:57 +02:00
|
|
|
}
|
|
|
|
|
2023-12-04 10:40:28 +01:00
|
|
|
function boldify()
|
|
|
|
{
|
|
|
|
var pos = currentrange();
|
|
|
|
var newcontent;
|
|
|
|
var offset = 2;
|
|
|
|
if (md.value.substr(pos.start - 2, 2) == "**" && md.value.substr(pos.end, 2) == "**")
|
|
|
|
{
|
|
|
|
newcontent = md.value.substr(0, pos.start - 2) + md.value.substr(pos.start, pos.end - pos.start) + md.value.substr(pos.end + 2);
|
|
|
|
offset = -2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newcontent = md.value.substr(0, pos.start) + "**" + md.value.substr(pos.start, pos.end - pos.start) + "**" + md.value.substr(pos.end);
|
|
|
|
}
|
|
|
|
|
|
|
|
seteditorcontent(newcontent);
|
|
|
|
md.setSelectionRange(pos.start + offset, pos.end + offset);
|
|
|
|
}
|
|
|
|
|
2023-12-08 14:19:54 +01:00
|
|
|
function snippetautocomplete()
|
|
|
|
{
|
|
|
|
var tocursor = md.value.substr(0, md.selectionStart)
|
|
|
|
var slashindex = tocursor.lastIndexOf("/");
|
|
|
|
if (slashindex > tocursor.lastIndexOf(" ") && slashindex > tocursor.lastIndexOf("\n"))
|
|
|
|
{
|
|
|
|
var commandbegin = tocursor.substr(slashindex);
|
|
|
|
var snippet = snippets.find(s => s.command.startsWith(commandbegin));
|
|
|
|
if (snippet)
|
|
|
|
{
|
|
|
|
insert(snippet.insert, snippet.cursor, commandbegin.length);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function mainkeydownhandler()
|
|
|
|
{
|
2023-01-25 23:50:48 +01:00
|
|
|
if (event.key == "Escape")
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-07-04 10:22:57 +02:00
|
|
|
esc(event);
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
2023-01-25 15:41:21 +01:00
|
|
|
else if (!searchdialog.hidden && (event.key == "Tab" || event.keyCode == "40" || event.keyCode == "38"))
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
fileindex += (event.shiftKey || event.keyCode == "38") ? -1 : 1;
|
|
|
|
fileindex = Math.min(fileindex, filteredlist.children.length - 1);
|
|
|
|
fileindex = Math.max(fileindex, 0);
|
|
|
|
applyfileindex();
|
|
|
|
}
|
2023-10-19 08:46:09 +02:00
|
|
|
else if (event.ctrlKey && event.key == " " || event.key == "F1")
|
2023-02-05 10:46:29 +01:00
|
|
|
{
|
|
|
|
commandpalette();
|
2023-10-19 08:46:09 +02:00
|
|
|
event.preventDefault();
|
2023-02-05 10:46:29 +01:00
|
|
|
}
|
2023-12-04 10:40:28 +01:00
|
|
|
else if (event.ctrlKey && event.key == "b" && md.selectionStart < md.selectionEnd)
|
|
|
|
{
|
|
|
|
boldify();
|
2023-12-04 10:51:41 +01:00
|
|
|
event.preventDefault();
|
2023-12-04 10:40:28 +01:00
|
|
|
}
|
2023-10-11 21:04:54 +02:00
|
|
|
else if (event.ctrlKey && event.shiftKey && (event.keyCode == "40" || event.keyCode == "38"))
|
2023-09-26 10:42:06 +02:00
|
|
|
{
|
2023-12-04 10:40:57 +01:00
|
|
|
var pos = currentrange();
|
2023-10-11 21:04:54 +02:00
|
|
|
var direction = event.keyCode == "40" ? 1 : -1;
|
|
|
|
var start = lineatpos(md.selectionStart);
|
|
|
|
var end = lineatpos(md.selectionEnd);
|
2023-09-26 10:42:06 +02:00
|
|
|
var lines = md.value.split("\n");
|
2023-10-11 21:04:54 +02:00
|
|
|
if (direction > 0 && end < lines.length || direction < 0 && start > 0)
|
2023-09-26 10:42:06 +02:00
|
|
|
{
|
2023-10-11 21:04:54 +02:00
|
|
|
var block = lines.splice(start, end - start + 1);
|
|
|
|
lines.splice(start + direction, 0, ...block);
|
2023-09-26 10:42:06 +02:00
|
|
|
seteditorcontent(lines.join("\n"));
|
2023-10-11 21:04:54 +02:00
|
|
|
var posshift = direction > 0 ? lines[start].length + 1 : - 1 - lines[end].length;
|
|
|
|
md.setSelectionRange(pos.start + posshift, pos.end + posshift);
|
|
|
|
|
2023-09-26 10:42:06 +02:00
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
2023-10-03 13:57:56 +02:00
|
|
|
else if (event.ctrlKey || event.altKey)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-10-03 13:37:30 +02:00
|
|
|
// notes shortcuts
|
|
|
|
var note = localdata.find(n =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-10-03 13:37:30 +02:00
|
|
|
var shortcut = n.content.match(/shortcut: (.*)/);
|
2023-10-03 13:43:19 +02:00
|
|
|
if (shortcut && shortcutmatches(event, shortcut[1]))
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-10-03 13:37:30 +02:00
|
|
|
console.log("Loading note '" + n.title + "' from header shortcut " + shortcut[1]);
|
2023-10-03 13:43:19 +02:00
|
|
|
event.preventDefault();
|
2023-10-03 13:37:30 +02:00
|
|
|
loadnote(n.title);
|
2023-10-03 13:43:19 +02:00
|
|
|
return true;
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
2023-10-03 13:37:30 +02:00
|
|
|
return false;
|
2023-01-25 15:41:21 +01:00
|
|
|
});
|
2023-10-03 13:37:30 +02:00
|
|
|
|
|
|
|
// commands shortcuts
|
|
|
|
if (!note)
|
|
|
|
{
|
|
|
|
commands.filter(c => c.shortcut)
|
|
|
|
.every(command =>
|
|
|
|
{
|
|
|
|
if (shortcutmatches(event, command.shortcut))
|
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
executecommand(command);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
2023-01-25 15:41:21 +01:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-01-21 21:05:39 +01:00
|
|
|
function setwindowtitle()
|
|
|
|
{
|
2023-11-15 22:00:39 +01:00
|
|
|
document.title = currentnote.title;
|
2023-01-21 21:05:39 +01:00
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function ontitlechange()
|
|
|
|
{
|
2023-01-26 12:00:32 +01:00
|
|
|
if (localdata.find(n => n.title == title.value))
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-01-26 12:00:32 +01:00
|
|
|
showtemporaryinfo(title.value + " alreday exists");
|
2023-01-18 12:34:55 +01:00
|
|
|
title.value = currentnote.title;
|
2023-01-26 12:00:32 +01:00
|
|
|
return;
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
2023-01-26 12:00:32 +01:00
|
|
|
|
|
|
|
// rename internal references
|
|
|
|
localdata
|
|
|
|
.filter(note => note != currentnote)
|
|
|
|
.forEach(note =>
|
|
|
|
{
|
|
|
|
note.content = note.content.replaceAll("[[" + currentnote.title + "]]", "[[" + title.value + "]]");
|
|
|
|
});
|
|
|
|
|
|
|
|
currentnote.title = title.value;
|
|
|
|
|
|
|
|
datachanged();
|
|
|
|
setwindowtitle();
|
2023-07-21 10:34:43 +02:00
|
|
|
|
|
|
|
if (!settings.titlebydefault)
|
|
|
|
{
|
|
|
|
toggletitle();
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
2023-08-16 17:03:38 +02:00
|
|
|
function simplifystring(str)
|
|
|
|
{
|
|
|
|
return str.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, "");
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function applyfilter()
|
|
|
|
{
|
|
|
|
[...filteredlist.children].forEach(div =>
|
|
|
|
{
|
2023-08-16 17:03:38 +02:00
|
|
|
div.hidden = simplifystring(div.textContent).indexOf(simplifystring(filter.value)) < 0;
|
2023-01-18 12:34:55 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
fileindex = 0;
|
|
|
|
applyfileindex();
|
|
|
|
}
|
|
|
|
|
|
|
|
function backspace(nb)
|
|
|
|
{
|
|
|
|
var pos = getpos();
|
|
|
|
var c = md.value;
|
2023-09-24 22:00:20 +02:00
|
|
|
seteditorcontent(c.substring(0, pos - nb) + c.substring(pos));
|
2023-01-18 12:34:55 +01:00
|
|
|
setpos(pos - nb);
|
|
|
|
}
|
|
|
|
|
|
|
|
function editorkeydown()
|
|
|
|
{
|
|
|
|
if (event.key == "Enter")
|
|
|
|
{
|
2023-01-21 16:07:14 +01:00
|
|
|
var line = md.value.substring(0, getpos()).split("\n").pop();
|
|
|
|
markerslist.filter(marker => line.startsWith(marker))
|
2023-06-07 09:43:12 +02:00
|
|
|
.every(marker =>
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
|
|
|
event.preventDefault();
|
2023-01-21 16:07:14 +01:00
|
|
|
if (line != marker)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2024-01-18 09:32:41 +01:00
|
|
|
insert("\n" + marker.replace("[x]", "[ ]"));
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
backspace(marker.length);
|
|
|
|
}
|
2023-06-07 09:43:12 +02:00
|
|
|
return false;
|
2023-01-18 12:34:55 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
else if (event.key === "Tab")
|
|
|
|
{
|
|
|
|
event.preventDefault();
|
2023-12-08 14:19:54 +01:00
|
|
|
if (!snippetautocomplete())
|
|
|
|
{
|
|
|
|
var init = currentrange();
|
|
|
|
var range = getlinesrange();
|
|
|
|
range.start--;
|
|
|
|
range.end--;
|
|
|
|
var selection = md.value.substring(range.start, range.end);
|
|
|
|
var newtext;
|
|
|
|
if (event.shiftKey)
|
|
|
|
{
|
|
|
|
newtext = selection.replaceAll("\n ", "\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newtext = selection.replaceAll("\n", "\n ");
|
|
|
|
}
|
|
|
|
seteditorcontent(md.value.substring(0, range.start)
|
|
|
|
+ newtext
|
|
|
|
+ md.value.substring(range.end));
|
2023-02-02 21:42:07 +01:00
|
|
|
|
2023-12-08 14:19:54 +01:00
|
|
|
var shift = 0;
|
|
|
|
if (newtext.length < selection.length)
|
|
|
|
{
|
|
|
|
shift = -4;
|
|
|
|
}
|
|
|
|
else if (newtext.length > selection.length)
|
|
|
|
{
|
|
|
|
shift = 4;
|
|
|
|
}
|
2023-02-03 12:56:31 +01:00
|
|
|
|
2023-12-08 14:19:54 +01:00
|
|
|
md.selectionStart = init.start + shift;
|
|
|
|
md.selectionEnd = init.end + (newtext.length - selection.length);
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
2023-01-21 21:25:09 +01:00
|
|
|
else if (event.key === "[" && before(1) == "[")
|
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
insert("[");
|
|
|
|
searchautocomplete();
|
|
|
|
}
|
2023-01-24 22:17:48 +01:00
|
|
|
else if (settings.tagautocomplete && event.key == " " && before(1) == "," && md.value.substring(0, getpos()).split("\n").pop().startsWith("tags: "))
|
2023-01-21 21:25:09 +01:00
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
// search in tags list
|
|
|
|
console.log(event.key);
|
|
|
|
tagslist()
|
2023-01-26 12:01:15 +01:00
|
|
|
.then(tag =>
|
2023-01-21 21:25:09 +01:00
|
|
|
{
|
|
|
|
insert(" " + tag);
|
|
|
|
md.focus();
|
|
|
|
})
|
|
|
|
}
|
2023-01-24 22:17:48 +01:00
|
|
|
else
|
2023-01-21 21:25:09 +01:00
|
|
|
{
|
|
|
|
var snippet = snippets.find(s => before(s.command.length - 1) + event.key == s.command);
|
|
|
|
if (snippet)
|
|
|
|
{
|
|
|
|
event.preventDefault();
|
|
|
|
insert(snippet.insert, snippet.cursor, snippet.command.length - 1);
|
|
|
|
}
|
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function insertautocomplete(selectednote)
|
|
|
|
{
|
|
|
|
md.focus();
|
|
|
|
insert(selectednote + "]] ");
|
|
|
|
}
|
|
|
|
|
|
|
|
function togglepreview()
|
|
|
|
{
|
2024-01-12 13:46:48 +01:00
|
|
|
preview.innerHTML = md2html(md.value);
|
2023-09-24 21:54:12 +02:00
|
|
|
toggleeditor(!md.hidden);
|
2023-01-18 12:34:55 +01:00
|
|
|
preview.hidden = !preview.hidden;
|
|
|
|
|
|
|
|
if (preview.hidden)
|
|
|
|
{
|
|
|
|
resize();
|
|
|
|
md.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-05 10:04:07 +01:00
|
|
|
function withsubs()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2023-09-11 09:57:00 +02:00
|
|
|
descendants(currentnote);
|
2023-02-05 10:04:07 +01:00
|
|
|
}
|
|
|
|
catch (err)
|
|
|
|
{
|
|
|
|
showtemporaryinfo(err);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-09-11 09:57:00 +02:00
|
|
|
var tempnote =
|
2023-02-05 10:04:07 +01:00
|
|
|
{
|
|
|
|
title: currentnote.title + " (with subnotes)",
|
2023-07-17 11:25:08 +02:00
|
|
|
content: md.value
|
2023-02-05 10:04:07 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
var kids = children(tempnote);
|
|
|
|
while (kids.length)
|
|
|
|
{
|
|
|
|
kids.forEach(kid =>
|
|
|
|
{
|
2023-02-05 15:11:26 +01:00
|
|
|
var kidcontent = kid.content;
|
|
|
|
if (kidcontent.startsWith("---\n"))
|
|
|
|
{
|
|
|
|
var pos = kidcontent.indexOf("---\n", 4);
|
|
|
|
kidcontent = kidcontent.substring(pos + 4);
|
|
|
|
}
|
|
|
|
tempnote.content = tempnote.content.replaceAll("[[" + kid.title + "]]", kidcontent);
|
2023-02-05 10:04:07 +01:00
|
|
|
});
|
|
|
|
kids = children(tempnote);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tempnote;
|
|
|
|
}
|
|
|
|
|
|
|
|
function togglepreviewwithsubs()
|
|
|
|
{
|
|
|
|
var note = withsubs();
|
|
|
|
if (note)
|
|
|
|
{
|
|
|
|
preview.innerHTML = md2html(note.content);
|
2023-09-24 21:54:12 +02:00
|
|
|
toggleeditor(!md.hidden);
|
2023-02-05 10:04:07 +01:00
|
|
|
preview.hidden = !preview.hidden;
|
|
|
|
|
|
|
|
if (preview.hidden)
|
|
|
|
{
|
|
|
|
resize();
|
|
|
|
md.focus();
|
2023-09-11 09:57:00 +02:00
|
|
|
}
|
|
|
|
}
|
2023-02-05 10:04:07 +01:00
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
function bindfile(note)
|
|
|
|
{
|
2023-01-30 08:48:15 +01:00
|
|
|
var changed = currentnote != note;
|
2023-01-18 12:34:55 +01:00
|
|
|
|
|
|
|
backup = note.content;
|
|
|
|
currentnote = note;
|
|
|
|
title.value = note.title;
|
2023-01-21 21:05:39 +01:00
|
|
|
setwindowtitle();
|
2023-01-18 12:34:55 +01:00
|
|
|
|
2023-10-11 21:11:27 +02:00
|
|
|
seteditorcontent(note.content || "", true);
|
2023-01-27 15:46:25 +01:00
|
|
|
|
2023-01-30 08:48:15 +01:00
|
|
|
if (changed)
|
|
|
|
{
|
|
|
|
md.style.height = "0px";
|
2023-09-11 09:57:00 +02:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
resize();
|
2023-01-27 15:46:25 +01:00
|
|
|
|
2023-12-08 14:23:05 +01:00
|
|
|
setpos(note.pos || 0);
|
|
|
|
|
2023-01-25 09:32:44 +01:00
|
|
|
if (!issplit() && searchdialog.hidden)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-12-08 14:23:05 +01:00
|
|
|
// force to scroll to cursor pos
|
|
|
|
md.blur();
|
2023-01-18 12:34:55 +01:00
|
|
|
md.focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-16 10:47:14 +01:00
|
|
|
function defaultheaders(tags = "")
|
2023-09-14 11:54:09 +02:00
|
|
|
{
|
|
|
|
return [
|
|
|
|
"---",
|
|
|
|
"date: " + timestamp().substr(0,10),
|
2023-11-15 22:00:39 +01:00
|
|
|
"tags: " + (tags || ""),
|
2023-09-14 11:54:09 +02:00
|
|
|
"---",
|
|
|
|
"",""].join("\n");
|
|
|
|
}
|
|
|
|
|
2023-01-21 16:07:14 +01:00
|
|
|
function loadnote(name)
|
2023-01-18 12:34:55 +01:00
|
|
|
{
|
2023-12-06 09:26:08 +01:00
|
|
|
var note = getorcreate(name, defaultheaders());
|
2023-12-11 11:04:39 +01:00
|
|
|
|
|
|
|
if (gettags(note).includes("journal"))
|
|
|
|
{
|
2023-12-13 08:47:20 +01:00
|
|
|
// remove empty entries
|
|
|
|
note.content = note.content.replace(/\d{4}-\d{2}-\d{2}\n*(\d{4}-\d{2}-\d{2})/g, "$1");
|
|
|
|
|
|
|
|
// create new entry for today
|
2023-12-11 11:04:39 +01:00
|
|
|
var hat = headerandtext(note);
|
|
|
|
var today = timestamp().substr(0,10);
|
2023-12-13 08:47:20 +01:00
|
|
|
if (!hat.text.startsWith(today) && !hat.text.startsWith("\n" + today))
|
2023-12-11 11:04:39 +01:00
|
|
|
{
|
|
|
|
note.content = hat.header + "\n" + today + "\n\n" + hat.text;
|
|
|
|
note.pos = hat.header.length + 12;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-12 09:57:29 +01:00
|
|
|
if (settings.autosorttodo && istodo(note))
|
|
|
|
{
|
|
|
|
sorttodotxt(note);
|
|
|
|
}
|
|
|
|
|
2023-01-18 12:34:55 +01:00
|
|
|
bindfile(note);
|
2023-01-26 12:00:32 +01:00
|
|
|
|
|
|
|
stat.cur.q = 0;
|
2023-02-03 12:56:31 +01:00
|
|
|
stat.cur.d = 0;
|
2023-01-26 12:00:32 +01:00
|
|
|
stat.cur.t = timestamp();
|
2023-05-11 10:49:36 +02:00
|
|
|
|
2024-01-12 13:46:48 +01:00
|
|
|
if (!preview.hidden || (preview.hidden && (gettags(note).indexOf("preview") !== -1)))
|
2023-05-11 10:49:36 +02:00
|
|
|
{
|
|
|
|
togglepreview();
|
2023-09-11 09:57:00 +02:00
|
|
|
}
|
2023-01-18 12:34:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function focuseditor()
|
|
|
|
{
|
|
|
|
if (document.documentElement == event.srcElement)
|
|
|
|
{
|
|
|
|
md.focus();
|
|
|
|
console.log("Forced focus");
|
|
|
|
}
|
2023-07-06 15:08:31 +02:00
|
|
|
}
|