mirror of
https://github.com/zadam/trilium.git
synced 2025-06-05 01:18:44 +02:00
shortcuts improvements
This commit is contained in:
parent
6883b71ce7
commit
6a9ac6f90a
@ -83,8 +83,10 @@ function getNoteTitleArrayForPath(notePathArray) {
|
||||
throw new Error(`${notePathArray} is not an array.`);
|
||||
}
|
||||
|
||||
if (notePathArray.length === 1 && notePathArray[0] === cls.getHoistedNoteId()) {
|
||||
return [getNoteTitle(cls.getHoistedNoteId())];
|
||||
const hoistedNoteId = cls.getHoistedNoteId();
|
||||
|
||||
if (notePathArray.length === 1 && notePathArray[0] === hoistedNoteId) {
|
||||
return [getNoteTitle(hoistedNoteId)];
|
||||
}
|
||||
|
||||
const titles = [];
|
||||
@ -92,6 +94,9 @@ function getNoteTitleArrayForPath(notePathArray) {
|
||||
let parentNoteId = 'root';
|
||||
let hoistedNotePassed = false;
|
||||
|
||||
// this is a notePath from outside of hoisted subtree so full title path needs to be returned
|
||||
const outsideOfHoistedSubtree = !notePathArray.includes(hoistedNoteId);
|
||||
|
||||
for (const noteId of notePathArray) {
|
||||
// start collecting path segment titles only after hoisted note
|
||||
if (hoistedNotePassed) {
|
||||
@ -100,7 +105,7 @@ function getNoteTitleArrayForPath(notePathArray) {
|
||||
titles.push(title);
|
||||
}
|
||||
|
||||
if (noteId === cls.getHoistedNoteId()) {
|
||||
if (!hoistedNotePassed && (noteId === hoistedNoteId || outsideOfHoistedSubtree)) {
|
||||
hoistedNotePassed = true;
|
||||
}
|
||||
|
||||
|
@ -193,9 +193,15 @@ class Branch extends AbstractEntity {
|
||||
|
||||
beforeSaving() {
|
||||
if (this.notePosition === undefined || this.notePosition === null) {
|
||||
// TODO finding new position can be refactored into becca
|
||||
const maxNotePos = sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]);
|
||||
this.notePosition = maxNotePos === null ? 0 : maxNotePos + 10;
|
||||
let maxNotePos = 0;
|
||||
|
||||
for (const childBranch of this.parentNote.getChildBranches()) {
|
||||
if (maxNotePos < childBranch.notePosition && childBranch.branchId !== 'hidden') {
|
||||
maxNotePos = childBranch.notePosition;
|
||||
}
|
||||
}
|
||||
|
||||
this.notePosition = maxNotePos + 10;
|
||||
}
|
||||
|
||||
if (!this.isExpanded) {
|
||||
|
@ -396,6 +396,10 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
autoExpandMS: 600,
|
||||
preventLazyParents: false,
|
||||
dragStart: (node, data) => {
|
||||
if (['root', 'hidden', 'lb_root', 'lb_availableshortcuts', 'lb_visibleshortcuts'].includes(node.data.noteId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const notes = this.getSelectedOrActiveNodes(node).map(node => ({
|
||||
noteId: node.data.noteId,
|
||||
branchId: node.data.branchId,
|
||||
@ -417,7 +421,19 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
data.dataTransfer.setData("text", JSON.stringify(notes));
|
||||
return true; // allow dragging to start
|
||||
},
|
||||
dragEnter: (node, data) => node.data.noteType !== 'search',
|
||||
dragEnter: (node, data) => {
|
||||
console.log(data, node.data.noteType);
|
||||
|
||||
if (node.data.noteType === 'search') {
|
||||
return false;
|
||||
} else if (node.data.noteId === 'lb_root') {
|
||||
return false;
|
||||
} else if (node.data.noteType === 'shortcut') {
|
||||
return ['before', 'after'];
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
dragDrop: async (node, data) => {
|
||||
if ((data.hitMode === 'over' && node.data.noteType === 'search') ||
|
||||
(['after', 'before'].includes(data.hitMode)
|
||||
|
@ -20,8 +20,12 @@ function updateNoteAttribute(req) {
|
||||
if (body.attributeId) {
|
||||
attribute = becca.getAttribute(body.attributeId);
|
||||
|
||||
if (!attribute) {
|
||||
return [404, `Attribute '${body.attributeId}' does not exist.`];
|
||||
}
|
||||
|
||||
if (attribute.noteId !== noteId) {
|
||||
return [400, `Attribute ${body.attributeId} is not owned by ${noteId}`];
|
||||
return [400, `Attribute '${body.attributeId}' is not owned by ${noteId}`];
|
||||
}
|
||||
|
||||
if (body.type !== attribute.type
|
||||
|
@ -73,10 +73,7 @@ function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) {
|
||||
const parentNote = becca.getNote(parentNoteId);
|
||||
|
||||
if (parentNote.type === 'search') {
|
||||
return {
|
||||
success: false,
|
||||
message: "Can't clone into a search note"
|
||||
};
|
||||
return { success: false, message: "Can't clone into a search note" };
|
||||
}
|
||||
|
||||
const validationResult = treeService.validateParentChild(parentNoteId, noteId);
|
||||
@ -122,6 +119,12 @@ function toggleNoteInParent(present, noteId, parentNoteId, prefix) {
|
||||
}
|
||||
|
||||
function cloneNoteAfter(noteId, afterBranchId) {
|
||||
if (['hidden', 'root'].includes(noteId)) {
|
||||
return { success: false, message: 'Cloning the given note is forbidden.' };
|
||||
} else if (afterBranchId === 'hidden') {
|
||||
return { success: false, message: 'Cannot clone after the hidden branch.' };
|
||||
}
|
||||
|
||||
const afterNote = becca.getBranch(afterBranchId);
|
||||
|
||||
if (isNoteDeleted(noteId) || isNoteDeleted(afterNote.parentNoteId)) {
|
||||
|
27
src/services/hoisted_note.js
Normal file
27
src/services/hoisted_note.js
Normal file
@ -0,0 +1,27 @@
|
||||
const cls = require("./cls");
|
||||
const becca = require("../becca/becca");
|
||||
|
||||
function getHoistedNoteId() {
|
||||
return cls.getHoistedNoteId();
|
||||
}
|
||||
|
||||
function isHoistedInHiddenSubtree() {
|
||||
const hoistedNoteId = getHoistedNoteId();
|
||||
|
||||
if (hoistedNoteId === 'root') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hoistedNote = becca.getNote(hoistedNoteId);
|
||||
|
||||
if (!hoistedNote) {
|
||||
throw new Error(`Cannot find hoisted note ${hoistedNoteId}`);
|
||||
}
|
||||
|
||||
return hoistedNote.hasAncestor('hidden');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getHoistedNoteId,
|
||||
isHoistedInHiddenSubtree
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const cls = require('../cls');
|
||||
const hoistedNoteService = require("../hoisted_note");
|
||||
|
||||
class SearchContext {
|
||||
constructor(params = {}) {
|
||||
@ -9,8 +9,10 @@ class SearchContext {
|
||||
this.ignoreHoistedNote = !!params.ignoreHoistedNote;
|
||||
this.ancestorNoteId = params.ancestorNoteId;
|
||||
|
||||
if (!this.ancestorNoteId && !this.ignoreHoistedNote) {
|
||||
this.ancestorNoteId = cls.getHoistedNoteId();
|
||||
if (!this.ancestorNoteId && !this.ignoreHoistedNote && !hoistedNoteService.isHoistedInHiddenSubtree()) {
|
||||
// hoisting in hidden subtree should not limit autocomplete
|
||||
// since we want to link (create relations) to the normal non-hidden notes
|
||||
this.ancestorNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
}
|
||||
|
||||
this.ancestorDepth = params.ancestorDepth;
|
||||
|
@ -53,6 +53,16 @@ function getHiddenRoot() {
|
||||
hidden.addLabel("docName", "hidden");
|
||||
}
|
||||
|
||||
const MAX_POS = 999_999_999;
|
||||
|
||||
const branch = hidden.getBranches()[0];
|
||||
if (branch.notePosition !== MAX_POS) {
|
||||
// we want to keep the hidden subtree always last, otherwise there will be problems with e.g. keyboard navigation
|
||||
// over tree when it's in the middle
|
||||
branch.notePosition = MAX_POS;
|
||||
branch.save();
|
||||
}
|
||||
|
||||
return hidden;
|
||||
}
|
||||
|
||||
|
@ -30,13 +30,13 @@ function getNotes(noteIds) {
|
||||
}
|
||||
|
||||
function validateParentChild(parentNoteId, childNoteId, branchId = null) {
|
||||
if (childNoteId === 'root') {
|
||||
return { success: false, message: 'Cannot move root note.'};
|
||||
if (['root', 'hidden'].includes(childNoteId)) {
|
||||
return { success: false, message: `Cannot change this note's location.`};
|
||||
}
|
||||
|
||||
if (parentNoteId === 'none') {
|
||||
// this shouldn't happen
|
||||
return { success: false, message: 'Cannot move anything into root parent.' };
|
||||
return { success: false, message: `Cannot move anything into 'none' parent.` };
|
||||
}
|
||||
|
||||
const existing = getExistingBranch(parentNoteId, childNoteId);
|
||||
@ -58,13 +58,10 @@ function validateParentChild(parentNoteId, childNoteId, branchId = null) {
|
||||
};
|
||||
}
|
||||
|
||||
const parentNoteIsShortcut = becca.getNote(parentNoteId).type === 'shortcut';
|
||||
const childNoteIsShortcut = becca.getNote(childNoteId).type === 'shortcut';
|
||||
|
||||
if (parentNoteIsShortcut !== childNoteIsShortcut) {
|
||||
if (becca.getNote(parentNoteId).type === 'shortcut') {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Moving/cloning is not possible between shortcuts / normal notes.'
|
||||
message: 'Shortcut note cannot have any children.'
|
||||
};
|
||||
}
|
||||
|
||||
@ -189,6 +186,10 @@ function sortNotes(parentNoteId, customSortBy = 'title', reverse = false, folder
|
||||
for (const note of notes) {
|
||||
const branch = note.getParentBranches().find(b => b.parentNoteId === parentNoteId);
|
||||
|
||||
if (branch.branchId === 'hidden') {
|
||||
position = 999_999_999;
|
||||
}
|
||||
|
||||
sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?",
|
||||
[position, branch.branchId]);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user