add "top" label to keep notes on top, allow sorting by label, #2343

This commit is contained in:
zadam 2021-11-23 23:09:29 +01:00
parent df4cf80be4
commit 211ff90ee8
4 changed files with 61 additions and 17 deletions

View File

@ -189,6 +189,7 @@ const ATTR_HELP = {
"runAtHour": "On which hour should this run. Should be used together with <code>#run=hourly</code>. Can be defined multiple times for more runs during the day.",
"disableInclusion": "scripts with this label won't be included into parent script execution.",
"sorted": "keeps child notes sorted by title alphabetically",
"top": "keep given note on top in its parent (applies only on sorted parents)",
"hidePromotedAttributes": "Hide promoted attributes on this note",
"readOnly": "editor is in read only mode. Works only for text and code notes.",
"autoReadOnlyDisabled": "text/code notes can be set automatically into read mode when they are too large. You can disable this behavior on per-note basis by adding this label to the note",
@ -208,6 +209,8 @@ const ATTR_HELP = {
"inbox": "default inbox location for new notes",
"hoistedInbox": "default inbox location for new notes when hoisted to some ancestor of this note",
"sqlConsoleHome": "default location of SQL console notes",
"bookmarked": "note with this label will appear in bookmarks",
"bookmarkFolder": "note with this label will appear in bookmarks as folder (allowing access to its children)"
},
"relation": {
"runOnNoteCreation": "executes when note is created on backend",

View File

@ -49,6 +49,8 @@ const BUILTIN_ATTRIBUTES = [
{ type: 'label', name: 'mapRootNoteId' },
{ type: 'label', name: 'bookmarked' },
{ type: 'label', name: 'bookmarkFolder' },
{ type: 'label', name: 'sorted' },
{ type: 'label', name: 'top' },
// relation names
{ type: 'relation', name: 'runOnNoteCreation', isDangerous: true },

View File

@ -39,6 +39,10 @@ eventService.subscribe(eventService.NOTE_TITLE_CHANGED, note => {
eventService.subscribe([ eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED ], ({ entityName, entity }) => {
if (entityName === 'attributes') {
runAttachedRelations(entity.getNote(), 'runOnAttributeChange', entity);
if (entity.type === 'label' && entity.name === 'sorted') {
handleSortedAttribute(entity);
}
}
else if (entityName === 'notes') {
runAttachedRelations(entity, 'runOnNoteChange', entity);
@ -83,17 +87,7 @@ eventService.subscribe(eventService.ENTITY_CREATED, ({ entityName, entity }) =>
}
}
else if (entity.type === 'label' && entity.name === 'sorted') {
treeService.sortNotesIfNeeded(entity.noteId);
if (entity.isInheritable) {
const note = becca.notes[entity.noteId];
if (note) {
for (const noteId of note.getSubtreeNoteIds()) {
treeService.sortNotesIfNeeded(noteId);
}
}
}
handleSortedAttribute(entity);
}
}
else if (entityName === 'notes') {
@ -122,6 +116,20 @@ function processInverseRelations(entityName, entity, handler) {
}
}
function handleSortedAttribute(entity) {
treeService.sortNotesIfNeeded(entity.noteId);
if (entity.isInheritable) {
const note = becca.notes[entity.noteId];
if (note) {
for (const noteId of note.getSubtreeNoteIds()) {
treeService.sortNotesIfNeeded(noteId);
}
}
}
}
eventService.subscribe(eventService.ENTITY_CHANGED, ({ entityName, entity }) => {
processInverseRelations(entityName, entity, (definition, note, targetNote) => {
// we need to make sure that also target's inverse attribute exists and if not, then create it

View File

@ -108,9 +108,9 @@ function loadSubtreeNoteIds(parentNoteId, subtreeNoteIds) {
}
}
function sortNotes(parentNoteId, sortBy = 'title', reverse = false, foldersFirst = false) {
if (!sortBy) {
sortBy = 'title';
function sortNotes(parentNoteId, customSortBy = 'title', reverse = false, foldersFirst = false) {
if (!customSortBy) {
customSortBy = 'title';
}
sql.transactional(() => {
@ -129,10 +129,41 @@ function sortNotes(parentNoteId, sortBy = 'title', reverse = false, foldersFirst
}
}
let aEl = normalize(a[sortBy]);
let bEl = normalize(b[sortBy]);
function fetchValue(note, key) {
const rawValue = ['title', 'dateCreated', 'dateModified'].includes(key)
? note[key]
: note.getLabelValue(key);
return aEl < bEl ? -1 : 1;
return normalize(rawValue);
}
function compare(a, b) {
return b === null || b === undefined || a < b ? -1 : 1;
}
const topAEl = fetchValue(a, 'top');
const topBEl = fetchValue(b, 'top');
console.log(a.title, topAEl);
console.log(b.title, topBEl);
console.log("comp", compare(topAEl, topBEl) && !reverse);
if (topAEl !== topBEl) {
// since "top" should not be reversible, we'll reverse it once more to nullify this effect
return compare(topAEl, topBEl) * (reverse ? -1 : 1);
}
const customAEl = fetchValue(a, customSortBy);
const customBEl = fetchValue(b, customSortBy);
if (customAEl !== customBEl) {
return compare(customAEl, customBEl);
}
const titleAEl = fetchValue(a, 'title');
const titleBEl = fetchValue(b, 'title');
return compare(titleAEl, titleBEl);
});
if (reverse) {