sqeptyk

task-trigger-listener

Jun 9th, 2026
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.33 KB | Source Code | 0 0
  1. <%*
  2. // ============================================================
  3. // TASK COMPLETION TRIGGER — Listener
  4. // by sqeptyk
  5. // ============================================================
  6. //
  7. // SETUP:
  8. // 1. Place this file anywhere in your vault.
  9. // 2. In Templater settings, add this file to "Startup Templates".
  10. // 3. Edit WATCH_FOLDER to the folder containing your task notes.
  11. // 4. Edit TASK_TAG_MAP to map your tags to your templates.
  12. //
  13. // TAG FORMAT: Tasks must use #yourtag somewhere in the task line.
  14. // Example: - [ ] Take Loki for a walk #mornwalk
  15. //
  16. // TEMPLATE PATH: Path relative to vault root, no .md extension.
  17. // Example: "Templates/MyTemplate"
  18. //
  19. // To add new tag → template mappings without editing this file,
  20. // use the companion add-task-trigger.md template.
  21. // ============================================================
  22. // -- CONFIGURATION -------------------------------------------
  23. // Folder to watch for task completions (vault-root relative)
  24. const WATCH_FOLDER = "TASKS";
  25. // Map of tags to templates
  26. // Add or remove entries as needed
  27. const TASK_TAG_MAP = {
  28. // "#yourtag": { template: "Templates/YourTemplate" },
  29. // "#anothertag": { template: "Templates/AnotherTemplate" },
  30. };
  31. // ------------------------------------------------------------
  32. const fileCache = new Map();
  33. const watchPrefix = WATCH_FOLDER + "/";
  34. const plugin = tp.app.plugins.getPlugin("templater-obsidian");
  35. function getCompletedTag(oldContent, newContent) {
  36. const oldSet = new Set(oldContent.split("\n"));
  37. const newLines = newContent.split("\n");
  38. const tags = Object.keys(TASK_TAG_MAP);
  39. const pattern = new RegExp("^- \[x\]");
  40. for (let i = 0; i < newLines.length; i++) {
  41. const line = newLines[i];
  42. if (pattern.test(line) && !oldSet.has(line)) {
  43. for (let j = 0; j < tags.length; j++) {
  44. if (line.indexOf(tags[j]) !== -1) return tags[j];
  45. }
  46. }
  47. }
  48. return null;
  49. }
  50. let processingTask = false;
  51. (async function init() {
  52. const allFiles = tp.app.vault.getFiles();
  53. for (let i = 0; i < allFiles.length; i++) {
  54. if (allFiles[i].path.indexOf(watchPrefix) === 0) {
  55. const c = await tp.app.vault.read(allFiles[i]);
  56. fileCache.set(allFiles[i].path, c);
  57. }
  58. }
  59. plugin.registerEvent(
  60. tp.app.vault.on("modify", async function(file) {
  61. if (file.path.indexOf(watchPrefix) !== 0) return;
  62. if (processingTask) return;
  63.  
  64. const newContent = await tp.app.vault.read(file);
  65. const oldContent = fileCache.get(file.path) || "";
  66. fileCache.set(file.path, newContent);
  67.  
  68. const tag = getCompletedTag(oldContent, newContent);
  69. if (!tag) return;
  70.  
  71. const config = TASK_TAG_MAP[tag];
  72. processingTask = true;
  73.  
  74. try {
  75. const templateFile = tp.app.vault.getAbstractFileByPath(config.template + ".md");
  76. if (!templateFile) {
  77. new Notice("Task Trigger: Template not found: " + config.template);
  78. return;
  79. }
  80. await plugin.templater.create_new_note_from_template(templateFile, undefined, undefined, false);
  81. } catch (e) {
  82. console.error("Task Trigger error:", e);
  83. new Notice("Task Trigger: Failed - check console.");
  84. } finally {
  85. processingTask = false;
  86. }
  87. })
  88. );
  89. })();
  90. %>
Tags: Obsidian
Advertisement
Add Comment
Please, Sign In to add comment