Files
trilium_share_gruvbox/blog_publish_manager.js
T
trilium-share-gruvbox aa7a2d0ab5 Add Gruvbox share theme + blog system for Trilium (anonymized)
Blog generator, publish manager, share scripts, theme CSS, highlight.js
bundles, font, favicon, templates and generated-reference outputs, plus an
English installation guide.
2026-08-28 13:36:22 +02:00

106 lines
3.9 KiB
JavaScript

const BLOG_ROOT_ID = "__BLOG_ROOT_ID__";
const UNPUBLISHED_ROOT_ID = "__UNPUBLISHED_ROOT_ID__";
const BLOG_GENERATOR_ID = "__BLOG_GENERATOR_ID__";
const entity = api.originEntity;
if (!entity) return;
function findOrCreateChild(parentId, title, iconClass) {
const parent = api.getNote(parentId);
let child = parent.getChildNotes().find(n => n.title === title);
if (!child) {
const created = api.createTextNote(parentId, title, "");
child = created.note ? created.note : created;
if (iconClass) child.setLabel("iconClass", iconClass);
child.save();
return { noteId: child.noteId, created: true };
}
if (child.hasLabel("blogCategory") && iconClass && child.getLabelValue("iconClass") !== iconClass) {
child.setLabel("iconClass", iconClass);
child.save();
}
return { noteId: child.noteId, created: false };
}
function mirrorPath(note, sourceRootId, targetRootId) {
const chain = [];
let current = note;
let guard = 0;
while (current && guard++ < 20) {
const parents = current.getParentNotes().filter(p => p.noteId === sourceRootId || p.hasAncestor(sourceRootId));
if (parents.length === 0) break;
const parent = parents[0];
if (parent.noteId === sourceRootId) break;
chain.unshift(parent);
current = parent;
}
let target = targetRootId;
const createdIds = [];
for (const folder of chain) {
const res = findOrCreateChild(target, folder.title, folder.getLabelValue("iconClass"));
if (res.created) createdIds.push(res.noteId);
target = res.noteId;
}
return { target, createdIds };
}
function blogParentsOf(note) {
return note.getParentNotes().filter(p => p.noteId === BLOG_ROOT_ID || p.hasAncestor(BLOG_ROOT_ID));
}
function runGenerator() {
const gen = api.getNote(BLOG_GENERATOR_ID);
if (gen) gen.executeScript();
}
function slugify(s) {
return String(s).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}
function ensureAlias(note) {
if (note.getLabelValue("shareAlias")) return;
const base = slugify(note.title) || "post";
let alias = base;
let i = 2;
while (api.getNotesWithLabel("shareAlias", alias).some(n => n.noteId !== note.noteId)) {
alias = base + "-" + i++;
}
note.setLabel("shareAlias", alias);
note.save();
api.log("blog_publish_manager: assigned shareAlias '" + alias + "' to '" + note.title + "'");
}
if (entity.type === "label" && entity.name === "publish") {
const note = api.getNote(entity.noteId);
if (!note) return;
const isPublished = note.getLabelValue("publish") === "true";
if (isPublished) ensureAlias(note);
const underBlog = note.hasAncestor(BLOG_ROOT_ID);
const underUnpublished = note.hasAncestor(UNPUBLISHED_ROOT_ID);
if (isPublished && underUnpublished && !underBlog) {
const res = mirrorPath(note, UNPUBLISHED_ROOT_ID, BLOG_ROOT_ID);
api.ensureNoteIsPresentInParent(note.noteId, res.target);
for (const id of res.createdIds) {
api.getNote(id).setLabel("blogCategory", "");
}
api.log("blog_publish_manager: cloned note '" + note.title + "' to blog");
runGenerator();
} else if (!isPublished && underBlog) {
if (underUnpublished) {
for (const p of blogParentsOf(note)) {
api.ensureNoteIsAbsentFromParent(note.noteId, p.noteId);
}
api.log("blog_publish_manager: removed clone of '" + note.title + "' from blog");
} else {
const res = mirrorPath(note, BLOG_ROOT_ID, UNPUBLISHED_ROOT_ID);
api.ensureNoteIsPresentInParent(note.noteId, res.target);
for (const p of blogParentsOf(note)) {
api.ensureNoteIsAbsentFromParent(note.noteId, p.noteId);
}
api.log("blog_publish_manager: moved note '" + note.title + "' back to unpublished");
}
runGenerator();
}
}