From 0704a6be27d02722e664aaf03fda923c23ecac8a Mon Sep 17 00:00:00 2001 From: Ross Keenan Date: Tue, 23 Nov 2021 16:39:14 +0200 Subject: [PATCH] feat(FolderNote): :sparkles: Folder Notes! Make all files in a folder point upwards to a chosen note (fix #112) --- .vscode/settings.json | 3 +- main.js | 190 ++++++++++++++++------------- src/main.ts | 263 +++++++++++++++++++++++++---------------- src/sharedFunctions.ts | 7 +- 4 files changed, 277 insertions(+), 186 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6e0f3770..c9477030 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "LimitTrailFields", "CSV Crumbs", "nextPrev", - "DucksView" + "DucksView", + "FolderNote" ] } \ No newline at end of file diff --git a/main.js b/main.js index 70525ca8..b15a5647 100644 --- a/main.js +++ b/main.js @@ -21826,7 +21826,11 @@ function debugGroupEnd(settings, type) { * Get basename from `path` * @param {string} path */ -const getBasename = (path) => path.split("/").last(); +const getBaseFromPath = (path) => path.split("/").last(); +const getDVBasename = (file) => file.basename || file.name; +const getFolder = (file) => { var _a; +//@ts-ignore +return ((_a = file === null || file === void 0 ? void 0 : file.parent) === null || _a === void 0 ? void 0 : _a.name) || file.folder; }; const splitAndTrim = (fields) => { if (fields === "") return []; @@ -49697,7 +49701,6 @@ class BCPlugin extends obsidian.Plugin { }); CSVRows.push(rowObj); }); - console.log({ CSVRows }); return CSVRows; } addCSVCrumbs(g, CSVRows, dir, field) { @@ -49751,7 +49754,7 @@ class BCPlugin extends obsidian.Plugin { if (typeof rawValuesPreFlat === "string") { const splits = rawValuesPreFlat.match(splitLinksRegex); if (splits !== null) { - const linkNames = splits.map((link) => getBasename(link.match(dropHeaderOrAlias)[1])); + const linkNames = splits.map((link) => getBaseFromPath(link.match(dropHeaderOrAlias)[1])); parsed.push(...linkNames); } } @@ -49767,14 +49770,14 @@ class BCPlugin extends obsidian.Plugin { const rawAsString = value.toString(); const splits = rawAsString.match(splitLinksRegex); if (splits !== null) { - const strs = splits.map((link) => getBasename(link.match(dropHeaderOrAlias)[1])); + const strs = splits.map((link) => getBaseFromPath(link.match(dropHeaderOrAlias)[1])); parsed.push(...strs); } else - parsed.push(getBasename(rawAsString)); + parsed.push(getBaseFromPath(rawAsString)); } else if (value.path !== undefined) { - const basename = getBasename(value.path); + const basename = getBaseFromPath(value.path); if (basename !== undefined) parsed.push(basename); } @@ -49816,15 +49819,6 @@ class BCPlugin extends obsidian.Plugin { const { fieldDir } = getFieldInfo(userHiers, field); if (!fieldDir) return; - // const fields = getFields(userHiers); - // DIRECTIONS.forEach((dir) => { - // userHiers.forEach((hier) => { - // if (hier[dir]?.includes(field)) { - // typeDir = dir; - // return; - // } - // }); - // }); jugglLink.links.push({ dir: fieldDir, field, @@ -49844,6 +49838,82 @@ class BCPlugin extends obsidian.Plugin { debugGroupEnd(settings, "debugMode"); return filteredLinks; } + addHNsToGraph(hierarchyNotesArr, mainG) { + const { HNUpField, userHiers } = this.settings; + const upFields = getFields(userHiers, "up"); + hierarchyNotesArr.forEach((hnItem, i) => { + var _a, _b, _c; + const upField = (_a = hnItem.field) !== null && _a !== void 0 ? _a : (HNUpField || upFields[0]); + const downField = (_b = getOppFields(userHiers, upField)[0]) !== null && _b !== void 0 ? _b : `${upField}`; + if (hnItem.parentNote === null) { + const s = hnItem.currNote; + const t = (_c = hierarchyNotesArr[i + 1]) === null || _c === void 0 ? void 0 : _c.currNote; + //@ts-ignore + addNodesIfNot(mainG, [s, t], { dir: "down", field: downField }); + //@ts-ignore + addEdgeIfNot(mainG, s, t, { dir: "down", field: downField }); + } + else { + const aUp = { + dir: "up", + field: upField, + }; + //@ts-ignore + addNodesIfNot(mainG, [hnItem.currNote, hnItem.parentNote], aUp); + //@ts-ignore + addEdgeIfNot(mainG, hnItem.currNote, hnItem.parentNote, aUp); + const aDown = { + dir: "down", + field: downField, + }; + //@ts-ignore + addNodesIfNot(mainG, [hnItem.parentNote, hnItem.currNote], aDown); + //@ts-ignore + addEdgeIfNot(mainG, hnItem.parentNote, hnItem.currNote, aDown); + } + }); + } + addJugglLinksToGraph(jugglLinks, fileFrontmatterArr, mainG) { + jugglLinks.forEach((jugglLink) => { + const { basename } = jugglLink.file; + jugglLink.links.forEach((link) => { + var _a, _b; + const { dir, field, linksInLine } = link; + if (dir === "") + return; + const sourceOrder = (_b = parseInt((_a = fileFrontmatterArr.find((arr) => arr.file.basename === basename)) === null || _a === void 0 ? void 0 : _a.order)) !== null && _b !== void 0 ? _b : 9999; + this.populateMain(mainG, basename, dir, field, linksInLine, sourceOrder, fileFrontmatterArr); + }); + }); + } + addFolderNoteLinksToGraph(fileFrontmatterArr, mainG) { + const { userHiers } = this.settings; + fileFrontmatterArr.forEach((fileFront) => { + var _a; + const folderNoteFile = fileFront.file; + if (fileFront["BC-folder-note"]) { + const folderNoteBasename = getDVBasename(folderNoteFile); + const folder = getFolder(folderNoteFile); + const sources = fileFrontmatterArr + .map((ff) => ff.file) + .filter((file) => getFolder(file) === folder && file.path !== folderNoteFile.path) + .map(getDVBasename); + let field = fileFront["BC-folder-note-up"]; + const upFields = getFields(userHiers, "up"); + if (typeof field !== "string" || !upFields.includes(field)) { + field = upFields[0]; + } + const oppField = (_a = getOppFields(userHiers, field)[0]) !== null && _a !== void 0 ? _a : getFields(userHiers, "down")[0]; + sources.forEach((source) => { + var _a; + // This is getting the order of the folder note, not the source pointing up to it + const sourceOrder = (_a = parseInt(fileFront.order)) !== null && _a !== void 0 ? _a : 9999; + this.populateMain(mainG, source, "up", field, [folderNoteBasename], sourceOrder, fileFrontmatterArr); + this.populateMain(mainG, folderNoteBasename, "down", oppField, [source], sourceOrder, fileFrontmatterArr); + }); + } + }); + } async initGraphs() { const { settings, app } = this; debugGroupStart(settings, "debugMode", "Initialise Graphs"); @@ -49855,33 +49925,14 @@ class BCPlugin extends obsidian.Plugin { if (fileFrontmatterArr[0] === undefined) { return new graphology_umd_min.MultiGraph(); } - debugGroupStart(settings, "debugMode", "Hierarchy Note Adjacency List"); - const hierarchyNotesArr = []; - if (settings.hierarchyNotes[0] !== "") { - for (const note of settings.hierarchyNotes) { - const file = app.metadataCache.getFirstLinkpathDest(note, ""); - if (file) { - hierarchyNotesArr.push(...(await this.getHierarchyNoteItems(file))); - } - else { - new obsidian.Notice(`${note} is no longer in your vault. It is best to remove it in Breadcrumbs settings.`); - } - } - } - debugGroupEnd(settings, "debugMode"); const { userHiers } = settings; const mainG = new graphology_umd_min.MultiGraph(); if (userHiers.length === 0) return mainG; const useCSV = settings.CSVPaths !== ""; const CSVRows = useCSV ? await this.getCSVRows() : []; - let jugglLinks = []; - if (app.plugins.plugins.juggl !== undefined || - settings.parseJugglLinksWithoutJuggl) { - jugglLinks = await this.getJugglLinks(files); - } fileFrontmatterArr.forEach((fileFrontmatter) => { - const basename = fileFrontmatter.file.basename || fileFrontmatter.file.name; + const basename = getDVBasename(fileFrontmatter.file); iterateHiers(userHiers, (hier, dir, field) => { var _a; const values = this.parseFieldValue(fileFrontmatter[field]); @@ -49891,61 +49942,38 @@ class BCPlugin extends obsidian.Plugin { this.addCSVCrumbs(mainG, CSVRows, dir, field); }); }); - if (jugglLinks.length) { - jugglLinks.forEach((jugglLink) => { - const { basename } = jugglLink.file; - jugglLink.links.forEach((link) => { - var _a, _b; - const { dir, field, linksInLine } = link; - if (dir === "") - return; - const sourceOrder = (_b = parseInt((_a = fileFrontmatterArr.find((arr) => arr.file.basename === basename)) === null || _a === void 0 ? void 0 : _a.order)) !== null && _b !== void 0 ? _b : 9999; - this.populateMain(mainG, basename, dir, field, linksInLine, sourceOrder, fileFrontmatterArr); - }); - }); - } - if (hierarchyNotesArr.length) { - const { HNUpField } = settings; - const upFields = getFields(userHiers, "up"); - hierarchyNotesArr.forEach((hnItem, i) => { - var _a, _b; - const upField = (_a = hnItem.field) !== null && _a !== void 0 ? _a : (HNUpField || upFields[0]); - const downField = (_b = getOppFields(userHiers, upField)[0]) !== null && _b !== void 0 ? _b : `${upField}`; - if (hnItem.parentNote === null) { - const s = hnItem.currNote; - const t = hierarchyNotesArr[i + 1].currNote; - //@ts-ignore - addNodesIfNot(mainG, [s, t], { dir: "down", field: downField }); - //@ts-ignore - addEdgeIfNot(mainG, s, t, { dir: "down", field: downField }); + // SECTION Juggl Links + const jugglLinks = app.plugins.plugins.juggl || settings.parseJugglLinksWithoutJuggl + ? await this.getJugglLinks(files) + : []; + if (jugglLinks.length) + this.addJugglLinksToGraph(jugglLinks, fileFrontmatterArr, mainG); + // !SECTION Juggl Links + // SECTION Hierarchy Notes + debugGroupStart(settings, "debugMode", "Hierarchy Note Adjacency List"); + const hierarchyNotesArr = []; + if (settings.hierarchyNotes[0] !== "") { + for (const note of settings.hierarchyNotes) { + const file = app.metadataCache.getFirstLinkpathDest(note, ""); + if (file) { + hierarchyNotesArr.push(...(await this.getHierarchyNoteItems(file))); } else { - const aUp = { - dir: "up", - field: upField, - }; - //@ts-ignore - addNodesIfNot(mainG, [hnItem.currNote, hnItem.parentNote], aUp); - //@ts-ignore - addEdgeIfNot(mainG, hnItem.currNote, hnItem.parentNote, aUp); - const aDown = { - dir: "down", - field: downField, - }; - //@ts-ignore - addNodesIfNot(mainG, [hnItem.parentNote, hnItem.currNote], aDown); - //@ts-ignore - addEdgeIfNot(mainG, hnItem.parentNote, hnItem.currNote, aDown); + new obsidian.Notice(`${note} is no longer in your vault. It is best to remove it in Breadcrumbs settings.`); } - }); + } } - this.debug("graphs inited"); - this.debug({ mainG }); + if (hierarchyNotesArr.length) + this.addHNsToGraph(hierarchyNotesArr, mainG); + // !SECTION Hierarchy Notes debugGroupEnd(settings, "debugMode"); + this.addFolderNoteLinksToGraph(fileFrontmatterArr, mainG); files.forEach((file) => { const { basename } = file; addNodesIfNot(mainG, [basename]); }); + this.debug("graphs inited"); + this.debug({ mainG }); return mainG; } // !SECTION OneSource diff --git a/src/main.ts b/src/main.ts index 8456eb05..8c5385b9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -45,9 +45,11 @@ import { createOrUpdateYaml, debugGroupEnd, debugGroupStart, - getBasename, + getBaseFromPath, + getDVBasename, getFieldInfo, getFields, + getFolder, getInNeighbours, getOppFields, getRealnImplied, @@ -517,8 +519,6 @@ export default class BCPlugin extends Plugin { }); CSVRows.push(rowObj); }); - - console.log({ CSVRows }); return CSVRows; } @@ -579,7 +579,7 @@ export default class BCPlugin extends Plugin { const splits = rawValuesPreFlat.match(splitLinksRegex); if (splits !== null) { const linkNames = splits.map((link) => - getBasename(link.match(dropHeaderOrAlias)[1]) + getBaseFromPath(link.match(dropHeaderOrAlias)[1]) ); parsed.push(...linkNames); } @@ -597,12 +597,12 @@ export default class BCPlugin extends Plugin { const splits = rawAsString.match(splitLinksRegex); if (splits !== null) { const strs = splits.map((link) => - getBasename(link.match(dropHeaderOrAlias)[1]) + getBaseFromPath(link.match(dropHeaderOrAlias)[1]) ); parsed.push(...strs); - } else parsed.push(getBasename(rawAsString)); + } else parsed.push(getBaseFromPath(rawAsString)); } else if (value.path !== undefined) { - const basename = getBasename(value.path); + const basename = getBaseFromPath(value.path); if (basename !== undefined) parsed.push(basename); } }); @@ -655,16 +655,6 @@ export default class BCPlugin extends Plugin { const { fieldDir } = getFieldInfo(userHiers, field); if (!fieldDir) return; - // const fields = getFields(userHiers); - // DIRECTIONS.forEach((dir) => { - // userHiers.forEach((hier) => { - // if (hier[dir]?.includes(field)) { - // typeDir = dir; - // return; - // } - // }); - // }); - jugglLink.links.push({ dir: fieldDir, field, @@ -691,6 +681,128 @@ export default class BCPlugin extends Plugin { return filteredLinks; } + addHNsToGraph(hierarchyNotesArr: HierarchyNoteItem[], mainG: MultiGraph) { + const { HNUpField, userHiers } = this.settings; + const upFields = getFields(userHiers, "up"); + + hierarchyNotesArr.forEach((hnItem, i) => { + const upField = hnItem.field ?? (HNUpField || upFields[0]); + const downField = + getOppFields(userHiers, upField)[0] ?? `${upField}`; + + if (hnItem.parentNote === null) { + const s = hnItem.currNote; + const t = hierarchyNotesArr[i + 1]?.currNote; + + //@ts-ignore + addNodesIfNot(mainG, [s, t], { dir: "down", field: downField }); + //@ts-ignore + addEdgeIfNot(mainG, s, t, { dir: "down", field: downField }); + } else { + const aUp = { + dir: "up", + field: upField, + }; + //@ts-ignore + addNodesIfNot(mainG, [hnItem.currNote, hnItem.parentNote], aUp); + //@ts-ignore + addEdgeIfNot(mainG, hnItem.currNote, hnItem.parentNote, aUp); + + const aDown = { + dir: "down", + field: downField, + }; + //@ts-ignore + addNodesIfNot(mainG, [hnItem.parentNote, hnItem.currNote], aDown); + //@ts-ignore + addEdgeIfNot(mainG, hnItem.parentNote, hnItem.currNote, aDown); + } + }); + } + + addJugglLinksToGraph( + jugglLinks: JugglLink[], + fileFrontmatterArr: dvFrontmatterCache[], + mainG: MultiGraph + ) { + jugglLinks.forEach((jugglLink) => { + const { basename } = jugglLink.file; + jugglLink.links.forEach((link) => { + const { dir, field, linksInLine } = link; + if (dir === "") return; + const sourceOrder = + parseInt( + fileFrontmatterArr.find((arr) => arr.file.basename === basename) + ?.order + ) ?? 9999; + this.populateMain( + mainG, + basename, + dir, + field, + linksInLine, + sourceOrder, + fileFrontmatterArr + ); + }); + }); + } + + addFolderNoteLinksToGraph( + fileFrontmatterArr: dvFrontmatterCache[], + mainG: MultiGraph + ) { + const { userHiers } = this.settings; + fileFrontmatterArr.forEach((fileFront) => { + const folderNoteFile = fileFront.file; + if (fileFront["BC-folder-note"]) { + const folderNoteBasename = getDVBasename(folderNoteFile); + const folder = getFolder(folderNoteFile); + + const sources = fileFrontmatterArr + .map((ff) => ff.file) + .filter( + (file) => + getFolder(file) === folder && file.path !== folderNoteFile.path + ) + .map(getDVBasename); + + let field = fileFront["BC-folder-note-up"]; + const upFields = getFields(userHiers, "up"); + if (typeof field !== "string" || !upFields.includes(field)) { + field = upFields[0]; + } + + const oppField = + getOppFields(userHiers, field as string)[0] ?? + getFields(userHiers, "down")[0]; + + sources.forEach((source) => { + // This is getting the order of the folder note, not the source pointing up to it + const sourceOrder = parseInt(fileFront.order) ?? 9999; + this.populateMain( + mainG, + source, + "up", + field as string, + [folderNoteBasename], + sourceOrder, + fileFrontmatterArr + ); + this.populateMain( + mainG, + folderNoteBasename, + "down", + oppField, + [source], + sourceOrder, + fileFrontmatterArr + ); + }); + } + }); + } + async initGraphs(): Promise { const { settings, app } = this; debugGroupStart(settings, "debugMode", "Initialise Graphs"); @@ -705,23 +817,6 @@ export default class BCPlugin extends Plugin { return new MultiGraph(); } - debugGroupStart(settings, "debugMode", "Hierarchy Note Adjacency List"); - - const hierarchyNotesArr: HierarchyNoteItem[] = []; - if (settings.hierarchyNotes[0] !== "") { - for (const note of settings.hierarchyNotes) { - const file = app.metadataCache.getFirstLinkpathDest(note, ""); - if (file) { - hierarchyNotesArr.push(...(await this.getHierarchyNoteItems(file))); - } else { - new Notice( - `${note} is no longer in your vault. It is best to remove it in Breadcrumbs settings.` - ); - } - } - } - debugGroupEnd(settings, "debugMode"); - const { userHiers } = settings; const mainG = new MultiGraph(); if (userHiers.length === 0) return mainG; @@ -729,17 +824,8 @@ export default class BCPlugin extends Plugin { const useCSV = settings.CSVPaths !== ""; const CSVRows = useCSV ? await this.getCSVRows() : []; - let jugglLinks: JugglLink[] = []; - if ( - app.plugins.plugins.juggl !== undefined || - settings.parseJugglLinksWithoutJuggl - ) { - jugglLinks = await this.getJugglLinks(files); - } - fileFrontmatterArr.forEach((fileFrontmatter) => { - const basename = - fileFrontmatter.file.basename || fileFrontmatter.file.name; + const basename = getDVBasename(fileFrontmatter.file); iterateHiers(userHiers, (hier, dir, field) => { const values = this.parseFieldValue(fileFrontmatter[field]); const sourceOrder = parseInt(fileFrontmatter.order) ?? 9999; @@ -756,76 +842,47 @@ export default class BCPlugin extends Plugin { }); }); - if (jugglLinks.length) { - jugglLinks.forEach((jugglLink) => { - const { basename } = jugglLink.file; - jugglLink.links.forEach((link) => { - const { dir, field, linksInLine } = link; - if (dir === "") return; - const sourceOrder = - parseInt( - fileFrontmatterArr.find((arr) => arr.file.basename === basename) - ?.order - ) ?? 9999; - this.populateMain( - mainG, - basename, - dir, - field, - linksInLine, - sourceOrder, - fileFrontmatterArr - ); - }); - }); - } + // SECTION Juggl Links + const jugglLinks = + app.plugins.plugins.juggl || settings.parseJugglLinksWithoutJuggl + ? await this.getJugglLinks(files) + : []; + + if (jugglLinks.length) + this.addJugglLinksToGraph(jugglLinks, fileFrontmatterArr, mainG); - if (hierarchyNotesArr.length) { - const { HNUpField } = settings; - const upFields = getFields(userHiers, "up"); - - hierarchyNotesArr.forEach((hnItem, i) => { - const upField = hnItem.field ?? (HNUpField || upFields[0]); - const downField = - getOppFields(userHiers, upField)[0] ?? `${upField}`; - - if (hnItem.parentNote === null) { - const s = hnItem.currNote; - const t = hierarchyNotesArr[i + 1].currNote; - //@ts-ignore - addNodesIfNot(mainG, [s, t], { dir: "down", field: downField }); - //@ts-ignore - addEdgeIfNot(mainG, s, t, { dir: "down", field: downField }); + // !SECTION Juggl Links + // SECTION Hierarchy Notes + debugGroupStart(settings, "debugMode", "Hierarchy Note Adjacency List"); + + const hierarchyNotesArr: HierarchyNoteItem[] = []; + if (settings.hierarchyNotes[0] !== "") { + for (const note of settings.hierarchyNotes) { + const file = app.metadataCache.getFirstLinkpathDest(note, ""); + if (file) { + hierarchyNotesArr.push(...(await this.getHierarchyNoteItems(file))); } else { - const aUp = { - dir: "up", - field: upField, - }; - //@ts-ignore - addNodesIfNot(mainG, [hnItem.currNote, hnItem.parentNote], aUp); - //@ts-ignore - addEdgeIfNot(mainG, hnItem.currNote, hnItem.parentNote, aUp); - - const aDown = { - dir: "down", - field: downField, - }; - //@ts-ignore - addNodesIfNot(mainG, [hnItem.parentNote, hnItem.currNote], aDown); - //@ts-ignore - addEdgeIfNot(mainG, hnItem.parentNote, hnItem.currNote, aDown); + new Notice( + `${note} is no longer in your vault. It is best to remove it in Breadcrumbs settings.` + ); } - }); + } } - this.debug("graphs inited"); - this.debug({ mainG }); + if (hierarchyNotesArr.length) this.addHNsToGraph(hierarchyNotesArr, mainG); + + // !SECTION Hierarchy Notes debugGroupEnd(settings, "debugMode"); + + this.addFolderNoteLinksToGraph(fileFrontmatterArr, mainG); + files.forEach((file) => { const { basename } = file; addNodesIfNot(mainG, [basename]); }); + this.debug("graphs inited"); + this.debug({ mainG }); return mainG; } diff --git a/src/sharedFunctions.ts b/src/sharedFunctions.ts index cb44eb50..2ae590bf 100644 --- a/src/sharedFunctions.ts +++ b/src/sharedFunctions.ts @@ -72,7 +72,12 @@ export function splitAndDrop(str: string): string[] { * Get basename from `path` * @param {string} path */ -export const getBasename = (path: string) => path.split("/").last(); +export const getBaseFromPath = (path: string) => path.split("/").last(); + +export const getDVBasename = (file: TFile) => file.basename || file.name; +export const getFolder = (file: TFile): string => + //@ts-ignore + file?.parent?.name || file.folder; export const splitAndTrim = (fields: string): string[] => { if (fields === "") return [];