mirror of
https://github.com/zadam/trilium.git
synced 2025-06-05 01:18:44 +02:00
work on hash & history
This commit is contained in:
parent
2178f82324
commit
dd1fc23fe8
@ -1,4 +1,4 @@
|
||||
INSERT INTO options (name, value, utcDateCreated, utcDateModified, isSynced)
|
||||
SELECT 'openTabs', '[{"notePath":"' || value || '","active": true}]', '2019-05-01T18:31:00.874Z', '2019-05-01T18:31:00.874Z', 0 FROM options WHERE name = 'startNotePath';
|
||||
SELECT 'openTabs', '[{"notePath":"' || value || '","active": true,"tabId":"1111"}]', '2019-05-01T18:31:00.874Z', '2019-05-01T18:31:00.874Z', 0 FROM options WHERE name = 'startNotePath';
|
||||
|
||||
DELETE FROM options WHERE name = 'startNotePath';
|
@ -47,8 +47,6 @@ async function showTree() {
|
||||
|
||||
treeService.clearSelectedNodes();
|
||||
|
||||
treeService.setCurrentNotePathToHash(node);
|
||||
|
||||
showDetailPane();
|
||||
|
||||
const notePath = await treeUtils.getNotePath(node);
|
||||
|
@ -103,8 +103,6 @@ async function deleteNodes(nodes) {
|
||||
if (next) {
|
||||
// activate next element after this one is deleted so we don't lose focus
|
||||
next.setActive();
|
||||
|
||||
treeService.setCurrentNotePathToHash(next);
|
||||
}
|
||||
|
||||
await treeService.loadTreeCache();
|
||||
@ -163,8 +161,6 @@ async function changeNode(func, node, beforeNoteId = null, afterNoteId = null) {
|
||||
|
||||
await treeCache.moveNote(childNoteId, thisOldParentNode.data.noteId, thisNewParentNode.data.noteId, beforeNoteId, afterNoteId);
|
||||
|
||||
treeService.setCurrentNotePathToHash(node);
|
||||
|
||||
await treeService.checkFolderStatus(thisOldParentNode);
|
||||
await treeService.checkFolderStatus(thisNewParentNode);
|
||||
|
||||
|
@ -268,9 +268,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @returns {Promise<string>} returns note path of active note
|
||||
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
||||
*/
|
||||
this.getActiveNotePath = treeService.getActiveNotePath;
|
||||
this.getActiveNotePath = () => {
|
||||
const activeTabContext = noteDetailService.getActiveTabContext();
|
||||
|
||||
return activeTabContext ? activeTabContext.notePath : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* This method checks whether user navigated away from the note from which the scripts has been started.
|
||||
|
@ -102,9 +102,27 @@ function getActiveTabContext() {
|
||||
return tabContexts.find(tc => tc.tabId === tabId);
|
||||
}
|
||||
|
||||
function isActive(tabContext) {
|
||||
return tabContext.$tab[0] === tabRow.activateTab;
|
||||
}
|
||||
|
||||
async function activateTabContext(tabContext) {
|
||||
await tabRow.activateTab(tabContext.$tab[0]);
|
||||
}
|
||||
|
||||
/** @returns {TabContext} */
|
||||
function getTabContext(tabId) {
|
||||
return tabContexts.find(tc => tc.tabId === tabId);
|
||||
}
|
||||
|
||||
async function showTab(tabId) {
|
||||
for (const ctx of tabContexts) {
|
||||
ctx.$tabContent.toggle(ctx.tabId === tabId);
|
||||
if (ctx.tabId === tabId) {
|
||||
ctx.show();
|
||||
}
|
||||
else {
|
||||
ctx.hide();
|
||||
}
|
||||
}
|
||||
|
||||
const oldActiveNode = treeService.getActiveNode();
|
||||
@ -207,9 +225,9 @@ async function loadNoteDetail(origNotePath, options = {}) {
|
||||
const loadedNote = await loadNote(noteId);
|
||||
let ctx;
|
||||
|
||||
if (tabContexts.length === 0 || newTab) {
|
||||
if (!getActiveTabContext() || newTab) {
|
||||
// if it's a new tab explicitly by user then it's in background
|
||||
ctx = new TabContext(tabRow);
|
||||
ctx = new TabContext(tabRow, options.tabId);
|
||||
tabContexts.push(ctx);
|
||||
}
|
||||
else {
|
||||
@ -229,7 +247,7 @@ async function loadNoteDetail(origNotePath, options = {}) {
|
||||
|
||||
if (activate) {
|
||||
// will also trigger showTab via event
|
||||
tabRow.setCurrentTab(ctx.$tab[0]);
|
||||
await tabRow.activateTab(ctx.$tab[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +334,7 @@ async function openEmptyTab() {
|
||||
|
||||
await renderComponent(ctx);
|
||||
|
||||
await tabRow.setCurrentTab(ctx.tab);
|
||||
await tabRow.activateTab(ctx.$tab[0]);
|
||||
}
|
||||
|
||||
tabRow.addListener('newTab', openEmptyTab);
|
||||
@ -380,7 +398,7 @@ if (utils.isElectron()) {
|
||||
const nextTab = tabRow.nextTabEl;
|
||||
|
||||
if (nextTab) {
|
||||
tabRow.setCurrentTab(nextTab);
|
||||
tabRow.activateTab(nextTab);
|
||||
}
|
||||
});
|
||||
|
||||
@ -388,7 +406,7 @@ if (utils.isElectron()) {
|
||||
const prevTab = tabRow.previousTabEl;
|
||||
|
||||
if (prevTab) {
|
||||
tabRow.setCurrentTab(prevTab);
|
||||
tabRow.activateTab(prevTab);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -424,6 +442,7 @@ async function saveOpenTabs() {
|
||||
|
||||
if (tabContext && tabContext.notePath) {
|
||||
openTabs.push({
|
||||
tabId: tabContext.tabId,
|
||||
notePath: tabContext.notePath,
|
||||
active: activeTabEl === tabEl
|
||||
});
|
||||
@ -457,8 +476,11 @@ export default {
|
||||
saveNotesIfChanged,
|
||||
onNoteChange,
|
||||
addDetailLoadedListener,
|
||||
getTabContext,
|
||||
getTabContexts,
|
||||
getActiveTabContext,
|
||||
isActive,
|
||||
activateTabContext,
|
||||
getActiveComponent,
|
||||
clearOpenTabsTask,
|
||||
filterTabs
|
||||
|
@ -141,7 +141,7 @@ async function refreshSearch() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
const hashValue = treeService.getHashValueFromAddress();
|
||||
const hashValue = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
|
||||
|
||||
if (hashValue.startsWith("search=")) {
|
||||
showSearch();
|
||||
|
@ -36,10 +36,10 @@ class TabContext {
|
||||
/**
|
||||
* @param {TabRow} tabRow
|
||||
*/
|
||||
constructor(tabRow) {
|
||||
constructor(tabRow, tabId = null) {
|
||||
this.tabRow = tabRow;
|
||||
this.$tab = $(this.tabRow.addTab());
|
||||
this.tabId = this.$tab.attr('data-tab-id');
|
||||
this.tabId = tabId || utils.randomString(4);
|
||||
this.$tab = $(this.tabRow.addTab(this.tabId));
|
||||
|
||||
this.$tabContent = $(".note-tab-content-template").clone();
|
||||
this.$tabContent.removeClass('note-tab-content-template');
|
||||
@ -96,9 +96,40 @@ class TabContext {
|
||||
|
||||
this.setupClasses();
|
||||
|
||||
this.setCurrentNotePathToHash();
|
||||
|
||||
setTimeout(async () => {
|
||||
// we include the note into recent list only if the user stayed on the note at least 5 seconds
|
||||
if (notePath && notePath === await this.notePath) {
|
||||
await server.post('recent-notes', { notePath });
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
console.log(`Switched tab ${this.tabId} to ${this.noteId}`);
|
||||
}
|
||||
|
||||
show() {
|
||||
this.$tabContent.show();
|
||||
this.setCurrentNotePathToHash();
|
||||
|
||||
document.title = "Trilium Notes";
|
||||
|
||||
if (this.note) {
|
||||
// it helps navigating in history if note title is included in the title
|
||||
document.title += " - " + this.note.title;
|
||||
}
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.$tabContent.hide();
|
||||
}
|
||||
|
||||
setCurrentNotePathToHash() {
|
||||
if (this.$tab[0] === this.tabRow.activeTabEl) {
|
||||
document.location.hash = (this.notePath || "") + "-" + this.tabId;
|
||||
}
|
||||
}
|
||||
|
||||
setupClasses() {
|
||||
for (const clazz of Array.from(this.$tab[0].classList)) { // create copy to safely iterate over while removing classes
|
||||
if (clazz !== 'note-tab') {
|
||||
@ -205,13 +236,11 @@ class TabContext {
|
||||
|
||||
this.$childrenOverview.empty();
|
||||
|
||||
const notePath = await treeService.getActiveNotePath();
|
||||
|
||||
for (const childBranch of await this.note.getChildBranches()) {
|
||||
const link = $('<a>', {
|
||||
href: 'javascript:',
|
||||
text: await treeUtils.getNoteTitle(childBranch.noteId, childBranch.parentNoteId)
|
||||
}).attr('data-action', 'note').attr('data-note-path', notePath + '/' + childBranch.noteId);
|
||||
}).attr('data-action', 'note').attr('data-note-path', this.notePath + '/' + childBranch.noteId);
|
||||
|
||||
const childEl = $('<div class="child-overview-item">').html(link);
|
||||
this.$childrenOverview.append(childEl);
|
||||
|
File diff suppressed because one or more lines are too long
@ -38,10 +38,6 @@ function getActiveNode() {
|
||||
return $tree.fancytree("getActiveNode");
|
||||
}
|
||||
|
||||
async function getActiveNotePath() {
|
||||
return getHashValueFromAddress();
|
||||
}
|
||||
|
||||
async function getNodesByBranchId(branchId) {
|
||||
utils.assertArguments(branchId);
|
||||
|
||||
@ -135,6 +131,12 @@ async function activateNote(notePath, noteLoadedListener) {
|
||||
// notePath argument can contain only noteId which is not good when hoisted since
|
||||
// then we need to check the whole note path
|
||||
const runNotePath = await getRunPath(notePath);
|
||||
|
||||
if (!runNotePath) {
|
||||
console.log("Cannot activate " + notePath);
|
||||
return;
|
||||
}
|
||||
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
if (hoistedNoteId !== 'root' && !runNotePath.includes(hoistedNoteId)) {
|
||||
@ -172,7 +174,7 @@ async function activateNote(notePath, noteLoadedListener) {
|
||||
async function resolveNotePath(notePath) {
|
||||
const runPath = await getRunPath(notePath);
|
||||
|
||||
return runPath.join("/");
|
||||
return runPath ? runPath.join("/") : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,7 +207,8 @@ async function getRunPath(notePath) {
|
||||
const child = await treeCache.getNote(childNoteId);
|
||||
|
||||
if (!child) {
|
||||
console.log("Can't find " + childNoteId);
|
||||
console.log("Can't find note " + childNoteId);
|
||||
return;
|
||||
}
|
||||
|
||||
const parents = await child.getParentNotes();
|
||||
@ -331,26 +334,6 @@ async function setExpandedToServer(branchId, isExpanded) {
|
||||
await server.put('branches/' + branchId + '/expanded/' + expandedNum);
|
||||
}
|
||||
|
||||
function addRecentNote(branchId, notePath) {
|
||||
setTimeout(async () => {
|
||||
// we include the note into recent list only if the user stayed on the note at least 5 seconds
|
||||
if (notePath && notePath === await getActiveNotePath()) {
|
||||
await server.post('recent-notes', { branchId, notePath });
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
async function setCurrentNotePathToHash(node) {
|
||||
utils.assertArguments(node);
|
||||
|
||||
const activeNotePath = await treeUtils.getNotePath(node);
|
||||
const currentBranchId = node.data.branchId;
|
||||
|
||||
document.location.hash = activeNotePath;
|
||||
|
||||
addRecentNote(currentBranchId, activeNotePath);
|
||||
}
|
||||
|
||||
function getSelectedNodes(stopOnParents = false) {
|
||||
return getTree().getSelectedNodes(stopOnParents);
|
||||
}
|
||||
@ -402,8 +385,13 @@ async function treeInitialized() {
|
||||
});
|
||||
}
|
||||
|
||||
if (!filteredTabs.find(tab => tab.active)) {
|
||||
filteredTabs[0].active = true;
|
||||
}
|
||||
|
||||
for (const tab of filteredTabs) {
|
||||
await noteDetailService.loadNoteDetail(tab.notePath, {
|
||||
tabId: tab.tabId,
|
||||
newTab: true,
|
||||
activate: tab.active
|
||||
});
|
||||
@ -465,8 +453,6 @@ function initFancyTree(tree) {
|
||||
// click event won't propagate so let's close context menu manually
|
||||
contextMenuWidget.hideContextMenu();
|
||||
|
||||
await setCurrentNotePathToHash(node);
|
||||
|
||||
const notePath = await treeUtils.getNotePath(node);
|
||||
|
||||
noteDetailService.switchToNote(notePath);
|
||||
@ -554,11 +540,17 @@ async function reload() {
|
||||
}
|
||||
|
||||
function isNotePathInAddress() {
|
||||
return getHashValueFromAddress().startsWith("root");
|
||||
const [notePath, tabId] = getHashValueFromAddress();
|
||||
|
||||
return notePath.startsWith("root")
|
||||
// empty string is for empty/uninitialized tab
|
||||
|| (notePath === '' && !!tabId);
|
||||
}
|
||||
|
||||
function getHashValueFromAddress() {
|
||||
return document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
|
||||
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
|
||||
|
||||
return str.split("-");
|
||||
}
|
||||
|
||||
async function loadTreeCache() {
|
||||
@ -835,13 +827,27 @@ utils.bindShortcut('ctrl+.', scrollToActiveNote);
|
||||
|
||||
$(window).bind('hashchange', async function() {
|
||||
if (isNotePathInAddress()) {
|
||||
const notePath = getHashValueFromAddress();
|
||||
const noteId = notePath.split("/").pop();
|
||||
const [notePath, tabId] = getHashValueFromAddress();
|
||||
|
||||
if (noteId !== '-' && noteId !== getActiveNode().data.noteId) {
|
||||
console.debug("Switching to " + notePath + " because of hash change");
|
||||
console.debug(`Switching to ${notePath} on tab ${tabId} because of hash change`);
|
||||
|
||||
activateNote(notePath);
|
||||
let tabContext = noteDetailService.getTabContext(tabId);
|
||||
|
||||
if (!tabContext) {
|
||||
noteDetailService.loadNoteDetail(notePath, {
|
||||
newTab: true,
|
||||
tabId: tabId,
|
||||
activate: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (!noteDetailService.isActive(tabContext)) {
|
||||
noteDetailService.activateTabContext(tabContext);
|
||||
}
|
||||
|
||||
if (notePath && tabContext.notePath !== notePath) {
|
||||
noteDetailService.loadNoteDetail(notePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -860,8 +866,6 @@ export default {
|
||||
activateNote,
|
||||
getFocusedNode,
|
||||
getActiveNode,
|
||||
getActiveNotePath,
|
||||
setCurrentNotePathToHash,
|
||||
setNoteTitle,
|
||||
setPrefix,
|
||||
createNote,
|
||||
|
@ -134,11 +134,6 @@ li.dropdown-submenu:hover > ul.dropdown-menu {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.note-tab-content {
|
||||
font-family: var(--detail-font-family);
|
||||
font-size: var(--detail-font-size);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
}
|
||||
|
@ -118,6 +118,8 @@ ul.fancytree-container {
|
||||
flex-direction: column;
|
||||
min-height: 200px;
|
||||
word-break: break-all; /* otherwise CKEditor fails miserably on super long lines */
|
||||
font-family: var(--detail-font-family);
|
||||
font-size: var(--detail-font-size);
|
||||
}
|
||||
|
||||
.note-detail-component {
|
||||
|
@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
const optionService = require('../../services/options');
|
||||
const RecentNote = require('../../entities/recent_note');
|
||||
|
||||
async function addRecentNote(req) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user