reimplement note source to open in a new tab

This commit is contained in:
zadam 2023-02-14 16:06:49 +01:00
parent c190296bf9
commit b1e2b5ba8e
11 changed files with 82 additions and 127 deletions

View File

@ -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,8 +228,8 @@ class NoteContext extends Component {
const noteComplement = await this.getNoteComplement();
const sizeLimit = this.note.type === 'text' ?
options.getInt('autoReadonlySizeText')
const sizeLimit = this.note.type === 'text'
? options.getInt('autoReadonlySizeText')
: options.getInt('autoReadonlySizeCode');
return noteComplement.content
@ -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'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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">&times;</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);
}
}

View File

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

View File

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