mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	reimplement note source to open in a new tab
This commit is contained in:
		| @@ -37,7 +37,9 @@ class NoteContext extends Component { | ||||
|         return !this.noteId; | ||||
|     } | ||||
|  | ||||
|     async setNote(inputNotePath, triggerSwitchEvent = true) { | ||||
|     async setNote(inputNotePath, opts = {}) { | ||||
|         opts.triggerSwitchEvent = opts.triggerSwitchEvent !== undefined ? opts.triggerSwitchEvent : true; | ||||
|  | ||||
|         const resolvedNotePath = await this.getResolvedNotePath(inputNotePath); | ||||
|  | ||||
|         if (!resolvedNotePath) { | ||||
| @@ -52,12 +54,13 @@ class NoteContext extends Component { | ||||
|         ({noteId: this.noteId, parentNoteId: this.parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(resolvedNotePath)); | ||||
|  | ||||
|         this.resetViewScope(); | ||||
|         this.viewScope.viewMode = opts.viewMode || "default"; | ||||
|  | ||||
|         this.saveToRecentNotes(resolvedNotePath); | ||||
|  | ||||
|         protectedSessionHolder.touchProtectedSessionIfNecessary(this.note); | ||||
|  | ||||
|         if (triggerSwitchEvent) { | ||||
|         if (opts.triggerSwitchEvent) { | ||||
|             await this.triggerEvent('noteSwitched', { | ||||
|                 noteContext: this, | ||||
|                 notePath: this.notePath | ||||
| @@ -183,7 +186,8 @@ class NoteContext extends Component { | ||||
|             mainNtxId: this.mainNtxId, | ||||
|             notePath: this.notePath, | ||||
|             hoistedNoteId: this.hoistedNoteId, | ||||
|             active: this.isActive() | ||||
|             active: this.isActive(), | ||||
|             viewMode: this.viewScope.viewMode | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -224,9 +228,9 @@ class NoteContext extends Component { | ||||
|  | ||||
|         const noteComplement = await this.getNoteComplement(); | ||||
|  | ||||
|         const sizeLimit = this.note.type === 'text' ? | ||||
|             options.getInt('autoReadonlySizeText') | ||||
|                 : options.getInt('autoReadonlySizeCode'); | ||||
|         const sizeLimit = this.note.type === 'text' | ||||
|             ? options.getInt('autoReadonlySizeText') | ||||
|             : options.getInt('autoReadonlySizeCode'); | ||||
|  | ||||
|         return noteComplement.content | ||||
|             && noteComplement.content.length > sizeLimit | ||||
| @@ -251,6 +255,7 @@ class NoteContext extends Component { | ||||
|  | ||||
|     hasNoteList() { | ||||
|         return this.note | ||||
|             && this.viewScope.viewMode === 'default' | ||||
|             && this.note.hasChildren() | ||||
|             && ['book', 'text', 'code'].includes(this.note.type) | ||||
|             && this.note.mime !== 'text/x-sqlite;schema=trilium' | ||||
|   | ||||
| @@ -18,7 +18,7 @@ export default class RootCommandExecutor extends Component { | ||||
|     async showSQLConsoleCommand() { | ||||
|         const sqlConsoleNote = await dateNoteService.createSqlConsole(); | ||||
|  | ||||
|         const noteContext = await appContext.tabManager.openContextWithNote(sqlConsoleNote.noteId, true); | ||||
|         const noteContext = await appContext.tabManager.openContextWithNote(sqlConsoleNote.noteId, { activate: true }); | ||||
|  | ||||
|         appContext.triggerEvent('focusOnDetail', {ntxId: noteContext.ntxId}); | ||||
|     } | ||||
| @@ -32,7 +32,10 @@ export default class RootCommandExecutor extends Component { | ||||
|         const activeNoteContext = appContext.tabManager.getActiveContext(); | ||||
|         const hoistedNoteId = activeNoteContext?.hoistedNoteId || 'root'; | ||||
|  | ||||
|         const noteContext = await appContext.tabManager.openContextWithNote(searchNote.noteId, true, null, hoistedNoteId); | ||||
|         const noteContext = await appContext.tabManager.openContextWithNote(searchNote.noteId, { | ||||
|             activate: true, | ||||
|             hoistedNoteId | ||||
|         }); | ||||
|  | ||||
|         appContext.triggerCommand('focusOnSearchDefinition', {ntxId: noteContext.ntxId}); | ||||
|     } | ||||
| @@ -73,7 +76,7 @@ export default class RootCommandExecutor extends Component { | ||||
|     } | ||||
|  | ||||
|     async showBackendLogCommand() { | ||||
|         await appContext.tabManager.openContextWithNote('_backendLog', true); | ||||
|         await appContext.tabManager.openContextWithNote('_backendLog', { activate: true }); | ||||
|     } | ||||
|  | ||||
|     async showLaunchBarSubtreeCommand() { | ||||
| @@ -89,11 +92,10 @@ export default class RootCommandExecutor extends Component { | ||||
|     } | ||||
|  | ||||
|     async showOptionsCommand({section}) { | ||||
|         await appContext.tabManager.openContextWithNote( | ||||
|             section || '_options', | ||||
|             true, | ||||
|             null, | ||||
|             '_options'); | ||||
|         await appContext.tabManager.openContextWithNote(section || '_options', { | ||||
|             activate: true, | ||||
|             hoistedNoteId: '_options' | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async showSQLConsoleHistoryCommand() { | ||||
| @@ -109,6 +111,17 @@ export default class RootCommandExecutor extends Component { | ||||
|     } | ||||
|  | ||||
|     async showAndHoistSubtree(subtreeNoteId) { | ||||
|         await appContext.tabManager.openContextWithNote(subtreeNoteId, true, null, subtreeNoteId); | ||||
|         await appContext.tabManager.openContextWithNote(subtreeNoteId, { | ||||
|             activate: true, | ||||
|             hoistedNoteId: subtreeNoteId | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     async showNoteSourceEvent() { | ||||
|         const notePath = appContext.tabManager.getActiveContextNotePath(); | ||||
|  | ||||
|         if (notePath) { | ||||
|             await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'source' }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -96,7 +96,13 @@ export default class TabManager extends Component { | ||||
|  | ||||
|             await this.tabsUpdate.allowUpdateWithoutChange(async () => { | ||||
|                 for (const tab of filteredTabs) { | ||||
|                     await this.openContextWithNote(tab.notePath, tab.active, tab.ntxId, tab.hoistedNoteId, tab.mainNtxId); | ||||
|                     await this.openContextWithNote(tab.notePath, { | ||||
|                         activate: tab.active, | ||||
|                         ntxId: tab.ntxId, | ||||
|                         mainNtxId: tab.mainNtxId, | ||||
|                         hoistedNoteId: tab.hoistedNoteId, | ||||
|                         viewMode: tab.viewMode | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
| @@ -277,14 +283,24 @@ export default class TabManager extends Component { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return this.openContextWithNote(notePath, activate, null, hoistedNoteId); | ||||
|         return this.openContextWithNote(notePath, { activate, hoistedNoteId }); | ||||
|     } | ||||
|  | ||||
|     async openContextWithNote(notePath, activate, ntxId = null, hoistedNoteId = 'root', mainNtxId = null) { | ||||
|     async openContextWithNote(notePath, opts = {}) { | ||||
|         const activate = !!opts.activate; | ||||
|         const ntxId = opts.ntxId || null; | ||||
|         const mainNtxId = opts.mainNtxId || null; | ||||
|         const hoistedNoteId = opts.hoistedNoteId || 'root'; | ||||
|         const viewMode = opts.viewMode || "default"; | ||||
|  | ||||
|         const noteContext = await this.openEmptyTab(ntxId, hoistedNoteId, mainNtxId); | ||||
|  | ||||
|         if (notePath) { | ||||
|             await noteContext.setNote(notePath, !activate); // if activate is false then send normal noteSwitched event | ||||
|             await noteContext.setNote(notePath, { | ||||
|                 // if activate is false then send normal noteSwitched event | ||||
|                 triggerSwitchEvent: !activate, | ||||
|                 viewMode: viewMode | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         if (activate) { | ||||
| @@ -310,7 +326,7 @@ export default class TabManager extends Component { | ||||
|  | ||||
|         // if no tab with this note has been found we'll create new tab | ||||
|  | ||||
|         await this.openContextWithNote(noteId, true); | ||||
|         await this.openContextWithNote(noteId, { activate: true }); | ||||
|     } | ||||
|  | ||||
|     async activateNoteContext(ntxId, triggerEvent = true) { | ||||
|   | ||||
| @@ -46,7 +46,6 @@ import FindWidget from "../widgets/find.js"; | ||||
| import TocWidget from "../widgets/toc.js"; | ||||
| import BulkActionsDialog from "../widgets/dialogs/bulk_actions.js"; | ||||
| import AboutDialog from "../widgets/dialogs/about.js"; | ||||
| import NoteSourceDialog from "../widgets/dialogs/note_source.js"; | ||||
| import HelpDialog from "../widgets/dialogs/help.js"; | ||||
| import RecentChangesDialog from "../widgets/dialogs/recent_changes.js"; | ||||
| import BackendLogDialog from "../widgets/dialogs/backend_log.js"; | ||||
| @@ -186,7 +185,6 @@ export default class DesktopLayout { | ||||
|             ) | ||||
|             .child(new BulkActionsDialog()) | ||||
|             .child(new AboutDialog()) | ||||
|             .child(new NoteSourceDialog()) | ||||
|             .child(new HelpDialog()) | ||||
|             .child(new RecentChangesDialog()) | ||||
|             .child(new BackendLogDialog()) | ||||
|   | ||||
| @@ -16,7 +16,7 @@ function openContextMenu(notePath, hoistedNoteId, e) { | ||||
|             } | ||||
|  | ||||
|             if (command === 'openNoteInNewTab') { | ||||
|                 appContext.tabManager.openContextWithNote(notePath, false, null, hoistedNoteId); | ||||
|                 appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId }); | ||||
|             } | ||||
|             else if (command === 'openNoteInNewSplit') { | ||||
|                 const subContexts = appContext.tabManager.getActiveContext().getSubContexts(); | ||||
|   | ||||
| @@ -103,7 +103,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | ||||
|     this.openTabWithNote = async (notePath, activate) => { | ||||
|         await ws.waitForMaxKnownEntityChangeId(); | ||||
|  | ||||
|         await appContext.tabManager.openContextWithNote(notePath, activate); | ||||
|         await appContext.tabManager.openContextWithNote(notePath, { activate }); | ||||
|  | ||||
|         if (activate) { | ||||
|             appContext.triggerEvent('focusAndSelectTitle'); | ||||
|   | ||||
| @@ -42,7 +42,7 @@ async function checkNoteAccess(notePath, noteContext) { | ||||
|     const resolvedNotePath = await treeService.resolveNotePath(notePath, noteContext.hoistedNoteId); | ||||
|  | ||||
|     if (!resolvedNotePath) { | ||||
|         console.log(`Cannot activate ${notePath}`); | ||||
|         console.log(`Cannot activate '${notePath}'`); | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -27,7 +27,7 @@ const TPL = ` | ||||
|     <div class="dropdown-menu dropdown-menu-right"> | ||||
|         <a data-trigger-command="renderActiveNote" class="dropdown-item render-note-button"><kbd data-command="renderActiveNote"></kbd> Re-render note</a> | ||||
|         <a data-trigger-command="findInText" class="dropdown-item find-in-text-button">Search in note <kbd data-command="findInText"></a> | ||||
|         <a data-trigger-command="openNoteSourceDialog" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a> | ||||
|         <a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a> | ||||
|         <a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a> | ||||
|         <a class="dropdown-item import-files-button">Import files</a> | ||||
|         <a class="dropdown-item export-note-button">Export note</a> | ||||
| @@ -81,7 +81,7 @@ export default class NoteActionsWidget extends NoteContextAwareWidget { | ||||
|     refreshWithNote(note) { | ||||
|         this.toggleDisabled(this.$findInTextButton, ['text', 'code', 'book', 'search'].includes(note.type)); | ||||
|  | ||||
|         this.toggleDisabled(this.$showSourceButton, ['text', 'relationMap', 'search', 'code'].includes(note.type)); | ||||
|         this.toggleDisabled(this.$showSourceButton, ['text', 'relationMap', 'mermaid'].includes(note.type)); | ||||
|  | ||||
|         this.toggleDisabled(this.$printActiveNoteButton, ['text', 'code'].includes(note.type)); | ||||
|  | ||||
|   | ||||
| @@ -1,77 +0,0 @@ | ||||
| import appContext from "../../components/app_context.js"; | ||||
| import BasicWidget from "../basic_widget.js"; | ||||
| import utils from "../../services/utils.js"; | ||||
|  | ||||
| const TPL = ` | ||||
| <div class="note-source-dialog modal fade mx-auto" tabindex="-1" role="dialog"> | ||||
|     <style> | ||||
|         .note-source-dialog .note-source { | ||||
|             height: 98%; | ||||
|             width: 100%; | ||||
|             min-height: 500px; | ||||
|             overflow: scroll; | ||||
|         } | ||||
|     </style> | ||||
|  | ||||
|     <div class="modal-dialog modal-lg" role="document"> | ||||
|         <div class="modal-content"> | ||||
|             <div class="modal-header"> | ||||
|                 <h5 class="modal-title">Note source</h5> | ||||
|                 <button type="button" class="close" data-dismiss="modal" aria-label="Close"> | ||||
|                     <span aria-hidden="true">×</span> | ||||
|                 </button> | ||||
|             </div> | ||||
|             <div class="modal-body"> | ||||
|                 <textarea readonly="readonly" class="note-source"></textarea> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div>`; | ||||
|  | ||||
| export default class NoteSourceDialog extends BasicWidget { | ||||
|     doRender() { | ||||
|         this.$widget = $(TPL); | ||||
|         this.$noteSource = this.$widget.find(".note-source"); | ||||
|     } | ||||
|  | ||||
|     async refresh() { | ||||
|         const noteCompletement = await appContext.tabManager.getActiveContext().getNoteComplement(); | ||||
|  | ||||
|         this.$noteSource.text(this.formatHtml(noteCompletement.content)); | ||||
|     } | ||||
|  | ||||
|     formatHtml(str) { | ||||
|         const div = document.createElement('div'); | ||||
|         div.innerHTML = str.trim(); | ||||
|  | ||||
|         return this.formatNode(div, 0).innerHTML.trim(); | ||||
|     } | ||||
|  | ||||
|     formatNode(node, level) { | ||||
|         const indentBefore = new Array(level++ + 1).join('  '); | ||||
|         const indentAfter  = new Array(level - 1).join('  '); | ||||
|         let textNode; | ||||
|  | ||||
|         for (let i = 0; i < node.children.length; i++) { | ||||
|             textNode = document.createTextNode(` | ||||
| ${indentBefore}`); | ||||
|             node.insertBefore(textNode, node.children[i]); | ||||
|  | ||||
|             this.formatNode(node.children[i], level); | ||||
|  | ||||
|             if (node.lastElementChild === node.children[i]) { | ||||
|                 textNode = document.createTextNode(` | ||||
| ${indentAfter}`); | ||||
|                 node.appendChild(textNode); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return node; | ||||
|     } | ||||
|  | ||||
|     async openNoteSourceDialogEvent() { | ||||
|         await this.refresh(); | ||||
|  | ||||
|         utils.openDialog(this.$widget); | ||||
|     } | ||||
| } | ||||
| @@ -187,23 +187,17 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { | ||||
|  | ||||
|         let type = note.type; | ||||
|  | ||||
|         if (type === 'text' && await this.noteContext.isReadOnly()) { | ||||
|             type = 'readOnlyText'; | ||||
|         } | ||||
|  | ||||
|         if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) { | ||||
|         if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') { | ||||
|             type = 'readOnlyCode'; | ||||
|         } | ||||
|  | ||||
|         if (type === 'text') { | ||||
|         } else if (type === 'text' && await this.noteContext.isReadOnly()) { | ||||
|             type = 'readOnlyText'; | ||||
|         } else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) { | ||||
|             type = 'readOnlyCode'; | ||||
|         } else if (type === 'text') { | ||||
|             type = 'editableText'; | ||||
|         } | ||||
|  | ||||
|         if (type === 'code' || type === 'mermaid') { | ||||
|         } else if (type === 'code' || type === 'mermaid') { | ||||
|             type = 'editableCode'; | ||||
|         } | ||||
|  | ||||
|         if (type === 'launcher') { | ||||
|         } else if (type === 'launcher') { | ||||
|             type = 'doc'; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -617,12 +617,13 @@ export default class TabRowWidget extends BasicWidget { | ||||
|     updateTabById(ntxId) { | ||||
|         const $tab = this.getTabById(ntxId); | ||||
|  | ||||
|         const {note} = appContext.tabManager.getNoteContextById(ntxId); | ||||
|         const noteContext = appContext.tabManager.getNoteContextById(ntxId); | ||||
|  | ||||
|         this.updateTab($tab, note); | ||||
|         this.updateTab($tab, noteContext); | ||||
|     } | ||||
|  | ||||
|     updateTab($tab, note) { | ||||
|     /** @param {NoteContext} noteContext */ | ||||
|     updateTab($tab, noteContext) { | ||||
|         if (!$tab.length) { | ||||
|             return; | ||||
|         } | ||||
| @@ -633,8 +634,6 @@ export default class TabRowWidget extends BasicWidget { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         const noteContext = appContext.tabManager.getNoteContextById(this.getTabId($tab)); | ||||
|  | ||||
|         if (noteContext) { | ||||
|             const hoistedNote = froca.getNoteFromCache(noteContext.hoistedNoteId); | ||||
|  | ||||
| @@ -651,12 +650,19 @@ export default class TabRowWidget extends BasicWidget { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         const {note} = noteContext; | ||||
|  | ||||
|         if (!note) { | ||||
|             this.updateTitle($tab, 'New tab'); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.updateTitle($tab, note.title); | ||||
|         const viewMode = noteContext.viewScope?.viewMode; | ||||
|         const title = (viewMode && viewMode !== 'default') | ||||
|             ? `${viewMode}: ${note.title}` | ||||
|             : note.title; | ||||
|  | ||||
|         this.updateTitle($tab, title); | ||||
|  | ||||
|         $tab.addClass(note.getCssClass()); | ||||
|         $tab.addClass(utils.getNoteTypeClass(note.type)); | ||||
| @@ -676,7 +682,7 @@ export default class TabRowWidget extends BasicWidget { | ||||
|             ) { | ||||
|                 const $tab = this.getTabById(noteContext.ntxId); | ||||
|  | ||||
|                 this.updateTab($tab, noteContext.note); | ||||
|                 this.updateTab($tab, noteContext); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -685,7 +691,7 @@ export default class TabRowWidget extends BasicWidget { | ||||
|         for (const noteContext of appContext.tabManager.noteContexts) { | ||||
|             const $tab = this.getTabById(noteContext.ntxId); | ||||
|  | ||||
|             this.updateTab($tab, noteContext.note); | ||||
|             this.updateTab($tab, noteContext); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -695,7 +701,7 @@ export default class TabRowWidget extends BasicWidget { | ||||
|         if ($tab) { | ||||
|             const noteContext = appContext.tabManager.getNoteContextById(ntxId); | ||||
|  | ||||
|             this.updateTab($tab, noteContext.note); | ||||
|             this.updateTab($tab, noteContext); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user