mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	refactoring - moving stuff to separate files
This commit is contained in:
		| @@ -152,11 +152,21 @@ | |||||||
|     <link href="stat/style.css" rel="stylesheet"> |     <link href="stat/style.css" rel="stylesheet"> | ||||||
|  |  | ||||||
|     <script src="stat/js/init.js"></script> |     <script src="stat/js/init.js"></script> | ||||||
|  |  | ||||||
|     <script src="stat/js/tree.js"></script> |     <script src="stat/js/tree.js"></script> | ||||||
|  |     <script src="stat/js/treeutils.js"></script> | ||||||
|  |     <script src="stat/js/draganddrop.js"></script> | ||||||
|  |     <script src="stat/js/contextmenu.js"></script> | ||||||
|  |  | ||||||
|     <script src="stat/js/note.js"></script> |     <script src="stat/js/note.js"></script> | ||||||
|     <script src="stat/js/notecase2html.js"></script> |     <script src="stat/js/notecase2html.js"></script> | ||||||
|     <script src="stat/js/html2notecase.js"></script> |     <script src="stat/js/html2notecase.js"></script> | ||||||
|     <script src="stat/js/encryption.js"></script> |     <script src="stat/js/encryption.js"></script> | ||||||
|  |  | ||||||
|  |     <script src="stat/js/recentnotes.js"></script> | ||||||
|  |     <script src="stat/js/addlink.js"></script> | ||||||
|  |     <script src="stat/js/jumptonote.js"></script> | ||||||
|  |  | ||||||
|     <script src="stat/js/utils.js"></script> |     <script src="stat/js/utils.js"></script> | ||||||
|   </body> |   </body> | ||||||
| </html> | </html> | ||||||
							
								
								
									
										96
									
								
								static/js/addlink.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								static/js/addlink.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | |||||||
|  | $(document).bind('keydown', 'alt+l', function() { | ||||||
|  |     $("#noteAutocomplete").val(''); | ||||||
|  |     $("#linkTitle").val(''); | ||||||
|  |  | ||||||
|  |     const noteDetail = $('#noteDetail'); | ||||||
|  |     noteDetail.summernote('editor.saveRange'); | ||||||
|  |  | ||||||
|  |     $("#insertLinkDialog").dialog({ | ||||||
|  |         modal: true, | ||||||
|  |         width: 500 | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     function setDefaultLinkTitle(noteId) { | ||||||
|  |         const note = getNodeByKey(noteId); | ||||||
|  |         if (!note) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let noteTitle = note.title; | ||||||
|  |  | ||||||
|  |         if (noteTitle.endsWith(" (clone)")) { | ||||||
|  |             noteTitle = noteTitle.substr(0, noteTitle.length - 8); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $("#linkTitle").val(noteTitle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $("#noteAutocomplete").autocomplete({ | ||||||
|  |         source: getAutocompleteItems(globalAllNoteIds), | ||||||
|  |         minLength: 0, | ||||||
|  |         change: function () { | ||||||
|  |             const val = $("#noteAutocomplete").val(); | ||||||
|  |             const noteId = getNodeIdFromLabel(val); | ||||||
|  |  | ||||||
|  |             if (noteId) { | ||||||
|  |                 setDefaultLinkTitle(noteId); | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         // this is called when user goes through autocomplete list with keyboard | ||||||
|  |         // at this point the item isn't selected yet so we use supplied ui.item to see where the cursor is | ||||||
|  |         focus: function (event, ui) { | ||||||
|  |             const noteId = getNodeIdFromLabel(ui.item.value); | ||||||
|  |  | ||||||
|  |             setDefaultLinkTitle(noteId); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | $("#insertLinkForm").submit(function() { | ||||||
|  |     let val = $("#noteAutocomplete").val(); | ||||||
|  |  | ||||||
|  |     const noteId = getNodeIdFromLabel(val); | ||||||
|  |  | ||||||
|  |     if (noteId) { | ||||||
|  |         const linkTitle = $("#linkTitle").val(); | ||||||
|  |         const noteDetail = $('#noteDetail'); | ||||||
|  |  | ||||||
|  |         $("#insertLinkDialog").dialog("close"); | ||||||
|  |  | ||||||
|  |         noteDetail.summernote('editor.restoreRange'); | ||||||
|  |  | ||||||
|  |         noteDetail.summernote('createLink', { | ||||||
|  |             text: linkTitle, | ||||||
|  |             url: 'app#' + noteId, | ||||||
|  |             isNewWindow: true | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | // when click on link popup, in case of internal link, just go the the referenced note instead of default behavior | ||||||
|  | // of opening the link in new window/tab | ||||||
|  | $(document).on('click', 'div.popover-content a', function(e) { | ||||||
|  |     const targetUrl = $(e.target).attr("href"); | ||||||
|  |  | ||||||
|  |     const noteIdMatch = /app#([A-Za-z0-9]{22})/.exec(targetUrl); | ||||||
|  |  | ||||||
|  |     if (noteIdMatch !== null) { | ||||||
|  |         const noteId = noteIdMatch[1]; | ||||||
|  |  | ||||||
|  |         getNodeByKey(noteId).setActive(); | ||||||
|  |  | ||||||
|  |         e.preventDefault(); | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | function getNodeIdFromLabel(label) { | ||||||
|  |     const noteIdMatch = / \(([A-Za-z0-9]{22})\)/.exec(label); | ||||||
|  |  | ||||||
|  |     if (noteIdMatch !== null) { | ||||||
|  |         return noteIdMatch[1]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return null; | ||||||
|  | } | ||||||
							
								
								
									
										63
									
								
								static/js/contextmenu.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								static/js/contextmenu.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | const contextMenuSetup = { | ||||||
|  |     delegate: "span.fancytree-title", | ||||||
|  |     autoFocus: true, | ||||||
|  |     menu: [ | ||||||
|  |         {title: "Insert note here", cmd: "insertNoteHere", uiIcon: "ui-icon-pencil"}, | ||||||
|  |         {title: "Insert child note", cmd: "insertChildNote", uiIcon: "ui-icon-pencil"}, | ||||||
|  |         {title: "Delete", cmd: "delete", uiIcon: "ui-icon-trash"}, | ||||||
|  |         {title: "----"}, | ||||||
|  |         {title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors"}, | ||||||
|  |         {title: "Copy / clone", cmd: "copy", uiIcon: "ui-icon-copy"}, | ||||||
|  |         {title: "Paste after", cmd: "pasteAfter", uiIcon: "ui-icon-clipboard"}, | ||||||
|  |         {title: "Paste into", cmd: "pasteInto", uiIcon: "ui-icon-clipboard"} | ||||||
|  |     ], | ||||||
|  |     beforeOpen: function (event, ui) { | ||||||
|  |         const node = $.ui.fancytree.getNode(ui.target); | ||||||
|  |         // Modify menu entries depending on node status | ||||||
|  |         globalTree.contextmenu("enableEntry", "pasteAfter", globalClipboardNoteId !== null); | ||||||
|  |         globalTree.contextmenu("enableEntry", "pasteInto", globalClipboardNoteId !== null); | ||||||
|  |  | ||||||
|  |         // Activate node on right-click | ||||||
|  |         node.setActive(); | ||||||
|  |         // Disable tree keyboard handling | ||||||
|  |         ui.menu.prevKeyboard = node.tree.options.keyboard; | ||||||
|  |         node.tree.options.keyboard = false; | ||||||
|  |     }, | ||||||
|  |     close: function (event, ui) {}, | ||||||
|  |     select: function (event, ui) { | ||||||
|  |         const node = $.ui.fancytree.getNode(ui.target); | ||||||
|  |  | ||||||
|  |         if (ui.cmd === "insertNoteHere") { | ||||||
|  |             const parentKey = getParentKey(node); | ||||||
|  |             const encryption = getParentEncryption(node); | ||||||
|  |  | ||||||
|  |             createNote(node, parentKey, 'after', encryption); | ||||||
|  |         } | ||||||
|  |         else if (ui.cmd === "insertChildNote") { | ||||||
|  |             createNote(node, node.key, 'into'); | ||||||
|  |         } | ||||||
|  |         else if (ui.cmd === "cut") { | ||||||
|  |             globalClipboardNoteId = node.key; | ||||||
|  |         } | ||||||
|  |         else if (ui.cmd === "pasteAfter") { | ||||||
|  |             const subjectNode = getNodeByKey(globalClipboardNoteId); | ||||||
|  |  | ||||||
|  |             moveAfterNode(subjectNode, node); | ||||||
|  |  | ||||||
|  |             globalClipboardNoteId = null; | ||||||
|  |         } | ||||||
|  |         else if (ui.cmd === "pasteInto") { | ||||||
|  |             const subjectNode = getNodeByKey(globalClipboardNoteId); | ||||||
|  |  | ||||||
|  |             moveToNode(subjectNode, node); | ||||||
|  |  | ||||||
|  |             globalClipboardNoteId = null; | ||||||
|  |         } | ||||||
|  |         else if (ui.cmd === "delete") { | ||||||
|  |             deleteNode(node); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             console.log("Unknown command: " + ui.cmd); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
							
								
								
									
										62
									
								
								static/js/draganddrop.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								static/js/draganddrop.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | const dragAndDropSetup = { | ||||||
|  |     autoExpandMS: 600, | ||||||
|  |     draggable: { // modify default jQuery draggable options | ||||||
|  |         zIndex: 1000, | ||||||
|  |         scroll: false, | ||||||
|  |         containment: "parent", | ||||||
|  |         revert: "invalid" | ||||||
|  |     }, | ||||||
|  |     preventRecursiveMoves: true, // Prevent dropping nodes on own descendants | ||||||
|  |     preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. | ||||||
|  |  | ||||||
|  |     dragStart: function (node, data) { | ||||||
|  |         // This function MUST be defined to enable dragging for the tree. | ||||||
|  |         // Return false to cancel dragging of node. | ||||||
|  |         return true; | ||||||
|  |     }, | ||||||
|  |     dragEnter: function (node, data) { | ||||||
|  |         /* data.otherNode may be null for non-fancytree droppables. | ||||||
|  |         * Return false to disallow dropping on node. In this case | ||||||
|  |         * dragOver and dragLeave are not called. | ||||||
|  |         * Return 'over', 'before, or 'after' to force a hitMode. | ||||||
|  |         * Return ['before', 'after'] to restrict available hitModes. | ||||||
|  |         * Any other return value will calc the hitMode from the cursor position. | ||||||
|  |         */ | ||||||
|  |         // Prevent dropping a parent below another parent (only sort | ||||||
|  |         // nodes under the same parent): | ||||||
|  |         //    if(node.parent !== data.otherNode.parent){ | ||||||
|  |         //      return false; | ||||||
|  |         //    } | ||||||
|  |         // Don't allow dropping *over* a node (would create a child). Just | ||||||
|  |         // allow changing the order: | ||||||
|  |         //    return ["before", "after"]; | ||||||
|  |         // Accept everything: | ||||||
|  |         return true; | ||||||
|  |     }, | ||||||
|  |     dragExpand: function (node, data) { | ||||||
|  |         // return false to prevent auto-expanding data.node on hover | ||||||
|  |     }, | ||||||
|  |     dragOver: function (node, data) { | ||||||
|  |     }, | ||||||
|  |     dragLeave: function (node, data) { | ||||||
|  |     }, | ||||||
|  |     dragStop: function (node, data) { | ||||||
|  |     }, | ||||||
|  |     dragDrop: function (node, data) { | ||||||
|  |         // This function MUST be defined to enable dropping of items on the tree. | ||||||
|  |         // data.hitMode is 'before', 'after', or 'over'. | ||||||
|  |  | ||||||
|  |         if (data.hitMode === "before") { | ||||||
|  |             moveBeforeNode(data.otherNode, node); | ||||||
|  |         } | ||||||
|  |         else if (data.hitMode === "after") { | ||||||
|  |             moveAfterNode(data.otherNode, node); | ||||||
|  |         } | ||||||
|  |         else if (data.hitMode === "over") { | ||||||
|  |             moveToNode(data.otherNode, node); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             throw new Exception("Unknown hitMode=" + data.hitMode); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
| @@ -14,7 +14,7 @@ function handleEncryption(requireEncryption, modal, callback) { | |||||||
|             open: function() { |             open: function() { | ||||||
|                 if (!modal) { |                 if (!modal) { | ||||||
|                     // dialog steals focus for itself, which is not what we want for non-modal (viewing) |                     // dialog steals focus for itself, which is not what we want for non-modal (viewing) | ||||||
|                     getNodeByKey(globalNote.detail.note_id).setFocus(); |                     getNodeByKey(globalCurrentNote.detail.note_id).setFocus(); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @@ -127,8 +127,8 @@ setInterval(function() { | |||||||
|     if (globalLastEncryptionOperationDate !== null && new Date().getTime() - globalLastEncryptionOperationDate.getTime() > globalEncryptionKeyTimeToLive) { |     if (globalLastEncryptionOperationDate !== null && new Date().getTime() - globalLastEncryptionOperationDate.getTime() > globalEncryptionKeyTimeToLive) { | ||||||
|         globalEncryptionKey = null; |         globalEncryptionKey = null; | ||||||
|  |  | ||||||
|         if (globalNote.detail.encryption > 0) { |         if (globalCurrentNote.detail.encryption > 0) { | ||||||
|             loadNote(globalNote.detail.note_id); |             loadNote(globalCurrentNote.detail.note_id); | ||||||
|  |  | ||||||
|             for (const noteId of globalAllNoteIds) { |             for (const noteId of globalAllNoteIds) { | ||||||
|                 const note = getNodeByKey(noteId); |                 const note = getNodeByKey(noteId); | ||||||
| @@ -189,7 +189,7 @@ function encryptNote(note) { | |||||||
|  |  | ||||||
| function encryptNoteAndSendToServer() { | function encryptNoteAndSendToServer() { | ||||||
|     handleEncryption(true, true, () => { |     handleEncryption(true, true, () => { | ||||||
|         const note = globalNote; |         const note = globalCurrentNote; | ||||||
|  |  | ||||||
|         updateNoteFromInputs(note); |         updateNoteFromInputs(note); | ||||||
|  |  | ||||||
| @@ -203,7 +203,7 @@ function encryptNoteAndSendToServer() { | |||||||
|  |  | ||||||
| function decryptNoteAndSendToServer() { | function decryptNoteAndSendToServer() { | ||||||
|     handleEncryption(true, true, () => { |     handleEncryption(true, true, () => { | ||||||
|         const note = globalNote; |         const note = globalCurrentNote; | ||||||
|  |  | ||||||
|         updateNoteFromInputs(note); |         updateNoteFromInputs(note); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| $(function() { | $(function() { | ||||||
|     $(window).resize(function() { |     $(window).resize(function() { | ||||||
|  |         // dynamically setting height of tree and note content to match window's height | ||||||
|         const fancyTree = $('ul.fancytree-container'); |         const fancyTree = $('ul.fancytree-container'); | ||||||
|  |  | ||||||
|         if (fancyTree.length) { |         if (fancyTree.length) { | ||||||
| @@ -15,6 +16,7 @@ $(function() { | |||||||
|     $(window).resize(); |     $(window).resize(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | // hot keys are active also inside inputs and content editables | ||||||
| jQuery.hotkeys.options.filterInputAcceptingElements = true; | jQuery.hotkeys.options.filterInputAcceptingElements = true; | ||||||
| jQuery.hotkeys.options.filterContentEditable = true; | jQuery.hotkeys.options.filterContentEditable = true; | ||||||
|  |  | ||||||
| @@ -27,176 +29,11 @@ $(document).bind('keydown', 'alt+h', function() { | |||||||
|     $("#noteDetailWrapper").css("width", hidden ? "750px" : "100%"); |     $("#noteDetailWrapper").css("width", hidden ? "750px" : "100%"); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| $(document).bind('keydown', 'alt+q', function() { |  | ||||||
|     $("#recentNotesDialog").dialog({ |  | ||||||
|         modal: true, |  | ||||||
|         width: 500 |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     let recentNotesSelectBox = $('#recentNotesSelectBox'); |  | ||||||
|  |  | ||||||
|     recentNotesSelectBox.find('option').remove(); |  | ||||||
|  |  | ||||||
|     // remove the current note |  | ||||||
|     let recNotes = globalRecentNotes.filter(note => note !== globalNote.detail.note_id); |  | ||||||
|  |  | ||||||
|     $.each(recNotes, function(key, valueNoteId) { |  | ||||||
|         let noteTitle = getFullName(valueNoteId); |  | ||||||
|  |  | ||||||
|         if (!noteTitle) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         let option = $("<option></option>") |  | ||||||
|                 .attr("value", valueNoteId) |  | ||||||
|                 .text(noteTitle); |  | ||||||
|  |  | ||||||
|         // select the first one (most recent one) by default |  | ||||||
|         if (key === 0) { |  | ||||||
|             option.attr("selected", "selected"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         recentNotesSelectBox.append(option); |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| function setActiveNoteBasedOnRecentNotes() { |  | ||||||
|     let noteId = $("#recentNotesSelectBox option:selected").val(); |  | ||||||
|  |  | ||||||
|     getNodeByKey(noteId).setActive(); |  | ||||||
|  |  | ||||||
|     $("#recentNotesDialog").dialog('close'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| $('#recentNotesSelectBox').keydown(function(e) { |  | ||||||
|     let key = e.which; |  | ||||||
|  |  | ||||||
|     if (key === 13)// the enter key code |  | ||||||
|     { |  | ||||||
|         setActiveNoteBasedOnRecentNotes(); |  | ||||||
|     } |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| $('#recentNotesSelectBox').dblclick(function(e) { |  | ||||||
|     setActiveNoteBasedOnRecentNotes(); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| // when click on link popup, in case of internal link, just go the the referenced note instead of default behavior |  | ||||||
| // of opening the link in new window/tab |  | ||||||
| $(document).on('click', 'div.popover-content a', function(e) { |  | ||||||
|     const targetUrl = $(e.target).attr("href"); |  | ||||||
|  |  | ||||||
|     const noteIdMatch = /app#([A-Za-z0-9]{22})/.exec(targetUrl); |  | ||||||
|  |  | ||||||
|     if (noteIdMatch !== null) { |  | ||||||
|         const noteId = noteIdMatch[1]; |  | ||||||
|  |  | ||||||
|         getNodeByKey(noteId).setActive(); |  | ||||||
|  |  | ||||||
|         e.preventDefault(); |  | ||||||
|     } |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| function getNodeIdFromLabel(label) { |  | ||||||
|     const noteIdMatch = / \(([A-Za-z0-9]{22})\)/.exec(label); |  | ||||||
|  |  | ||||||
|     if (noteIdMatch !== null) { |  | ||||||
|         return noteIdMatch[1]; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return null; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getAutocompleteItems() { |  | ||||||
|     const autocompleteItems = []; |  | ||||||
|  |  | ||||||
|     for (const noteId of globalAllNoteIds) { |  | ||||||
|         const fullName = getFullName(noteId); |  | ||||||
|  |  | ||||||
|         autocompleteItems.push({ |  | ||||||
|             value: fullName + " (" + noteId + ")", |  | ||||||
|             label: fullName |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return autocompleteItems; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| $(document).bind('keydown', 'alt+l', function() { |  | ||||||
|     $("#noteAutocomplete").val(''); |  | ||||||
|     $("#linkTitle").val(''); |  | ||||||
|  |  | ||||||
|     const noteDetail = $('#noteDetail'); |  | ||||||
|     noteDetail.summernote('editor.saveRange'); |  | ||||||
|  |  | ||||||
|     $("#insertLinkDialog").dialog({ |  | ||||||
|         modal: true, |  | ||||||
|         width: 500 |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     function setDefaultLinkTitle(noteId) { |  | ||||||
|         const note = getNodeByKey(noteId); |  | ||||||
|         if (!note) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         let noteTitle = note.title; |  | ||||||
|  |  | ||||||
|         if (noteTitle.endsWith(" (clone)")) { |  | ||||||
|             noteTitle = noteTitle.substr(0, noteTitle.length - 8); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         $("#linkTitle").val(noteTitle); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     $("#noteAutocomplete").autocomplete({ |  | ||||||
|         source: getAutocompleteItems(), |  | ||||||
|         minLength: 0, |  | ||||||
|         change: function () { |  | ||||||
|             const val = $("#noteAutocomplete").val(); |  | ||||||
|             const noteId = getNodeIdFromLabel(val); |  | ||||||
|  |  | ||||||
|             if (noteId) { |  | ||||||
|                 setDefaultLinkTitle(noteId); |  | ||||||
|             } |  | ||||||
|         }, |  | ||||||
|         // this is called when user goes through autocomplete list with keyboard |  | ||||||
|         // at this point the item isn't selected yet so we use supplied ui.item to see where the cursor is |  | ||||||
|         focus: function (event, ui) { |  | ||||||
|             const noteId = getNodeIdFromLabel(ui.item.value); |  | ||||||
|  |  | ||||||
|             setDefaultLinkTitle(noteId); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| $("#insertLinkForm").submit(function() { |  | ||||||
|     let val = $("#noteAutocomplete").val(); |  | ||||||
|  |  | ||||||
|     const noteId = getNodeIdFromLabel(val); |  | ||||||
|  |  | ||||||
|     if (noteId) { |  | ||||||
|         const linkTitle = $("#linkTitle").val(); |  | ||||||
|         const noteDetail = $('#noteDetail'); |  | ||||||
|  |  | ||||||
|         $("#insertLinkDialog").dialog("close"); |  | ||||||
|  |  | ||||||
|         noteDetail.summernote('editor.restoreRange'); |  | ||||||
|  |  | ||||||
|         noteDetail.summernote('createLink', { |  | ||||||
|             text: linkTitle, |  | ||||||
|             url: 'app#' + noteId, |  | ||||||
|             isNewWindow: true |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| $(document).bind('keydown', 'alt+s', function() { | $(document).bind('keydown', 'alt+s', function() { | ||||||
|     $("input[name=search]").focus(); |     $("input[name=search]").focus(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | // hide (toggle) everything except for the note content for distraction free writing | ||||||
| $(document).bind('keydown', 'alt+t', function() { | $(document).bind('keydown', 'alt+t', function() { | ||||||
|     const date = new Date(); |     const date = new Date(); | ||||||
|  |  | ||||||
| @@ -206,34 +43,8 @@ $(document).bind('keydown', 'alt+t', function() { | |||||||
|     $('#noteDetail').summernote('insertText', dateString); |     $('#noteDetail').summernote('insertText', dateString); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| $(document).bind('keydown', 'alt+j', function() { |  | ||||||
|     $("#jumpToNoteAutocomplete").val(''); |  | ||||||
|  |  | ||||||
|     $("#jumpToNoteDialog").dialog({ |  | ||||||
|         modal: true, |  | ||||||
|         width: 500 |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     $("#jumpToNoteAutocomplete").autocomplete({ |  | ||||||
|         source: getAutocompleteItems(), |  | ||||||
|         minLength: 0 |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| $("#jumpToNoteForm").submit(function() { |  | ||||||
|     const val = $("#jumpToNoteAutocomplete").val(); |  | ||||||
|     const noteId = getNodeIdFromLabel(val); |  | ||||||
|  |  | ||||||
|     if (noteId) { |  | ||||||
|         getNodeByKey(noteId).setActive(); |  | ||||||
|  |  | ||||||
|         $("#jumpToNoteDialog").dialog('close'); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| $(window).on('beforeunload', function(){ | $(window).on('beforeunload', function(){ | ||||||
|     // asynchronously send the request and don't wait for result |     // this makes sure that when user e.g. reloads the page or navigates away from the page, the note's content is saved | ||||||
|  |     // this sends the request asynchronously and doesn't wait for result | ||||||
|     saveNoteIfChanged(); |     saveNoteIfChanged(); | ||||||
| }); | }); | ||||||
							
								
								
									
										26
									
								
								static/js/jumptonote.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								static/js/jumptonote.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | $(document).bind('keydown', 'alt+j', function() { | ||||||
|  |     $("#jumpToNoteAutocomplete").val(''); | ||||||
|  |  | ||||||
|  |     $("#jumpToNoteDialog").dialog({ | ||||||
|  |         modal: true, | ||||||
|  |         width: 500 | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     $("#jumpToNoteAutocomplete").autocomplete({ | ||||||
|  |         source: getAutocompleteItems(globalAllNoteIds), | ||||||
|  |         minLength: 0 | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | $("#jumpToNoteForm").submit(function() { | ||||||
|  |     const val = $("#jumpToNoteAutocomplete").val(); | ||||||
|  |     const noteId = getNodeIdFromLabel(val); | ||||||
|  |  | ||||||
|  |     if (noteId) { | ||||||
|  |         getNodeByKey(noteId).setActive(); | ||||||
|  |  | ||||||
|  |         $("#jumpToNoteDialog").dialog('close'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | }); | ||||||
| @@ -21,6 +21,43 @@ function noteChanged() { | |||||||
|     isNoteChanged = true; |     isNoteChanged = true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function saveNoteIfChanged(callback) { | ||||||
|  |     if (!isNoteChanged) { | ||||||
|  |         if (callback) { | ||||||
|  |             callback(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const note = globalCurrentNote; | ||||||
|  |  | ||||||
|  |     updateNoteFromInputs(note); | ||||||
|  |  | ||||||
|  |     encryptNoteIfNecessary(note); | ||||||
|  |  | ||||||
|  |     saveNoteToServer(note, callback); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | setInterval(saveNoteIfChanged, 5000); | ||||||
|  |  | ||||||
|  | $(document).ready(function() { | ||||||
|  |     $("#noteTitle").on('input', function() { | ||||||
|  |         noteChanged(); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     $('#noteDetail').summernote({ | ||||||
|  |         airMode: true, | ||||||
|  |         height: 300, | ||||||
|  |         callbacks: { | ||||||
|  |             onChange: noteChanged | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     // so that tab jumps from note title (which has tabindex 1) | ||||||
|  |     $(".note-editable").attr("tabindex", 2); | ||||||
|  | }); | ||||||
|  |  | ||||||
| function updateNoteFromInputs(note) { | function updateNoteFromInputs(note) { | ||||||
|     let contents = $('#noteDetail').summernote('code'); |     let contents = $('#noteDetail').summernote('code'); | ||||||
|  |  | ||||||
| @@ -54,44 +91,7 @@ function saveNoteToServer(note, callback) { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| function saveNoteIfChanged(callback) { | let globalCurrentNote; | ||||||
|     if (!isNoteChanged) { |  | ||||||
|         if (callback) { |  | ||||||
|             callback(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const note = globalNote; |  | ||||||
|  |  | ||||||
|     updateNoteFromInputs(note); |  | ||||||
|  |  | ||||||
|     encryptNoteIfNecessary(note); |  | ||||||
|  |  | ||||||
|     saveNoteToServer(note, callback); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| setInterval(saveNoteIfChanged, 5000); |  | ||||||
|  |  | ||||||
| $(document).ready(function() { |  | ||||||
|     $("#noteTitle").on('input', function() { |  | ||||||
|         noteChanged(); |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     $('#noteDetail').summernote({ |  | ||||||
|         airMode: true, |  | ||||||
|         height: 300, |  | ||||||
|         callbacks: { |  | ||||||
|             onChange: noteChanged |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
|  |  | ||||||
|     // so that tab jumps from note title (which has tabindex 1) |  | ||||||
|     $(".note-editable").attr("tabindex", 2); |  | ||||||
| }); |  | ||||||
|    |  | ||||||
| let globalNote; |  | ||||||
|  |  | ||||||
| function createNewTopLevelNote() { | function createNewTopLevelNote() { | ||||||
|     let rootNode = globalTree.fancytree("getRootNode"); |     let rootNode = globalTree.fancytree("getRootNode"); | ||||||
| @@ -149,8 +149,6 @@ function createNote(node, parentKey, target, encryption) { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| globalRecentNotes = []; |  | ||||||
|  |  | ||||||
| function setNoteBackgroundIfEncrypted(note) { | function setNoteBackgroundIfEncrypted(note) { | ||||||
|     if (note.detail.encryption > 0) { |     if (note.detail.encryption > 0) { | ||||||
|         $(".note-editable").addClass("encrypted"); |         $(".note-editable").addClass("encrypted"); | ||||||
| @@ -169,7 +167,7 @@ function setNoteBackgroundIfEncrypted(note) { | |||||||
|  |  | ||||||
| function loadNote(noteId) { | function loadNote(noteId) { | ||||||
|     $.get(baseUrl + 'notes/' + noteId).then(function(note) { |     $.get(baseUrl + 'notes/' + noteId).then(function(note) { | ||||||
|         globalNote = note; |         globalCurrentNote = note; | ||||||
|  |  | ||||||
|         if (newNoteCreated) { |         if (newNoteCreated) { | ||||||
|             newNoteCreated = false; |             newNoteCreated = false; | ||||||
| @@ -213,18 +211,3 @@ function loadNote(noteId) { | |||||||
|         }); |         }); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| function addRecentNote(noteTreeId, noteContentId) { |  | ||||||
|     const origDate = new Date(); |  | ||||||
|  |  | ||||||
|     setTimeout(function() { |  | ||||||
|         // we include the note into recent list only if the user stayed on the note at least 5 seconds |  | ||||||
|         if (noteTreeId === globalNote.detail.note_id || noteContentId === globalNote.detail.note_id) { |  | ||||||
|             // if it's already there, remove the note |  | ||||||
|             globalRecentNotes = globalRecentNotes.filter(note => note !== noteTreeId); |  | ||||||
|  |  | ||||||
|             globalRecentNotes.unshift(noteTreeId); |  | ||||||
|         } |  | ||||||
|     }, 1500); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										69
									
								
								static/js/recentnotes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								static/js/recentnotes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | let globalRecentNotes = []; | ||||||
|  |  | ||||||
|  | function addRecentNote(noteTreeId, noteContentId) { | ||||||
|  |     const origDate = new Date(); | ||||||
|  |  | ||||||
|  |     setTimeout(function() { | ||||||
|  |         // we include the note into recent list only if the user stayed on the note at least 5 seconds | ||||||
|  |         if (noteTreeId === globalCurrentNote.detail.note_id || noteContentId === globalCurrentNote.detail.note_id) { | ||||||
|  |             // if it's already there, remove the note | ||||||
|  |             globalRecentNotes = globalRecentNotes.filter(note => note !== noteTreeId); | ||||||
|  |  | ||||||
|  |             globalRecentNotes.unshift(noteTreeId); | ||||||
|  |         } | ||||||
|  |     }, 1500); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | $(document).bind('keydown', 'alt+q', function() { | ||||||
|  |     $("#recentNotesDialog").dialog({ | ||||||
|  |         modal: true, | ||||||
|  |         width: 500 | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     let recentNotesSelectBox = $('#recentNotesSelectBox'); | ||||||
|  |  | ||||||
|  |     recentNotesSelectBox.find('option').remove(); | ||||||
|  |  | ||||||
|  |     // remove the current note | ||||||
|  |     let recNotes = globalRecentNotes.filter(note => note !== globalCurrentNote.detail.note_id); | ||||||
|  |  | ||||||
|  |     $.each(recNotes, function(key, valueNoteId) { | ||||||
|  |         let noteTitle = getFullName(valueNoteId); | ||||||
|  |  | ||||||
|  |         if (!noteTitle) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         let option = $("<option></option>") | ||||||
|  |                 .attr("value", valueNoteId) | ||||||
|  |                 .text(noteTitle); | ||||||
|  |  | ||||||
|  |         // select the first one (most recent one) by default | ||||||
|  |         if (key === 0) { | ||||||
|  |             option.attr("selected", "selected"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         recentNotesSelectBox.append(option); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | function setActiveNoteBasedOnRecentNotes() { | ||||||
|  |     let noteId = $("#recentNotesSelectBox option:selected").val(); | ||||||
|  |  | ||||||
|  |     getNodeByKey(noteId).setActive(); | ||||||
|  |  | ||||||
|  |     $("#recentNotesDialog").dialog('close'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | $('#recentNotesSelectBox').keydown(function(e) { | ||||||
|  |     let key = e.which; | ||||||
|  |  | ||||||
|  |     if (key === 13)// the enter key code | ||||||
|  |     { | ||||||
|  |         setActiveNoteBasedOnRecentNotes(); | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | $('#recentNotesSelectBox').dblclick(function(e) { | ||||||
|  |     setActiveNoteBasedOnRecentNotes(); | ||||||
|  | }); | ||||||
| @@ -25,7 +25,7 @@ function moveToNode(node, toNode) { | |||||||
|         url: baseUrl + 'notes/' + node.key + '/moveTo/' + toNode.key, |         url: baseUrl + 'notes/' + node.key + '/moveTo/' + toNode.key, | ||||||
|         type: 'PUT', |         type: 'PUT', | ||||||
|         contentType: "application/json", |         contentType: "application/json", | ||||||
|         success: function (result) { |         success: function () { | ||||||
|             node.moveTo(toNode); |             node.moveTo(toNode); | ||||||
|  |  | ||||||
|             toNode.setExpanded(true); |             toNode.setExpanded(true); | ||||||
| @@ -66,12 +66,22 @@ function deleteNode(node) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| function getParentKey(node) { | function moveNodeUp(node) { | ||||||
|     return (node.getParent() === null || node.getParent().key === "root_1") ? "root" : node.getParent().key; |     if (node.getParent() !== null) { | ||||||
|  |         $.ajax({ | ||||||
|  |             url: baseUrl + 'notes/' + node.key + '/moveAfter/' + node.getParent().key, | ||||||
|  |             type: 'PUT', | ||||||
|  |             contentType: "application/json", | ||||||
|  |             success: function () { | ||||||
|  |                 if (node.getParent() !== null && node.getParent().getChildren().length <= 1) { | ||||||
|  |                     node.getParent().folder = false; | ||||||
|  |                     node.getParent().renderTitle(); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| function getParentEncryption(node) { |                 node.moveTo(node.getParent(), 'after'); | ||||||
|     return node.getParent() === null ? 0 : node.getParent().data.encryption; |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| const keybindings = { | const keybindings = { | ||||||
| @@ -101,21 +111,7 @@ const keybindings = { | |||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "shift+left": function(node) { |     "shift+left": function(node) { | ||||||
|         if (node.getParent() !== null) { |         moveNodeUp(node); | ||||||
|             $.ajax({ |  | ||||||
|                 url: baseUrl + 'notes/' + node.key + '/moveAfter/' + node.getParent().key, |  | ||||||
|                 type: 'PUT', |  | ||||||
|                 contentType: "application/json", |  | ||||||
|                 success: function() { |  | ||||||
|                     if (node.getParent() !== null && node.getParent().getChildren().length <= 1) { |  | ||||||
|                         node.getParent().folder = false; |  | ||||||
|                         node.getParent().renderTitle(); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     node.moveTo(node.getParent(), 'after'); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     }, |     }, | ||||||
|     "shift+right": function(node) { |     "shift+right": function(node) { | ||||||
|         let toNode = node.getPrevSibling(); |         let toNode = node.getPrevSibling(); | ||||||
| @@ -132,40 +128,11 @@ const keybindings = { | |||||||
|  |  | ||||||
| let globalAllNoteIds = []; | let globalAllNoteIds = []; | ||||||
|  |  | ||||||
| let globalTree; | const globalTree = $("#tree"); | ||||||
|  |  | ||||||
| function getNodeByKey(noteId) { |  | ||||||
|     return globalTree.fancytree('getNodeByKey', noteId); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function getFullName(noteId) { |  | ||||||
|     let note = getNodeByKey(noteId); |  | ||||||
|     const path = []; |  | ||||||
|  |  | ||||||
|     while (note) { |  | ||||||
|         path.push(note.title); |  | ||||||
|  |  | ||||||
|         note = note.getParent(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // remove "root" element |  | ||||||
|     path.pop(); |  | ||||||
|  |  | ||||||
|     return path.reverse().join(" > "); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| let globalClipboardNoteId = null; | let globalClipboardNoteId = null; | ||||||
|  |  | ||||||
| $(function(){ | function prepareNoteTree(notes) { | ||||||
|     $.get(baseUrl + 'tree').then(resp => { |  | ||||||
|         const notes = resp.notes; |  | ||||||
|         let startNoteId = resp.start_note_id; |  | ||||||
|  |  | ||||||
|         if (document.location.hash) { |  | ||||||
|             startNoteId = document.location.hash.substr(1); // strip initial # |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         function copyTitle(notes) { |  | ||||||
|     for (const note of notes) { |     for (const note of notes) { | ||||||
|         globalAllNoteIds.push(note.note_id); |         globalAllNoteIds.push(note.note_id); | ||||||
|  |  | ||||||
| @@ -186,14 +153,12 @@ $(function(){ | |||||||
|         note.expanded = note.is_expanded; |         note.expanded = note.is_expanded; | ||||||
|  |  | ||||||
|         if (note.children && note.children.length > 0) { |         if (note.children && note.children.length > 0) { | ||||||
|                     copyTitle(note.children); |             prepareNoteTree(note.children); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|         copyTitle(notes); | function setExpandedToServer(note_id, is_expanded) { | ||||||
|  |  | ||||||
|         function setExpanded(note_id, is_expanded) { |  | ||||||
|     expanded_num = is_expanded ? 1 : 0; |     expanded_num = is_expanded ? 1 : 0; | ||||||
|  |  | ||||||
|     $.ajax({ |     $.ajax({ | ||||||
| @@ -204,7 +169,17 @@ $(function(){ | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
|         globalTree = $("#tree"); | $(function(){ | ||||||
|  |     $.get(baseUrl + 'tree').then(resp => { | ||||||
|  |         const notes = resp.notes; | ||||||
|  |         let startNoteId = resp.start_note_id; | ||||||
|  |  | ||||||
|  |         if (document.location.hash) { | ||||||
|  |             startNoteId = document.location.hash.substr(1); // strip initial # | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         prepareNoteTree(notes); | ||||||
|  |  | ||||||
|         globalTree.fancytree({ |         globalTree.fancytree({ | ||||||
|             autoScroll: true, |             autoScroll: true, | ||||||
|             extensions: ["hotkeys", "filter", "dnd"], |             extensions: ["hotkeys", "filter", "dnd"], | ||||||
| @@ -215,10 +190,10 @@ $(function(){ | |||||||
|                 saveNoteIfChanged(() => loadNote(node.note_id)); |                 saveNoteIfChanged(() => loadNote(node.note_id)); | ||||||
|             }, |             }, | ||||||
|             expand: function(event, data) { |             expand: function(event, data) { | ||||||
|                 setExpanded(data.node.key, true); |                 setExpandedToServer(data.node.key, true); | ||||||
|             }, |             }, | ||||||
|             collapse: function(event, data) { |             collapse: function(event, data) { | ||||||
|                 setExpanded(data.node.key, false); |                 setExpandedToServer(data.node.key, false); | ||||||
|             }, |             }, | ||||||
|             init: function(event, data) { |             init: function(event, data) { | ||||||
|                 if (startNoteId) { |                 if (startNoteId) { | ||||||
| @@ -242,133 +217,10 @@ $(function(){ | |||||||
|                 nodata: true,      // Display a 'no data' status node if result is empty |                 nodata: true,      // Display a 'no data' status node if result is empty | ||||||
|                 mode: "hide"       // Grayout unmatched nodes (pass "hide" to remove unmatched node instead) |                 mode: "hide"       // Grayout unmatched nodes (pass "hide" to remove unmatched node instead) | ||||||
|             }, |             }, | ||||||
|             dnd: { |             dnd: dragAndDropSetup | ||||||
|                 autoExpandMS: 600, |  | ||||||
|                 draggable: { // modify default jQuery draggable options |  | ||||||
|                     zIndex: 1000, |  | ||||||
|                     scroll: false, |  | ||||||
|                     containment: "parent", |  | ||||||
|                     revert: "invalid" |  | ||||||
|                 }, |  | ||||||
|                 preventRecursiveMoves: true, // Prevent dropping nodes on own descendants |  | ||||||
|                 preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. |  | ||||||
|  |  | ||||||
|                 dragStart: function(node, data) { |  | ||||||
|                     // This function MUST be defined to enable dragging for the tree. |  | ||||||
|                     // Return false to cancel dragging of node. |  | ||||||
|                     return true; |  | ||||||
|                 }, |  | ||||||
|                 dragEnter: function(node, data) { |  | ||||||
|                     /* data.otherNode may be null for non-fancytree droppables. |  | ||||||
|                     * Return false to disallow dropping on node. In this case |  | ||||||
|                     * dragOver and dragLeave are not called. |  | ||||||
|                     * Return 'over', 'before, or 'after' to force a hitMode. |  | ||||||
|                     * Return ['before', 'after'] to restrict available hitModes. |  | ||||||
|                     * Any other return value will calc the hitMode from the cursor position. |  | ||||||
|                     */ |  | ||||||
|                     // Prevent dropping a parent below another parent (only sort |  | ||||||
|                     // nodes under the same parent): |  | ||||||
|                     //    if(node.parent !== data.otherNode.parent){ |  | ||||||
|                     //      return false; |  | ||||||
|                     //    } |  | ||||||
|                     // Don't allow dropping *over* a node (would create a child). Just |  | ||||||
|                     // allow changing the order: |  | ||||||
|                     //    return ["before", "after"]; |  | ||||||
|                     // Accept everything: |  | ||||||
|                     return true; |  | ||||||
|                 }, |  | ||||||
|                 dragExpand: function(node, data) { |  | ||||||
|                   // return false to prevent auto-expanding data.node on hover |  | ||||||
|                 }, |  | ||||||
|                 dragOver: function(node, data) { |  | ||||||
|                 }, |  | ||||||
|                 dragLeave: function(node, data) { |  | ||||||
|                 }, |  | ||||||
|                 dragStop: function(node, data) { |  | ||||||
|                 }, |  | ||||||
|                 dragDrop: function(node, data) { |  | ||||||
|                     // This function MUST be defined to enable dropping of items on the tree. |  | ||||||
|                     // data.hitMode is 'before', 'after', or 'over'. |  | ||||||
|  |  | ||||||
|                     if (data.hitMode === "before") { |  | ||||||
|                         moveBeforeNode(data.otherNode, node); |  | ||||||
|                     } |  | ||||||
|                     else if (data.hitMode === "after") { |  | ||||||
|                         moveAfterNode(data.otherNode, node); |  | ||||||
|                     } |  | ||||||
|                     else if (data.hitMode === "over") { |  | ||||||
|                         moveToNode(data.otherNode, node); |  | ||||||
|                     } |  | ||||||
|                     else { |  | ||||||
|                         throw new Exception("Unknown hitMode=" + data.hitMode); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         globalTree.contextmenu({ |         globalTree.contextmenu(contextMenuSetup); | ||||||
|             delegate: "span.fancytree-title", |  | ||||||
|             autoFocus: true, |  | ||||||
|             menu: [ |  | ||||||
|                 {title: "Insert note here", cmd: "insertNoteHere", uiIcon: "ui-icon-pencil"}, |  | ||||||
|                 {title: "Insert child note", cmd: "insertChildNote", uiIcon: "ui-icon-pencil"}, |  | ||||||
|                 {title: "Delete", cmd: "delete", uiIcon: "ui-icon-trash"}, |  | ||||||
|                 {title: "----"}, |  | ||||||
|                 {title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors"}, |  | ||||||
|                 {title: "Copy / clone", cmd: "copy", uiIcon: "ui-icon-copy"}, |  | ||||||
|                 {title: "Paste after", cmd: "pasteAfter", uiIcon: "ui-icon-clipboard"}, |  | ||||||
|                 {title: "Paste into", cmd: "pasteInto", uiIcon: "ui-icon-clipboard"} |  | ||||||
|             ], |  | ||||||
|             beforeOpen: function (event, ui) { |  | ||||||
|                 const node = $.ui.fancytree.getNode(ui.target); |  | ||||||
|                 // Modify menu entries depending on node status |  | ||||||
|                 globalTree.contextmenu("enableEntry", "pasteAfter", globalClipboardNoteId !== null); |  | ||||||
|                 globalTree.contextmenu("enableEntry", "pasteInto", globalClipboardNoteId !== null); |  | ||||||
|  |  | ||||||
|                 // Activate node on right-click |  | ||||||
|                 node.setActive(); |  | ||||||
|                 // Disable tree keyboard handling |  | ||||||
|                 ui.menu.prevKeyboard = node.tree.options.keyboard; |  | ||||||
|                 node.tree.options.keyboard = false; |  | ||||||
|             }, |  | ||||||
|             close: function (event, ui) {}, |  | ||||||
|             select: function (event, ui) { |  | ||||||
|                 const node = $.ui.fancytree.getNode(ui.target); |  | ||||||
|  |  | ||||||
|                 if (ui.cmd === "insertNoteHere") { |  | ||||||
|                     const parentKey = getParentKey(node); |  | ||||||
|                     const encryption = getParentEncryption(node); |  | ||||||
|  |  | ||||||
|                     createNote(node, parentKey, 'after', encryption); |  | ||||||
|                 } |  | ||||||
|                 else if (ui.cmd === "insertChildNote") { |  | ||||||
|                     createNote(node, node.key, 'into'); |  | ||||||
|                 } |  | ||||||
|                 else if (ui.cmd === "cut") { |  | ||||||
|                     globalClipboardNoteId = node.key; |  | ||||||
|                 } |  | ||||||
|                 else if (ui.cmd === "pasteAfter") { |  | ||||||
|                     const subjectNode = getNodeByKey(globalClipboardNoteId); |  | ||||||
|  |  | ||||||
|                     moveAfterNode(subjectNode, node); |  | ||||||
|  |  | ||||||
|                     globalClipboardNoteId = null; |  | ||||||
|                 } |  | ||||||
|                 else if (ui.cmd === "pasteInto") { |  | ||||||
|                     const subjectNode = getNodeByKey(globalClipboardNoteId); |  | ||||||
|  |  | ||||||
|                     moveToNode(subjectNode, node); |  | ||||||
|  |  | ||||||
|                     globalClipboardNoteId = null; |  | ||||||
|                 } |  | ||||||
|                 else if (ui.cmd === "delete") { |  | ||||||
|                     deleteNode(node); |  | ||||||
|                 } |  | ||||||
|                 else { |  | ||||||
|                     console.log("Unknown command: " + ui.cmd); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								static/js/treeutils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								static/js/treeutils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | function getParentKey(node) { | ||||||
|  |     return (node.getParent() === null || node.getParent().key === "root_1") ? "root" : node.getParent().key; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getParentEncryption(node) { | ||||||
|  |     return node.getParent() === null ? 0 : node.getParent().data.encryption; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getNodeByKey(noteId) { | ||||||
|  |     return globalTree.fancytree('getNodeByKey', noteId); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getFullName(noteId) { | ||||||
|  |     let note = getNodeByKey(noteId); | ||||||
|  |     const path = []; | ||||||
|  |  | ||||||
|  |     while (note) { | ||||||
|  |         path.push(note.title); | ||||||
|  |  | ||||||
|  |         note = note.getParent(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // remove "root" element | ||||||
|  |     path.pop(); | ||||||
|  |  | ||||||
|  |     return path.reverse().join(" > "); | ||||||
|  | } | ||||||
| @@ -14,6 +14,21 @@ function error(str) { | |||||||
|     error.fadeOut(10000); |     error.fadeOut(10000); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getAutocompleteItems(notes) { | ||||||
|  |     const autocompleteItems = []; | ||||||
|  |  | ||||||
|  |     for (const noteId of notes) { | ||||||
|  |         const fullName = getFullName(noteId); | ||||||
|  |  | ||||||
|  |         autocompleteItems.push({ | ||||||
|  |             value: fullName + " (" + noteId + ")", | ||||||
|  |             label: fullName | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return autocompleteItems; | ||||||
|  | } | ||||||
|  |  | ||||||
| function uint8ToBase64(u8Arr) { | function uint8ToBase64(u8Arr) { | ||||||
|     const CHUNK_SIZE = 0x8000; //arbitrary number |     const CHUNK_SIZE = 0x8000; //arbitrary number | ||||||
|     const length = u8Arr.length; |     const length = u8Arr.length; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user