[PLUGIN] Hidden Notes #2072
Replies: 4 comments 2 replies
-
This is wonderful, thank you for the useful addition! |
Beta Was this translation helpful? Give feedback.
-
Very nice, thank you! |
Beta Was this translation helpful? Give feedback.
-
I could have done something wrong, but this doesn't seem to work anymore. I'm getting a "isHidden" functiono not defined error after running the script. |
Beta Was this translation helpful? Give feedback.
-
Hi I've just updated this for the latest version of Trillium (version It does NOT require the CSS note anymore, just a JS as described how to make above with the type I have no idea how it deals with cloned notes, I'm sure it works the same as the one above. It does append (hidden) after showing hidden notes and makes the title italic. Enjoy. // Global State
window.hiddenNotesAreVisible = true;
// Show/Hide Logic
window.showNotes = async () => {
$('li:has(> span.hidden)').show().addClass("fst-italic");
$('span.hidden').append('<span id="hidden_text_elem"> (hidden)</span>');
window.hiddenNotesAreVisible = true;
$('button.bx-show').removeClass("bx-show").addClass("bx-hide");
};
window.hideNotes = async () => {
$('li:has(> span.hidden)').hide();
$('span.hidden').find('#hidden_text_elem').remove();
window.hiddenNotesAreVisible = false;
$('button.bx-hide').removeClass("bx-hide").addClass("bx-show");
};
window.toggleNotes = async () => {
window.hiddenNotesAreVisible ? window.hideNotes() : window.showNotes();
};
// Toolbar Button
api.addButtonToToolbar({
title: 'Show hidden notes',
icon: 'show',
action: window.toggleNotes
});
// Tab Switching Logic
const tabContextProto = Object.getPrototypeOf(api.getActiveContext());
const original_setNote = tabContextProto.setNote;
tabContextProto.setNote = async function(inputNotePath, triggerSwitchEvent = true) {
const splitPath = inputNotePath.split('/');
if (!window.hiddenNotesAreVisible) {
while (splitPath.length > 1) {
const currentNote = await api.getNote(splitPath.at(-1));
if (currentNote.hasLabel('hidden')) {
splitPath.pop();
} else {
break;
}
}
}
return original_setNote.call(this, splitPath.join('/'), triggerSwitchEvent);
};
// Tree Logic
const noteTree = api.getComponentByEl(document.querySelector('.tree-wrapper'));
const noteTreeProto = Object.getPrototypeOf(noteTree);
const original_initFancyTree = noteTreeProto.initFancyTree;
noteTreeProto.initFancyTree = function() {
original_initFancyTree.call(this);
updateHiddenClass(this.tree.rootNode);
};
const original_reloadTreeFromCache = noteTreeProto.reloadTreeFromCache;
noteTreeProto.reloadTreeFromCache = async function() {
await original_reloadTreeFromCache.call(this);
updateHiddenClass(this.tree.rootNode);
setTimeout(() => {
if (window.hiddenNotesAreVisible) window.hideNotes();
}, 100);
};
const original_updateNode = noteTreeProto.updateNode;
noteTreeProto.updateNode = function(node) {
original_updateNode.call(this, node);
updateHiddenClassOnNode(node);
};
// Tree Helpers
function flattenTree(node) {
return [node, ...(node.children?.flatMap(flattenTree) || [])];
}
function getNotePath(node) {
const path = [];
while (node) {
if (node.data.noteId) path.push(node.data.noteId);
node = node.getParent();
}
return path;
}
function updateHiddenClass(tree) {
const allNodes = flattenTree(tree.children[0]);
allNodes.forEach(updateHiddenClassOnNode);
if (!window.hiddenNotesAreVisible) window.hideNotes();
}
async function updateHiddenClassOnNode(node) {
const path = getNotePath(node);
const isHidden = await Promise.any(path.map(async id => {
const note = await api.getNote(id);
return note.hasLabel('hidden');
}));
node.toggleClass('hidden', isHidden);
}
// Attribute Editor Hook
const attributeEditor = $('.attribute-list > div');
const attributeEditorProto = Object.getPrototypeOf(attributeEditor);
const original_save = attributeEditorProto.save;
attributeEditorProto.save = async function() {
await original_save.call(this);
updateHiddenClass(api.mainTreeWidget.tree.rootNode);
};
// Note List Filtering
const noteList = $('.note-list-widget');
const noteListProto = Object.getPrototypeOf(noteList);
const original_renderNoteList = noteListProto.renderNoteList;
noteListProto.renderNoteList = async function(note) {
const noteProto = Object.getPrototypeOf(note);
const original_getChildNoteIds = noteProto.getChildNoteIds;
if (window.hiddenNotesAreVisible) {
noteProto.getChildNoteIds = function() {
return this.children.filter(id => {
const childNote = this.froca.getNoteFromCache(id);
return !childNote?.hasLabel('hidden');
});
};
}
await original_renderNoteList.call(this, note);
noteProto.getChildNoteIds = original_getChildNoteIds;
};
// Final Initialization
noteTree.reloadTreeFromCache();
console.log('[HideNotes] Plugin initialized'); |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This plugin allows you to mark notes as "hidden" so you can toggle their visibility at the click of a button.
Setting up the plugin
Two notes are needed for this plugin to function:
The 1st note contains the CSS for this plugin.
Create a new note, set its type to
CSS
and add the#appCss
label. From there, insert this content:The 2nd note contains the logic for this plugin.
Create a new note, set its type to
JS Frontend
and add the#run=frontendStartup
label. From there, insert this content:Now you can either reload the app or execute the JS note.
Using the plugin
Any notes with the
#hidden
label will be marked as hidden notes, and by default these are:Note that hidden notes only hide notes directly under them in the note tree, if a note under a hidden note has a clone elsewhere that clone will still be rendered. If you want clones to be hidden too, add the
(inheritable)
modifier to the#hidden
attribute.By clicking the eye button

that appears in the sidebar, you can toggle between hiding hidden notes and showing them to allow editing of hidden notes.
Beta Was this translation helpful? Give feedback.
All reactions