diff --git a/README.md b/README.md index 66f10e5..0f22da1 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,28 @@ Waypoint is an Obsidian plugin that automatically generates tables of contents/M Note that since waypoints can only be generated in folder notes, **it is highly recommended that you install a plugin like [Folder Note](https://github.com/xpgo/obsidian-folder-note-plugin)** to ensure that folder notes don't get lost after folder renames and other actions that change the file tree. If a folder note containing a waypoint is renamed to something other than the folder's name, the waypoint will no longer be updated. +### Ordering Notes on Waypoint + +By default, notes in Waypoint are sorted alphabetically. However, you can organize your notes in a specific order by setting up their Waypoint priorities. To do this, you would add an entry in your [note metadata](https://help.obsidian.md/Editing+and+formatting/Metadata) with a numeric value, such as: + +```markdown +--- +waypointPriority: 0 +--- + +# My note + +... + +``` + +Waypoint will then sort the notes based on the numeric value assigned to `waypointPriority`. Smaller values correspond to higher priority, so a note with `waypointPriority: 0` will appear above a note with `waypointPriority: 1`. If two notes have the same priority, they will be sorted alphabetically. + +In case a note does not have a `waypointPriority` defined, it will fall back to the default alphabetical sorting strategy. + +The `waypointPriority` key can be customized to a different key label in the Waypoint settings. This functionality works for both regulat notes and folder notes. + + ## Current Limitations - **Waypoints can only be created within a folder note** diff --git a/main.ts b/main.ts index def93e6..3fb2335 100644 --- a/main.ts +++ b/main.ts @@ -13,7 +13,8 @@ interface WaypointSettings { debugLogging: boolean, useWikiLinks: boolean, showEnclosingNote: boolean, - folderNoteType: string + folderNoteType: string, + waypointPriorityKey: string } const DEFAULT_SETTINGS: WaypointSettings = { @@ -24,7 +25,9 @@ const DEFAULT_SETTINGS: WaypointSettings = { debugLogging: false, useWikiLinks: true, showEnclosingNote: false, - folderNoteType: FolderNoteType.InsideFolder + folderNoteType: FolderNoteType.InsideFolder, + waypointPriorityKey: "waypointPriority" + } export default class Waypoint extends Plugin { @@ -60,7 +63,12 @@ export default class Waypoint extends Plugin { } this.scheduleUpdate(); })); - this.registerEvent(this.app.vault.on("modify", this.detectWaypointFlag)); + this.registerEvent(this.app.vault.on("modify", (file) => { + this.log("modify " + file.name); + this.foldersWithChanges.add(file.parent); + this.scheduleUpdate(); + this.detectWaypointFlag(file as TFile) + })); }); // This adds a settings tab so the user can configure various aspects of the plugin @@ -84,8 +92,8 @@ export default class Waypoint extends Plugin { if (this.isFolderNote(file)) { this.log("Found waypoint flag in folder note!"); await this.updateWaypoint(file); - await this.updateParentWaypoint(file.parent, this.settings.folderNoteType === FolderNoteType.OutsideFolder); - return; + await this.updateAncestorWaypoints(file.parent, this.settings.folderNoteType === FolderNoteType.OutsideFolder); + return; } else if (file.parent.isRoot()) { this.log("Found waypoint flag in root folder."); this.printWaypointError(file, `%% Error: Cannot create a waypoint in the root folder of your vault. For more information, check the instructions [here](https://github.com/IdreesInc/Waypoint) %%`); @@ -172,8 +180,15 @@ export default class Waypoint extends Plugin { return; } this.log("Waypoint found at " + waypointStart + " to " + waypointEnd); - lines.splice(waypointStart, waypointEnd !== -1 ? waypointEnd - waypointStart + 1 : 1, waypoint); - await this.app.vault.modify(file, lines.join("\n")); + + // Get the current waypoint block from lines and join it to form a string + let currentWaypoint = waypointEnd !== -1 ? lines.slice(waypointStart, waypointEnd + 1).join("\n") : lines[waypointStart]; + // Only splice and modify if waypoint differs from the current block + if (currentWaypoint !== waypoint) { + this.log("Waypoint content changed, updating") + lines.splice(waypointStart, waypointEnd !== -1 ? waypointEnd - waypointStart + 1 : 1, waypoint); + await this.app.vault.modify(file, lines.join("\n")); + } } /** @@ -187,7 +202,6 @@ export default class Waypoint extends Plugin { async getFileTreeRepresentation(rootNode: TFolder, node: TAbstractFile, indentLevel: number, topLevel = false): Promise|null { const bullet = " ".repeat(indentLevel) + "-"; if (node instanceof TFile) { - console.log(node) // Print the file name if (node.extension == "md") { if (this.settings.useWikiLinks) { @@ -237,9 +251,7 @@ export default class Waypoint extends Plugin { if (node.children && node.children.length > 0) { // Print the files and nested folders within the folder let children = node.children; - children = children.sort((a, b) => { - return a.name.localeCompare(b.name, undefined, {numeric: true, sensitivity: 'base'}); - }); + children = children.sort(this.sortWithPriority); if (!this.settings.showFolderNotes) { if (this.settings.folderNoteType === FolderNoteType.InsideFolder) { children = children.filter(child => this.settings.showFolderNotes || child.name !== node.name + ".md"); @@ -288,7 +300,7 @@ export default class Waypoint extends Plugin { this.log("Updating changed folders..."); this.foldersWithChanges.forEach((folder) => { this.log("Updating " + folder.path); - this.updateParentWaypoint(folder, true); + this.updateAncestorWaypoints(folder, true); }); this.foldersWithChanges.clear(); } @@ -303,26 +315,28 @@ export default class Waypoint extends Plugin { ); /** - * Update the ancestor waypoint (if any) of the given file/folder. + * Update all ancestor waypoints (if any) of the given file/folder. * @param node The node to start the search from * @param includeCurrentNode Whether to include the given folder in the search */ - updateParentWaypoint = async (node: TAbstractFile, includeCurrentNode: boolean) => { - const parentWaypoint = await this.locateParentWaypoint(node, includeCurrentNode); - if (parentWaypoint !== null) { - this.updateWaypoint(parentWaypoint); + updateAncestorWaypoints = async (node: TAbstractFile, includeCurrentNode: boolean) => { + const ancestorWaypoints = await this.locateAncestorWaypoints(node, includeCurrentNode); + for (let waypoint of ancestorWaypoints) { + this.updateWaypoint(waypoint); } } /** - * Locate the ancestor waypoint (if any) of the given file/folder. + * Locate all ancestor waypoints (if any) of the given file/folder. * @param node The node to start the search from * @param includeCurrentNode Whether to include the given folder in the search - * @returns The ancestor waypoint, or null if none was found + * @returns The list of ancestor waypoints, or an empty list if none were found */ - async locateParentWaypoint(node: TAbstractFile, includeCurrentNode: boolean): Promise { - this.log("Locating parent waypoint of " + node.name); + async locateAncestorWaypoints(node: TAbstractFile, includeCurrentNode: boolean): Promise { + this.log("Locating all ancestor waypoints of " + node.name); let folder = includeCurrentNode ? node : node.parent; + let ancestorWaypoints = []; + while (folder) { let folderNote; if (this.settings.folderNoteType === FolderNoteType.InsideFolder) { @@ -336,14 +350,14 @@ export default class Waypoint extends Plugin { this.log("Found folder note: " + folderNote.path); const text = await this.app.vault.cachedRead(folderNote); if (text.includes(Waypoint.BEGIN_WAYPOINT) || text.includes(this.settings.waypointFlag)) { - this.log("Found parent waypoint!"); - return folderNote; + this.log("Found ancestor waypoint!"); + ancestorWaypoints.push(folderNote); } } folder = folder.parent; } - this.log("No parent waypoint found."); - return null; + this.log("Found " + ancestorWaypoints.length + " ancestor waypoints."); + return ancestorWaypoints; } /** @@ -360,9 +374,9 @@ export default class Waypoint extends Plugin { } } - log(message: string) { + log(message?: any) { if (this.settings.debugLogging) { - console.log(message); + console.log(message); } } @@ -373,6 +387,51 @@ export default class Waypoint extends Plugin { async saveSettings() { await this.saveData(this.settings); } + + getWaypointPriority = (file: TAbstractFile): number | null => { + if (file instanceof TFile) { + let fileCache = this.app.metadataCache.getFileCache(file as TFile) + if (fileCache && fileCache.frontmatter && typeof fileCache.frontmatter[this.settings.waypointPriorityKey] === 'number') { + return fileCache.frontmatter[this.settings.waypointPriorityKey]; + } else { + return null; + } + } else if (file instanceof TFolder) { + if (this.settings.folderNoteType === FolderNoteType.InsideFolder) { + // If file is a folder and folder note is an inside note, attempt to find a child note with the same name. + let foldernote: TAbstractFile | null = file.children.find(child => child instanceof TFile && child.basename === file.name); + return foldernote ? this.getWaypointPriority(foldernote) : null + } else if (this.settings.folderNoteType === FolderNoteType.OutsideFolder) { + // If file is a folder and folder note is an outside note, attempt to find a sibling note with the same name. + if (!file.isRoot()) { + let foldernote: TAbstractFile | null = file.parent.children.find(child => child instanceof TFile && child.basename === file.name); + return foldernote ? this.getWaypointPriority(foldernote) : null; + } else { + return null; // Handle case when the file is the root folder. + } + } + return null; + } + } + + sortWithPriority = (a: TAbstractFile, b: TAbstractFile): number => { + let aPriority = this.getWaypointPriority(a) + let bPriority = this.getWaypointPriority(b) + if (aPriority !== null && bPriority !== null) { + // If both have waypointPriority, the one with a lower priority number should come first. + return aPriority - bPriority + } else if (aPriority !== null) { + // If only `a` has waypointPriority, `a` should come first. + return -1 + } else if (bPriority !== null) { + // If only `b` has waypointPriority, `b` should come first. + return 1 + } else { + // If neither has priority, sort alphabetically. + return a.name.localeCompare(b.name, undefined, {numeric: true, sensitivity: 'base'}); + } + } + } class WaypointSettingsTab extends PluginSettingTab { @@ -465,6 +524,17 @@ class WaypointSettingsTab extends PluginSettingTab { await this.plugin.saveSettings(); }) ); + new Setting(containerEl) + .setName("Frontmatter key for note priority") + .setDesc("The frontmatter key to set the note order piority when listed in a Waypoint.") + .addText(text => text + .setPlaceholder(DEFAULT_SETTINGS.waypointPriorityKey) + .setValue(this.plugin.settings.waypointPriorityKey) + .onChange(async (value) => { + this.plugin.settings.waypointPriorityKey = value; + await this.plugin.saveSettings() + }) + ); const postscriptElement = containerEl.createEl("div", { cls: "setting-item", }); diff --git a/manifest.json b/manifest.json index bb92187..6ba8d10 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "waypoint", "name": "Waypoint", - "version": "1.4.0", + "version": "1.5.0", "minAppVersion": "0.12.0", "description": "Easily generate dynamic content maps in your folder notes. Enables folders to show up in the graph view and removes the need for messy tags!", "author": "Idrees Hassan", diff --git a/package-lock.json b/package-lock.json index 9a588c8..4eaf7ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "waypoint", - "version": "1.3.0", + "version": "1.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "waypoint", - "version": "1.3.0", + "version": "1.4.0", "license": "MIT", "devDependencies": { "@types/codemirror": "^5.60.5", @@ -1832,9 +1832,9 @@ } }, "node_modules/style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.3.tgz", + "integrity": "sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==", "dev": true }, "node_modules/supports-color": { @@ -1932,9 +1932,9 @@ "peer": true }, "node_modules/w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.7.tgz", + "integrity": "sha512-XB8aa62d4rrVfoZYQaYNy3fy+z4nrfy2ooea3/0BnBzXW0tSdZ+lRgjzBZhk0La0H6h8fVyYCxx/qkQcAIuvfg==", "dev": true }, "node_modules/which": { @@ -3276,9 +3276,9 @@ "peer": true }, "style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.3.tgz", + "integrity": "sha512-78Jv8kYJdjbvRwwijtCevYADfsI0lGzYJe4mMFdceO8l75DFFDoqBhR1jVDicDRRaX4//g1u9wKeo+ztc2h1Rw==", "dev": true }, "supports-color": { @@ -3354,9 +3354,9 @@ "peer": true }, "w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.7.tgz", + "integrity": "sha512-XB8aa62d4rrVfoZYQaYNy3fy+z4nrfy2ooea3/0BnBzXW0tSdZ+lRgjzBZhk0La0H6h8fVyYCxx/qkQcAIuvfg==", "dev": true }, "which": { diff --git a/package.json b/package.json index 67315e9..8f6da2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "waypoint", - "version": "1.4.0", + "version": "1.5.0", "description": "Easily generate dynamic content maps in your folder notes. Enables folders to show up in the graph view and removes the need for messy tags!", "main": "main.js", "scripts": { diff --git a/versions.json b/versions.json index 68be0cc..017643b 100644 --- a/versions.json +++ b/versions.json @@ -3,5 +3,6 @@ "1.1.0": "0.12.0", "1.2.0": "0.12.0", "1.3.0": "0.12.0", - "1.4.0": "0.12.0" + "1.4.0": "0.12.0", + "1.5.0": "0.12.0" } \ No newline at end of file