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-11-07 15:28:32 +01:00
tagsinlists : true ,
2024-03-12 10:32:21 +01:00
uselinkpopup : true ,
downloadextension : ".md"
2023-01-18 12:34:55 +01:00
} ;
//builtin
2024-02-04 22:43:24 +01:00
const markerslist = [ "* " , "- " , " * " , " - " , ">> " , "> " , "=> " , "— " , "[ ] " , " " , "• " , "- [ ]" , "[x] " , "- [x]" ] ;
const codelanguages = [ "xml" , "js" , "sql" ] ;
const tagmark = "+" ;
2023-01-18 12:34:55 +01:00
// globals
2024-02-04 22:43:24 +01:00
var previoustitle = "" ;
2024-02-04 21:13:22 +01:00
var metadata = null ;
2023-01-18 12:34:55 +01:00
var fileindex = 0 ;
2023-01-22 21:17:23 +01:00
var workerid = null ;
2024-02-04 22:45:41 +01:00
var backup = "" ;
var settings = null ;
2023-01-21 16:07:14 +01:00
var tags = null ;
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" ,
action : commandpalette ,
} ,
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" ,
2024-02-15 22:11:56 +01:00
action : flush ,
2024-02-04 22:43:24 +01:00
shortcut : "ctrl+s"
2023-11-13 15:23:59 +01:00
} ,
2023-01-18 12:34:55 +01:00
{
hint : "Share note" ,
2024-02-04 22:43:24 +01:00
action : share
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" ,
2024-02-04 22:43:24 +01:00
action : toggletitle
2023-01-18 12:34:55 +01:00
} ,
{
shortcut : "ctrl+m" ,
hint : "Toggle preview" ,
2024-02-04 22:43:24 +01:00
action : togglepreview
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" ,
2024-02-04 22:43:24 +01:00
action : togglepreviewwithsubs
2023-02-05 10:04:07 +01:00
} ,
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" ,
2024-02-04 22:43:24 +01:00
action : insertheader
2023-07-20 09:52:17 +02:00
} ,
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 ,
2024-02-04 22:43:24 +01:00
shortcut : "ctrl+o"
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 ,
2024-02-04 22:43:24 +01:00
shortcut : "ctrl+w"
2023-01-25 23:50:48 +01:00
} ,
2023-01-27 15:46:25 +01:00
{
hint : "Toggle spell check" ,
action : togglespellcheck ,
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
} ,
2024-03-03 13:25:36 +01:00
{
hint : "Download all notes of tag (md files in zip archive)" ,
action : downloadtag
} ,
2023-11-06 11:49:45 +01:00
{
hint : "Download all notes (html files in zip archive)" ,
action : downloadhtmlnotes
} ,
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-10-09 12:45:50 +02:00
{
hint : "Replace" ,
shortcut : "ctrl+h" ,
action : searchandreplace
2023-10-25 11:28:12 +02:00
} ,
2023-11-09 09:57:24 +01:00
{
hint : "Sort text" ,
2024-02-04 22:43:24 +01:00
action : sortselection
2023-11-13 18:09:46 +01:00
} ,
{
hint : "Show backlinks" ,
action : backlinks
2024-03-12 17:06:53 +01:00
} ,
{
hint : "Import notes" ,
action : importnotes
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-03-12 17:06:53 +01:00
function importnotes ( )
{
const input = document . createElement ( 'input' ) ;
input . type = "file" ;
input . webkitdirectory = true ;
input . addEventListener ( "change" , ( ) =>
{
let files = Array . from ( input . files ) ;
files . forEach ( file =>
{
var title = file . name . replace ( ".md" , "" ) ;
if ( getguid ( title ) )
{
console . warn ( title + " already exists, skip import" ) ;
}
else
{
file . text ( ) . then ( content =>
{
var guid = createnote ( title , content ) ;
} ) ;
}
} ) ;
} ) ;
if ( 'showPicker' in HTMLInputElement . prototype )
{
input . showPicker ( ) ;
}
else
{
input . click ( ) ;
}
}
2024-02-02 10:41:02 +01:00
function genguid ( )
{
return crypto . randomUUID ( ) ;
}
2024-02-04 22:43:24 +01:00
function seteditorcontent ( content )
2023-09-24 22:00:20 +02:00
{
md . value = content ;
2023-10-12 14:21:55 +02:00
applycolors ( ) ;
2024-02-15 22:11:56 +01:00
flush ( ) ;
2023-12-20 08:39:41 +01:00
resize ( ) ;
2023-09-24 22:00:20 +02:00
}
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
} ;
}
2024-02-15 22:11:56 +01:00
function serialize ( key , value )
{
localStorage . setItem ( key , value ) ;
2024-02-16 15:04:36 +01:00
var name = metadata && metadata [ key ] ? metadata [ key ] . title : key ;
console . log ( "'" + name + "' serialized locally" ) ;
2024-02-15 22:11:56 +01:00
}
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
{
2024-02-07 21:41:03 +01:00
var guid = getguid ( title ) ;
if ( guid )
2023-01-30 10:01:14 +01:00
{
2024-02-07 21:41:03 +01:00
showtemporaryinfo ( "'" + title + "' already exists" ) ;
setpos ( md . selectionStart ) ;
md . focus ( ) ;
}
else
{
var range = currentrange ( ) ;
var content = getrangecontent ( range ) ;
guid = createnote ( title ) ;
2024-02-15 22:11:56 +01:00
serialize ( guid , content ) ;
2024-02-07 21:41:03 +01:00
seteditorcontent ( md . value . substring ( 0 , range . start )
+ "[[" + title + "]]"
+ md . value . substring ( range . end ) ) ;
2023-01-30 10:01:14 +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
{
2024-02-04 22:43:24 +01:00
deletenote ( title ) ;
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 ( )
{
2024-02-07 21:41:03 +01:00
var tags = gettags ( md . value ) ;
2023-01-26 12:00:32 +01:00
showtemporaryinfo (
2023-01-26 12:01:15 +01:00
[
2024-02-07 21:41:03 +01:00
"title: " + title . value ,
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 : "" ) ,
2024-02-07 21:41:03 +01:00
"notes count: " + sortedlist ( ) . length ,
2023-10-27 12:43:03 +02:00
"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 ( )
{
2024-02-16 15:04:36 +01:00
localStorage . setItem ( "settings" , JSON . stringify ( settings ) ) ;
2023-01-23 12:50:52 +01:00
}
2024-02-07 21:41:03 +01:00
function children ( guid )
2023-01-30 08:48:15 +01:00
{
2024-02-07 21:41:03 +01:00
var content = localStorage . getItem ( guid ) ;
return ( content
2023-01-30 08:48:15 +01:00
. 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)" ) )
2024-02-07 21:41:03 +01:00
. map ( l => getguid ( l ) ) ;
2023-01-30 08:48:15 +01:00
}
2024-02-07 21:41:03 +01:00
function parents ( guid )
2023-01-18 12:34:55 +01:00
{
2024-02-07 21:41:03 +01:00
return Object . keys ( metadata )
. filter ( g => localStorage . getItem ( g ) . indexOf ( "[[" + metadata [ guid ] . title + "]]" ) != - 1 ) ;
2023-01-30 08:48:15 +01:00
}
2023-01-27 09:22:09 +01:00
2024-02-07 21:44:12 +01:00
function connected ( guid )
2023-01-30 08:48:15 +01:00
{
2024-02-07 21:44:12 +01:00
var list = [ guid ] ;
2023-02-04 16:13:55 +01:00
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-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 = [ ] ;
2024-02-07 21:41:03 +01:00
var list = [ getguid ( title . value ) ] ;
2023-09-11 09:57:00 +02:00
2023-02-05 10:04:07 +01:00
while ( list . length )
{
var current = list . shift ( ) ;
2024-02-07 21:41:03 +01:00
if ( ! nodes . find ( n => n . id == current ) )
2023-02-05 10:04:07 +01:00
{
nodes . push (
{
2024-02-07 21:41:03 +01:00
id : current ,
label : metadata [ current ] . title
2023-02-05 10:04:07 +01:00
} ) ;
var buddies = children ( current ) . concat ( parents ( current ) ) ;
list = list . concat ( buddies ) ;
buddies .
forEach ( buddy => {
2024-02-07 21:41:03 +01:00
if ( ! edges . find ( edge => ( edge . to == current && edge . from == buddy ) || ( edge . to == buddy && edge . from == current ) ) )
2023-02-05 10:04:07 +01:00
{
edges . push ( {
2024-02-07 21:41:03 +01:00
from : current ,
to : buddy
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 data = {
nodes : nodes ,
edges : edges
} ;
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 (
{
2024-02-07 21:41:03 +01:00
nodes : [ getguid ( title . value ) ]
2023-11-10 10:13:26 +01:00
} ) ;
2023-02-05 10:04:07 +01:00
}
else
{
2024-02-07 21:44:12 +01:00
searchinlist ( connected ( getguid ( title . value ) ) . map ( g => metadata [ g ] . title ) )
2023-02-05 10:04:07 +01:00
. 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-02-01 12:13:11 +01:00
a . innerText = "Open on " +
link . replace ( "https://" , "" )
. replace ( "http://" , "" )
. replace ( "www." , "" )
. replace ( /\/.*/ , "" ) ;
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-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 ( )
{
2024-02-04 22:43:24 +01:00
bind ( "settings.json" , JSON . stringify ( settings , null , " " ) ) ;
2023-01-18 12:34:55 +01:00
}
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-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
2024-02-15 08:58:57 +01:00
Object . values ( metadata )
2023-01-26 12:01:15 +01:00
. forEach ( n =>
2023-01-18 12:34:55 +01:00
{
2024-02-15 08:58:57 +01:00
var ts = n . header . tags ;
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
}
2024-02-01 23:21:05 +01:00
function gettags ( content )
2023-01-18 12:34:55 +01:00
{
2024-02-01 23:21:05 +01:00
var i = content . indexOf ( "tags: " ) ;
2023-01-18 12:34:55 +01:00
if ( i > - 1 )
{
2024-02-01 23:21:05 +01:00
var j = content . indexOf ( "\n" , i ) ;
return content . substring ( i + 6 , j )
2023-11-06 09:59:01 +01:00
. 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 ,
2024-02-07 21:41:03 +01:00
title : title . value
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>' ] ,
2024-02-07 21:41:03 +01:00
title . value + ".html" ,
2023-01-27 09:22:09 +01:00
{
2023-10-19 15:28:53 +02:00
type : "text/html" ,
2023-01-27 09:22:09 +01:00
} ) ;
navigator . share (
{
2024-02-07 21:41:03 +01:00
title : title . value ,
2023-10-19 15:28:53 +02:00
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 )
{
2024-03-12 10:32:21 +01:00
return title . replace ( /[\?\"<>|\*:\/\\]/g , "_" ) + settings . downloadextension ;
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
}
2024-03-03 13:25:36 +01:00
function downloadtag ( )
{
tagslist ( )
. then ( tag =>
{
var zip = new JSZip ( ) ;
Object . keys ( metadata ) . forEach ( guid =>
{
if ( metadata [ guid ] . header . tags . includes ( tag ) )
{
zip . file ( getfilename ( metadata [ guid ] . title ) , localStorage . getItem ( guid ) ) ;
}
} ) ;
zip . generateAsync ( { type : "blob" } )
. then ( function ( content )
{
2024-03-03 13:27:15 +01:00
saveAs ( content , "notes-" + tag + "-" + timestamp ( ) + ".zip" ) ;
2024-03-03 13:25:36 +01:00
} ) ;
} ) ;
}
2023-01-18 12:34:55 +01:00
function downloadnotes ( )
{
2023-09-01 10:40:28 +02:00
var zip = new JSZip ( ) ;
2024-02-15 08:58:57 +01:00
Object . keys ( metadata ) . forEach ( guid =>
2023-01-18 12:34:55 +01:00
{
2024-02-15 08:58:57 +01:00
zip . file ( getfilename ( metadata [ guid ] . title ) , localStorage . getItem ( guid ) ) ;
2023-09-01 10:40:28 +02:00
} ) ;
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 ( ) ;
2024-02-15 08:58:57 +01:00
Object . keys ( metadata ) . forEach ( guid =>
2023-11-06 11:49:45 +01:00
{
2024-03-06 22:22:09 +01:00
zip . file ( getfilename ( metadata [ guid ] . title ) + ".html" , md2html ( localStorage . getItem ( guid ) ) ) ;
2023-11-06 11:49:45 +01:00
} ) ;
zip . generateAsync ( { type : "blob" } )
. then ( function ( content )
{
saveAs ( content , "notes-html-" + timestamp ( ) + ".zip" ) ;
} ) ;
}
2024-02-02 11:42:35 +01:00
function headerandtext ( content )
2023-10-23 12:14:01 +02:00
{
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 )
{
2024-02-04 22:43:24 +01:00
var guid = getguid ( "todo" ) ;
if ( ! guid )
{
guid = createnote ( "todo" ) ;
}
var content = localStorage . getItem ( guid ) ;
var split = headerandtext ( content ) ;
content = split . header + text + "\n" + split . text ;
if ( title . value == "todo" )
2024-01-17 09:09:25 +01:00
{
2024-02-04 22:43:24 +01:00
seteditorcontent ( content ) ;
}
else
{
2024-02-15 22:11:56 +01:00
serialize ( guid , content ) ;
2024-02-04 22:43:24 +01:00
metadata [ guid ] . lastchanged = Date . now ( ) ;
2024-02-15 22:11:56 +01:00
flush ( ) ;
2024-01-17 09:09:25 +01:00
}
}
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-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
{
2024-03-12 10:32:21 +01:00
download ( getfilename ( note . title ) , note . content ) ;
2023-09-11 09:57:00 +02:00
}
2023-01-30 10:01:14 +01:00
}
2023-01-18 12:34:55 +01:00
function downloadnote ( )
{
2024-03-12 10:32:21 +01:00
download ( getfilename ( title . value ) , md . value ) ;
2023-01-18 12:34:55 +01:00
}
2024-02-04 21:13:22 +01:00
function getguid ( title )
{
2024-02-08 09:07:24 +01:00
return Object . keys ( metadata ) . find ( guid => metadata [ guid ] . title === title ) ;
2024-02-04 21:13:22 +01:00
}
2023-09-06 21:29:32 +02:00
function gotoline ( line )
{
var i = 0 ;
var pos = 0 ;
while ( i < line && pos > - 1 )
{
2024-02-07 21:41:03 +01:00
pos = md . value . indexOf ( "\n" , pos + 1 ) ;
2023-09-06 21:29:32 +02:00
i ++ ;
}
if ( pos > - 1 )
{
setpos ( pos + 1 ) ;
}
}
2024-03-12 17:06:53 +01:00
function createnote ( title , content )
2024-02-04 21:13:22 +01:00
{
var guid = genguid ( ) ;
2024-03-12 17:06:53 +01:00
content = content || defaultheaders ( ) ;
2024-02-04 21:13:22 +01:00
var item = {
2024-02-07 21:41:03 +01:00
lastchanged : Date . now ( ) ,
2024-02-04 21:13:22 +01:00
title : title ,
pos : content . length ,
header : indexheader ( content )
} ;
metadata [ guid ] = item ;
2024-02-15 11:07:21 +01:00
serializeindex ( )
2024-02-15 22:11:56 +01:00
serialize ( guid , content ) ;
2024-02-04 21:13:22 +01:00
return guid ;
}
2023-01-18 12:34:55 +01:00
function loadstorage ( )
{
2024-02-04 21:13:22 +01:00
metadata = JSON . parse ( localStorage . getItem ( "index" ) ) ;
if ( ! metadata )
{
metadata = { } ;
createnote ( timestamp ( ) ) ;
2024-02-01 23:21:05 +01:00
}
2023-01-18 12:34:55 +01:00
2023-09-06 21:29:32 +02:00
var params = new URLSearchParams ( window . location . search ) ;
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-02-04 22:43:24 +01:00
inserttodo ( "@clip " + clip )
window . close ( ) ;
2024-01-05 14:12:08 +01:00
}
2023-05-22 14:04:35 +02:00
2024-02-15 10:16:23 +01:00
var title = params . get ( "n" ) || params . get ( "name" ) ;
2024-02-15 22:39:50 +01:00
if ( window . title . value )
2023-01-18 12:34:55 +01:00
{
2024-02-07 21:41:03 +01:00
// reload current
2024-02-15 22:39:50 +01:00
loadnote ( window . title . value ) ;
2023-01-18 12:34:55 +01:00
}
2024-02-15 10:06:23 +01:00
else if ( title )
{
loadnote ( title ) ;
2024-02-15 10:16:23 +01:00
var line = params . get ( "l" ) ;
if ( line )
{
gotoline ( parseInt ( line ) ) ;
}
2024-02-15 10:06:23 +01:00
}
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 ( )
{
2024-02-15 22:11:56 +01:00
if ( ! unsavedmark . hidden )
2023-01-18 12:34:55 +01:00
{
return "not saved" ;
2024-02-15 22:11:56 +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
}
2024-02-02 11:42:35 +01:00
function indexheader ( content )
{
2024-02-15 09:33:27 +01:00
var indexedheader = {
tags : [ ]
} ;
2024-02-02 11:42:35 +01:00
var hat = headerandtext ( content ) ;
var header = hat . header ;
if ( header )
{
header . split ( "\n" ) . forEach ( line =>
{
if ( line && line != "---" )
{
var t = line . split ( ":" ) ;
var val = t . pop ( ) ;
var key = t . pop ( ) ;
if ( key == "tags" )
{
val = val . split ( "," ) . map ( t => t . trim ( ) ) ;
2024-02-02 12:01:31 +01:00
if ( val . length == 1 && ! val [ 0 ] )
{
val . pop ( ) ;
}
2024-02-02 11:42:35 +01:00
}
indexedheader [ key ] = val ;
}
} ) ;
}
return indexedheader ;
}
2024-02-01 23:21:05 +01:00
function migratelegacystorage ( )
{
var legacy = localStorage . getItem ( "data" ) ;
if ( legacy )
{
2024-02-16 09:46:15 +01:00
alert ( "Hey! I am about to migrate your notes to the brand new data model. No worries, I will keep a backup somewhere in case things go wrong. Take a deep breath, and click ok when you're ready." ) ;
localStorage . setItem ( "legacy" , legacy ) ;
2024-02-15 09:35:09 +01:00
legacy = JSON . parse ( legacy ) ;
2024-02-01 23:21:05 +01:00
var index = { } ;
2024-02-15 09:35:09 +01:00
legacy . reverse ( ) . forEach ( ( note , i ) =>
2024-02-01 23:21:05 +01:00
{
2024-02-02 10:41:02 +01:00
var guid = genguid ( ) ;
2024-02-01 23:21:05 +01:00
localStorage . setItem ( guid , note . content ) ;
2024-02-02 11:42:35 +01:00
note . header = indexheader ( note . content ) ;
2024-02-15 09:35:09 +01:00
note . lastchanged = i ;
2024-02-01 23:21:05 +01:00
delete note . content ;
index [ guid ] = note ;
} ) ;
localStorage . setItem ( "index" , JSON . stringify ( index ) ) ;
localStorage . removeItem ( "data" ) ;
}
}
2024-02-15 16:02:56 +01:00
function init ( )
{
migratelegacystorage ( ) ;
loadsettings ( ) ;
window . onbeforeunload = checksaved ;
window . onclick = focuseditor ;
2024-02-16 15:04:36 +01:00
title . value = "" ;
2024-02-15 16:02:56 +01:00
initsnippets ( ) ;
2024-03-19 10:07:22 +01:00
loadstorage ( ) ;
2023-01-18 12:34:55 +01:00
2024-03-19 10:07:22 +01:00
if ( issplit ( ) )
{
if ( settings . defaultpreviewinsplit && name == "right" )
2023-01-18 12:34:55 +01:00
{
2024-03-19 10:07:22 +01:00
togglepreview ( ) ;
2023-01-18 12:34:55 +01:00
}
2024-03-19 10:07:22 +01:00
else if ( name == "left" )
2024-02-16 10:51:18 +01:00
{
2024-03-19 10:07:22 +01:00
md . focus ( ) ;
}
2024-02-16 10:51:18 +01:00
}
}
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 ( )
{
2024-02-15 08:58:57 +01:00
searchinlist ( Object . keys ( metadata )
. filter ( guid => localStorage . getItem ( guid ) . includes ( "[[" + title . value + "]]" ) )
. map ( guid => metadata [ guid ] . title ) )
2023-11-13 18:09:46 +01:00
. 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 ( )
{
2024-02-07 21:41:03 +01:00
loadnote ( sortedlist ( ) [ 0 ] . title ) ;
2023-01-21 16:07:14 +01:00
}
function loadprevious ( )
{
2024-02-07 21:52:25 +01:00
var list = sortedlist ( ) ;
var index = list . findIndex ( i => i . title == title . value ) ;
if ( index > - 1 && index < list . length - 1 )
2023-07-05 09:42:33 +02:00
{
2024-02-07 21:52:25 +01:00
loadnote ( list [ index + 1 ] . title ) ;
2023-07-05 09:42:33 +02:00
}
2023-01-18 12:34:55 +01:00
}
2023-07-05 13:40:13 +02:00
function loadnext ( )
{
2024-02-07 21:52:25 +01:00
var list = sortedlist ( ) ;
var index = list . findIndex ( i => i . title == title . value ) ;
2023-12-06 09:26:08 +01:00
if ( index > - 1 && index > 0 )
2023-07-05 13:40:13 +02:00
{
2024-02-07 21:52:25 +01:00
loadnote ( list [ index - 1 ] . title ) ;
2023-07-05 13:40:13 +02:00
}
}
2024-03-06 22:22:09 +01:00
function sortedlist ( )
2024-02-07 21:41:03 +01:00
{
2024-02-07 22:26:22 +01:00
return Object
. values ( metadata )
. sort ( ( i , j ) => j . lastchanged - i . lastchanged ) ;
2024-02-07 21:41:03 +01:00
}
2023-01-18 12:34:55 +01:00
function grep ( needle )
{
var result = { } ;
2024-02-07 21:41:03 +01:00
sortedlist ( )
. forEach ( item =>
2023-01-18 12:34:55 +01:00
{
2024-02-07 21:41:03 +01:00
if ( item . title . toLowerCase ( ) . includes ( needle . toLowerCase ( ) ) )
2023-01-18 12:34:55 +01:00
{
2024-02-07 21:41:03 +01:00
result [ item . title ] = { } ;
2023-01-18 12:34:55 +01:00
}
2024-02-07 21:41:03 +01:00
var content = localStorage . getItem ( getguid ( item . title ) ) ;
content . split ( "\n" )
2023-01-18 12:34:55 +01:00
. forEach ( ( line , nb ) => {
if ( line . toLowerCase ( ) . includes ( needle . toLowerCase ( ) ) )
{
2024-02-07 21:41:03 +01:00
result [ item . title ] = result [ item . title ] || { } ;
result [ item . title ] [ nb ] = line ;
2023-01-18 12:34:55 +01:00
}
} ) ;
} ) ;
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." ) ;
}
2024-02-04 22:43:24 +01:00
bind ( "Search result" , grepcontent . join ( "\n" ) ) ;
2023-01-18 12:34:55 +01:00
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
} ;
} ) )
2024-02-07 21:41:03 +01:00
. concat (
sortedlist ( )
2024-02-06 13:29:27 +01:00
. map ( item =>
2023-11-15 17:57:11 +01:00
{
return {
2024-01-12 13:46:48 +01:00
prefix : "note " ,
2024-02-02 11:42:35 +01:00
text : item . title ,
suffix : item . header . tags . map ( t => tagmark + t )
2023-11-15 17:57:11 +01:00
} ;
} ) )
. 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 ,
2024-03-19 10:07:22 +01:00
suffix : [ settings [ s ] ]
2023-11-15 17:57:11 +01:00
} ;
} ) ) )
. 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
}
2023-01-25 15:41:21 +01:00
function postpone ( )
{
return new Promise ( function ( resolve )
{
clearTimeout ( workerid ) ;
workerid = setTimeout ( resolve , settings . savedelay ) ;
} ) ;
}
2024-02-15 22:11:56 +01:00
function flush ( )
2024-02-01 23:21:05 +01:00
{
2024-02-04 22:43:24 +01:00
clearTimeout ( workerid ) ;
workerid = null ;
2024-02-02 11:42:35 +01:00
2024-02-16 15:04:36 +01:00
var guid = getguid ( title . value ) ;
2024-02-04 22:43:24 +01:00
if ( guid )
{
var item = metadata [ guid ] ;
item . title = title . value ;
item . pos = md . selectionStart ;
item . header = indexheader ( md . value ) ;
item . lastchanged = Date . now ( ) ;
2024-02-01 23:21:05 +01:00
2024-02-15 22:11:56 +01:00
serializeindex ( ) ;
serialize ( guid , md . value ) ;
2024-02-04 22:43:24 +01:00
}
else if ( title . value == "settings.json" )
{
settings = JSON . parse ( md . value ) ;
savesettings ( ) ;
loadsettings ( ) ;
}
2024-03-19 10:07:22 +01:00
unsavedmark . hidden = true ;
2024-02-15 22:11:56 +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 = {
2024-02-19 14:25:20 +01:00
"sql" : [ "select" , "from" , "where" , "and" , "or" , "set" , "declare" ] ,
2023-11-10 12:37:07 +01:00
"js" : [ "var" , "for" , "if" , "else" ] ,
2024-03-22 15:52:12 +01:00
"zsh" : [ "sudo" ] ,
2024-03-22 15:58:51 +01:00
"bash" : [ "molecule" , "cd" ] ,
"python" : [ "from" , "import" ]
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
2024-03-08 16:46:58 +01:00
if ( line . startsWith ( "x " ) )
2023-10-23 14:46:48 +02:00
{
2024-03-08 16:46:58 +01:00
line = "<span class='color-todo-complete'>" + line + "</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 ( )
{
2024-02-15 22:11:56 +01:00
unsavedmark . hidden = false ;
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" ) ) ;
2024-02-15 22:11:56 +01:00
// todo: fix if current note change during postponing, the wrong one will be saved. Or prevent binding another note?
postpone ( ) . then ( flush ) ;
2023-12-20 08:39:41 +01:00
resize ( ) ;
2023-09-23 09:02:02 +02:00
}
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 ( )
{
2024-02-15 22:11:56 +01:00
flush ( ) ;
2023-11-15 08:44:01 +01:00
loadnote ( timestamp ( ) ) ;
}
2023-01-18 12:34:55 +01:00
function startnewnote ( )
{
2024-02-15 22:11:56 +01:00
flush ( ) ;
2023-10-04 08:44:10 +02:00
var title = prompt ( "Note title: " , timestamp ( ) ) ;
if ( title )
{
loadnote ( title ) ;
}
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 ( "[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" ) ;
2024-03-19 10:24:58 +01:00
help . push ( "https://git.ouvaton.coop/quenousimporte/notes" ) ;
2023-09-28 13:55:38 +02:00
2024-02-04 22:43:24 +01:00
bind ( "Help" , help . join ( "\n" ) ) ;
2023-01-18 12:34:55 +01:00
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 (
2024-02-07 21:41:03 +01:00
sortedlist ( )
2024-02-06 13:29:27 +01:00
. map ( item =>
2023-11-15 17:57:11 +01:00
{
return {
2024-02-02 17:33:25 +01:00
text : item . title ,
suffix : item . header . tags . map ( t => tagmark + t )
2023-11-15 17:57:11 +01:00
}
} ) ) ;
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 =>
{
2024-02-02 17:33:25 +01:00
var title = selected . text || selected ;
2024-02-04 21:13:22 +01:00
loadnote ( title ) ;
2023-11-07 09:13:45 +01:00
} ) ;
2023-01-18 12:34:55 +01:00
}
2024-02-15 09:35:21 +01:00
function istodo ( title , content )
{
return title . includes ( "todo" ) || gettags ( content ) . includes ( "todo" ) ;
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 ) ) ;
}
2024-02-15 11:07:21 +01:00
function serializeindex ( )
{
2024-02-15 22:11:56 +01:00
serialize ( "index" , JSON . stringify ( metadata ) ) ;
2024-02-15 11:07:21 +01:00
}
2024-02-04 22:43:24 +01:00
function deletenote ( title )
2023-01-18 12:34:55 +01:00
{
2024-02-04 22:43:24 +01:00
var guid = getguid ( title ) ;
2024-03-06 22:22:09 +01:00
delete metadata [ guid ] ;
2024-02-04 22:43:24 +01:00
renameinternallinks ( title , title + " (deleted)" ) ;
2024-03-06 22:22:09 +01:00
var content = localStorage . getItem ( guid ) ;
localStorage . setItem ( guid , "Deleted. Title: " + title + ". Date: " + timestamp ( ) + "\r\n" + content ) ;
serializeindex ( ) ;
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 ( )
{
2024-02-04 22:43:24 +01:00
if ( confirm ( 'delete "' + title . value + '"?' ) )
2023-02-01 13:54:49 +01:00
{
2024-02-04 22:43:24 +01:00
deletenote ( title . value ) ;
2023-01-27 09:22:09 +01:00
loadlast ( ) ;
2023-01-18 12:34:55 +01:00
}
}
function restore ( )
{
2024-02-04 22:45:41 +01:00
if ( confirm ( 'restore "' + title . value + '"?' ) )
2023-01-18 12:34:55 +01:00
{
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 )
{
2024-02-15 16:02:56 +01:00
if ( command . action )
2023-01-26 08:36:12 +01:00
{
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 ( ) ;
}
2024-02-07 21:41:03 +01:00
else if ( title . value == "Help" || title . value == "Search result" )
2023-07-04 10:22:57 +02:00
{
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 ) ;
}
2024-02-04 21:13:22 +01:00
function foreachmetadata ( callback )
2024-02-02 11:42:35 +01:00
{
2024-02-04 21:13:22 +01:00
Object . keys ( metadata ) . forEach ( guid =>
2024-02-02 11:42:35 +01:00
{
2024-02-04 21:13:22 +01:00
callback ( guid , metadata [ guid ] ) ;
2024-02-02 11:42:35 +01:00
} ) ;
}
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
2024-02-02 11:42:35 +01:00
var found = false ;
2024-02-04 21:13:22 +01:00
foreachmetadata ( ( guid , item ) =>
2023-01-18 12:34:55 +01:00
{
2024-02-02 11:42:35 +01:00
if ( item . header . shortcut && shortcutmatches ( event , item . header . shortcut ) )
2023-01-18 12:34:55 +01:00
{
2024-02-02 11:42:35 +01:00
console . log ( "Loading note '" + item . title + "' from header shortcut " + item . header . shortcut ) ;
2023-10-03 13:43:19 +02:00
event . preventDefault ( ) ;
2024-02-04 21:13:22 +01:00
loadnote ( item . title ) ;
2024-02-02 11:42:35 +01:00
found = true ;
2023-01-18 12:34:55 +01:00
}
2023-01-25 15:41:21 +01:00
} ) ;
2023-10-03 13:37:30 +02:00
// commands shortcuts
2024-02-02 11:42:35 +01:00
if ( ! found )
2023-10-03 13:37:30 +02:00
{
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 ( )
{
2024-02-01 23:21:05 +01:00
document . title = title . value ;
2023-01-21 21:05:39 +01:00
}
2024-02-04 22:43:24 +01:00
function renameinternallinks ( from , to )
{
foreachmetadata ( ( guid , item ) =>
{
var content = localStorage . getItem ( guid ) ;
var newcontent = content . replaceAll ( "[[" + from + "]]" , "[[" + to + "]]" ) ;
if ( content != newcontent )
{
2024-02-15 22:11:56 +01:00
serialize ( guid , newcontent ) ;
2024-02-16 15:04:36 +01:00
if ( item . title == title . value )
2024-02-06 13:29:27 +01:00
{
seteditorcontent ( newcontent ) ;
}
2024-02-04 22:43:24 +01:00
}
} ) ;
}
2023-01-18 12:34:55 +01:00
function ontitlechange ( )
{
2024-02-04 22:43:24 +01:00
var guid = getguid ( title . value ) ;
if ( guid )
2023-01-18 12:34:55 +01:00
{
2023-01-26 12:00:32 +01:00
showtemporaryinfo ( title . value + " alreday exists" ) ;
2024-02-04 22:43:24 +01:00
title . value = previoustitle ;
2023-01-18 12:34:55 +01:00
}
2024-02-04 22:43:24 +01:00
else
2023-01-26 12:00:32 +01:00
{
2024-02-04 22:43:24 +01:00
renameinternallinks ( previoustitle , title . value ) ;
2023-01-26 12:00:32 +01:00
2024-02-04 22:43:24 +01:00
guid = getguid ( previoustitle ) ;
previoustitle = title . value ;
metadata [ guid ] . title = title . value ;
setwindowtitle ( ) ;
2024-02-15 22:11:56 +01:00
flush ( ) ;
2023-07-21 10:34:43 +02:00
2024-02-04 22:43:24 +01:00
if ( ! settings . titlebydefault )
{
toggletitle ( ) ;
}
2023-07-21 10:34:43 +02:00
}
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 ( )
{
2024-02-15 08:58:57 +01:00
// todo: handle loops
2024-02-15 08:41:25 +01:00
var currentguid = getguid ( title . value ) ;
var content = md . value ;
var kids = children ( currentguid ) ;
2023-02-05 10:04:07 +01:00
while ( kids . length )
{
2024-02-15 08:41:25 +01:00
kids . forEach ( guid =>
2023-02-05 10:04:07 +01:00
{
2024-02-15 08:41:25 +01:00
var kidcontent = localStorage . getItem ( guid ) ;
2023-02-05 15:11:26 +01:00
if ( kidcontent . startsWith ( "---\n" ) )
{
var pos = kidcontent . indexOf ( "---\n" , 4 ) ;
kidcontent = kidcontent . substring ( pos + 4 ) ;
}
2024-02-15 08:41:25 +01:00
content = content . replaceAll ( "[[" + metadata [ guid ] . title + "]]" , kidcontent ) ;
2023-02-05 10:04:07 +01:00
} ) ;
2024-02-15 08:41:25 +01:00
kids = children ( currentguid ) ;
2023-02-05 10:04:07 +01:00
}
2024-02-15 08:41:25 +01:00
return content ;
2023-02-05 10:04:07 +01:00
}
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
}
2024-02-01 23:21:05 +01:00
function bind ( title , content , pos )
2023-01-18 12:34:55 +01:00
{
2024-02-15 22:11:56 +01:00
if ( workerid )
{
2024-02-16 09:39:19 +01:00
showtemporaryinfo ( "Cannot open '" + title + "' because current note not yet serialized" ) ;
2024-02-15 22:11:56 +01:00
return ;
}
2024-02-04 22:43:24 +01:00
previoustitle = title ;
2024-02-01 23:21:05 +01:00
backup = content ;
2024-02-04 22:43:24 +01:00
2024-02-02 12:01:31 +01:00
window . title . value = title ;
2023-01-21 21:05:39 +01:00
setwindowtitle ( ) ;
2023-01-18 12:34:55 +01:00
2024-02-04 22:43:24 +01:00
md . value = content || "" ;
applycolors ( ) ;
2023-01-27 15:46:25 +01:00
2024-02-04 22:43:24 +01:00
md . style . height = "0px" ;
2023-01-18 12:34:55 +01:00
resize ( ) ;
2023-01-27 15:46:25 +01:00
2024-02-01 23:21:05 +01:00
setpos ( pos || 0 ) ;
2023-12-08 14:23:05 +01:00
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" ) ;
}
2024-02-04 21:13:22 +01:00
function loadnote ( title )
2023-01-18 12:34:55 +01:00
{
2024-02-04 21:13:22 +01:00
var guid = getguid ( title ) ;
if ( ! guid )
{
guid = createnote ( title ) ;
}
2024-02-01 23:21:05 +01:00
var content = localStorage . getItem ( guid ) ;
2024-02-04 21:13:22 +01:00
var item = metadata [ guid ] ;
2023-12-11 11:04:39 +01:00
2024-02-07 21:41:03 +01:00
if ( item . header . tags . includes ( "journal" ) )
2023-12-11 11:04:39 +01:00
{
2023-12-13 08:47:20 +01:00
// remove empty entries
2024-02-01 23:21:05 +01:00
content = content . replace ( /\d{4}-\d{2}-\d{2}\n*(\d{4}-\d{2}-\d{2})/g , "$1" ) ;
2023-12-13 08:47:20 +01:00
// create new entry for today
2024-02-07 21:41:03 +01:00
var hat = headerandtext ( content ) ;
2023-12-11 11:04:39 +01:00
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
{
2024-02-07 21:41:03 +01:00
content = hat . header + "\n" + today + "\n\n" + hat . text ;
item . pos = hat . header . length + 12 ;
2023-12-11 11:04:39 +01:00
}
2024-02-07 21:41:03 +01:00
}
2023-12-11 11:04:39 +01:00
2024-02-01 23:21:05 +01:00
bind ( item . title , content , item . pos ) ;
2023-01-26 12:00:32 +01:00
2024-02-01 23:21:05 +01:00
if ( ! preview . hidden || ( preview . hidden && ( gettags ( md . value ) . 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
}