<%* const EXCLUDE = ["title", "cssclasses", "aliases", "position", "member"]; module.exports = async (params) => { const { app } = params; const file = app.workspace.getActiveFile(); if (!file) { new Notice("No active file."); return; } // Step 1: Strip the button block let content = await app.vault.read(file); content = content.replace(/\n?```button[\s\S]*?```\n?/g, ""); await app.vault.modify(file, content); await new Promise(r => setTimeout(r, 150)); const cache = app.metadataCache.getFileCache(file); const fm = cache?.frontmatter; if (!fm) { new Notice("No frontmatter found."); return; } // Step 2: Generate reference code if missing if (!fm["reference code"]) { const refCode = Math.floor(Math.random() * 9000000000000000) + 1000000000000000; await app.fileManager.processFrontMatter(file, (fmObj) => { fmObj["reference code"] = refCode; }); await new Promise(r => setTimeout(r, 300)); } // Step 3: Re-read updated frontmatter const updatedFm = app.metadataCache.getFileCache(file)?.frontmatter; if (!updatedFm) { new Notice("Could not read updated frontmatter."); return; } const folder = file.parent?.name || ""; const title = file.basename; const refCode = updatedFm["reference code"] || ""; // Step 4: Build table rows (excluding reference code from display) const EXCLUDE_FROM_TABLE = [...EXCLUDE, "reference code"]; const rows = Object.entries(updatedFm) .filter(([key]) => !EXCLUDE_FROM_TABLE.includes(key.toLowerCase())) .map(([key, value]) => { if (value === null || value === undefined || value === "") return null; let display; if (key.toLowerCase() === "source" && String(value).startsWith("http")) { display = `[Article Link](${value})`; } else if (Array.isArray(value)) { display = value.join(", "); } else { display = String(value); } return `| ${key} | ${display} |`; }) .filter(Boolean); // Step 5: Build email button const emailButton = `<div style="text-align:center;"><a href="mailto:[email protected]?subject=Revision:%20${encodeURIComponent(folder)}%2F${encodeURIComponent(title)}%20-%20${refCode}" style="border:1px solid #555; padding:4px 12px; border-radius:4px; color:#a89ee8; text-decoration:none; font-size:0.9em; background-color:#2a2a2a;">📩 Submit a Revision/Addition</a></div>`; // Step 6: Read file and locate frontmatter end content = await app.vault.read(file); const firstDash = content.indexOf("---"); const secondDash = content.indexOf("---", firstDash + 3); const fmEnd = secondDash + 3; const beforeFm = content.slice(0, fmEnd); let afterFm = content.slice(fmEnd); // Strip existing table, buttons, and stray rows afterFm = afterFm.replace(/^(\s*\|[^\n]*\n)+/m, ""); afterFm = afterFm.replace(/<div[^>]*>[\s\S]*?<a href="mailto:[^"]*"[\s\S]*?<\/a>[\s\S]*?<\/div>\n*/g, ""); afterFm = afterFm.replace(/<a href="mailto:[^"]*"[^>]*>.*?<\/a>\n*/gs, ""); afterFm = afterFm.replace(/^\s*\|\s*reference code\s*\|[^\n]*\n?/gim, ""); afterFm = afterFm.replace(/^\s*\|\s*member\s*\|[^\n]*\n?/gim, ""); const bodyContent = afterFm.trimStart(); // Step 7: Reassemble if (rows.length === 0) { const newContent = beforeFm + "\n\n" + emailButton + "\n\n" + bodyContent; await app.vault.modify(file, newContent); } else { const newTable = `| | |\n| --- | --- |\n${rows.join("\n")}`; const newContent = beforeFm + "\n\n" + newTable + "\n<br>\n" + emailButton + "\n\n" + bodyContent; await app.vault.modify(file, newContent); } new Notice("Done."); }; _%>