From 05f8e549e68d5aa98341c75a3996015a15e82ca9 Mon Sep 17 00:00:00 2001 From: Ross Keenan Date: Tue, 23 Nov 2021 10:55:50 +0200 Subject: [PATCH] feat(Path View): :sparkles: Option to show Trail View in Edit and Live Preview mode! Option to show Trail View in Edit and Live Preview mode! (fix #157, #19) --- main.js | 98 +++++++++++++++++++++++-------- src/BreadcrumbsSettingTab.ts | 15 +++++ src/constants.ts | 1 + src/interfaces.ts | 1 + src/main.ts | 108 ++++++++++++++++++++++++++--------- styles.css | 2 +- 6 files changed, 174 insertions(+), 51 deletions(-) diff --git a/main.js b/main.js index 9c7ff884..58438531 100644 --- a/main.js +++ b/main.js @@ -24812,6 +24812,7 @@ const DEFAULT_SETTINGS = { showRelationType: true, rlLeaf: true, showBCs: true, + showBCsInEditLPMode: false, showTrail: true, showGrid: true, showPrevNext: true, @@ -25893,6 +25894,16 @@ class BCSettingTab extends obsidian.PluginSettingTab { await plugin.saveSettings(); await plugin.drawTrail(); })); + new obsidian.Setting(trailDetails) + .setName("Show Breadcrumbs in Edit/Live-Preview Mode") + .setDesc("It always shows in preview mode, but should it also show in the other two?\n\nKeep in mind that there is currently a limitation where the Breadcrumbs view will be stuck to the top of the note in edit/LP mode, even if you scroll down.") + .addToggle((toggle) => toggle + .setValue(settings.showBCsInEditLPMode) + .onChange(async (value) => { + settings.showBCsInEditLPMode = value; + await plugin.saveSettings(); + await plugin.drawTrail(); + })); const limitTrailFieldsDiv = trailDetails.createDiv({ cls: "limit-ML-fields", }); @@ -49313,6 +49324,7 @@ class BCPlugin extends obsidian.Plugin { super(...arguments); this.visited = []; this.activeLeafChange = undefined; + this.layoutChange = undefined; this.statusBatItemEl = undefined; this.initEverything = async () => { const { settings } = this; @@ -49323,7 +49335,8 @@ class BCPlugin extends obsidian.Plugin { } if (settings.showBCs) await this.drawTrail(); - this.registerActiveLeafEvent(); + this.registerActiveLeafChangeEvent(); + this.registerLayoutChangeEvent(); }; this.writeBCToFile = async (file) => { var _a; @@ -49356,7 +49369,9 @@ class BCPlugin extends obsidian.Plugin { async refreshIndex() { var _a; if (!this.activeLeafChange) - this.registerActiveLeafEvent(); + this.registerActiveLeafChangeEvent(); + if (!this.layoutChange) + this.registerLayoutChangeEvent(); this.mainG = await this.initGraphs(); for (const view of VIEWS) await ((_a = this.getActiveTYPEView(view.type)) === null || _a === void 0 ? void 0 : _a.draw()); @@ -49364,7 +49379,7 @@ class BCPlugin extends obsidian.Plugin { await this.drawTrail(); new obsidian.Notice("Index refreshed"); } - registerActiveLeafEvent() { + registerActiveLeafChangeEvent() { this.activeLeafChange = this.app.workspace.on("active-leaf-change", async () => { if (this.settings.refreshOnNoteChange) { await this.refreshIndex(); @@ -49379,6 +49394,13 @@ class BCPlugin extends obsidian.Plugin { }); this.registerEvent(this.activeLeafChange); } + registerLayoutChangeEvent() { + this.layoutChange = this.app.workspace.on("layout-change", async () => { + if (this.settings.showBCs) + await this.drawTrail(); + }); + this.registerEvent(this.layoutChange); + } async onload() { console.log("loading breadcrumbs plugin"); await this.loadSettings(); @@ -50006,7 +50028,7 @@ class BCPlugin extends obsidian.Plugin { const { node, path } = queue.shift(); const extPath = [node, ...path]; const succs = g.hasNode(node) - ? g.filterOutNeighbors(node, (n, a) => !path.includes(n)) + ? g.filterOutNeighbors(node, (n) => !path.includes(n)) : []; for (const node of succs) { queue.push({ node, path: extPath }); @@ -50035,7 +50057,6 @@ class BCPlugin extends obsidian.Plugin { return null; const { indexNotes } = this.settings; let allTrails = this.bfsAllPaths(g, basename); - console.log({ allTrails }); // No index note chosen if (indexNotes[0] !== "" && allTrails[0].length > 0) { allTrails = allTrails.filter((trail) => indexNotes.includes(trail[0])); @@ -50063,31 +50084,45 @@ class BCPlugin extends obsidian.Plugin { return getSubInDirs(closed, "up"); } async drawTrail() { - var _a, _b, _c, _d; + var _a, _b; const { settings } = this; + const { showBCs, hideTrailField, noPathMessage, respectReadableLineLength, showTrail, showGrid, showPrevNext, } = settings; debugGroupStart(settings, "debugMode", "Draw Trail"); const activeMDView = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView); - if (!settings.showBCs || !activeMDView) { + if (!showBCs || !activeMDView) { debugGroupEnd(settings, "debugMode"); return; } - const currFile = activeMDView.file; - const currMetadata = this.app.metadataCache.getFileCache(currFile); - const previewView = activeMDView.contentEl.querySelector(".markdown-preview-view"); - (_a = previewView.querySelector("div.BC-trail")) === null || _a === void 0 ? void 0 : _a.remove(); - if ((_b = currMetadata.frontmatter) === null || _b === void 0 ? void 0 : _b.hasOwnProperty(settings.hideTrailField)) { + const mode = activeMDView.getMode(); + if ((mode === "source" || mode === "live") && + !settings.showBCsInEditLPMode) { debugGroupEnd(settings, "debugMode"); return; } - const frontm = (_d = (_c = this.app.metadataCache.getFileCache(currFile)) === null || _c === void 0 ? void 0 : _c.frontmatter) !== null && _d !== void 0 ? _d : {}; - if (frontm["kanban-plugin"]) { + const { file } = activeMDView; + const { frontmatter } = (_a = this.app.metadataCache.getFileCache(file)) !== null && _a !== void 0 ? _a : {}; + if ((frontmatter === null || frontmatter === void 0 ? void 0 : frontmatter[hideTrailField]) || (frontmatter === null || frontmatter === void 0 ? void 0 : frontmatter["kanban-plugin"])) { debugGroupEnd(settings, "debugMode"); return; } + let view; + switch (mode) { + case "source": + view = activeMDView.contentEl.querySelector("div.markdown-source-view"); + break; + case "preview": + view = activeMDView.contentEl.querySelector("div.markdown-preview-view[tabindex='-1']"); + break; + case "live": + view = activeMDView.contentEl.querySelector("div.markdown-source-view.is-live-preview"); + break; + } + (_b = activeMDView.containerEl + .querySelectorAll(".BC-trail")) === null || _b === void 0 ? void 0 : _b.forEach((trail) => trail.remove()); const closedUp = this.getLimitedTrailSub(); - const sortedTrails = this.getBreadcrumbs(closedUp, currFile); + const sortedTrails = this.getBreadcrumbs(closedUp, file); this.debug({ sortedTrails }); - const { basename } = currFile; + const { basename } = file; const { next: { reals: rNext, implieds: iNext }, prev: { reals: rPrev, implieds: iPrev }, } = getRealnImplied(this, basename, "next"); // Remove duplicate implied const next = [...rNext]; @@ -50103,37 +50138,52 @@ class BCPlugin extends obsidian.Plugin { } }); const noItems = sortedTrails.length === 0 && next.length === 0 && prev.length === 0; - if (noItems && settings.noPathMessage === "") { + if (noItems && noPathMessage === "") { debugGroupEnd(settings, "debugMode"); return; } + const max_width = getComputedStyle(document.querySelector(".markdown-preview-view.is-readable-line-width .markdown-preview-sizer")).getPropertyValue("max-width"); const trailDiv = createDiv({ - cls: `BC-trail ${settings.respectReadableLineLength + cls: `BC-trail ${respectReadableLineLength ? "is-readable-line-width markdown-preview-sizer markdown-preview-section" : ""}`, + attr: { + style: (mode !== "preview" ? `max-width: ${max_width};` : "") + + "margin: 0 auto", + }, }); - this.visited.push([currFile.path, trailDiv]); - previewView.querySelector(".markdown-preview-sizer").before(trailDiv); + this.visited.push([file.path, trailDiv]); + if (mode === "preview") { + view.querySelector("div.markdown-preview-sizer").before(trailDiv); + } + else if (mode === "live") { + const editorDiv = view.querySelector("div.cm-editor"); + editorDiv.before(trailDiv); + } + else { + const editorDiv = view.querySelector("div.CodeMirror-sizer"); + editorDiv.before(trailDiv); + } trailDiv.empty(); if (noItems) { - trailDiv.innerText = settings.noPathMessage; + trailDiv.innerText = noPathMessage; debugGroupEnd(settings, "debugMode"); return; } const props = { sortedTrails, app: this.app, plugin: this }; - if (settings.showTrail && sortedTrails.length) { + if (showTrail && sortedTrails.length) { new TrailPath({ target: trailDiv, props, }); } - if (settings.showGrid && sortedTrails.length) { + if (showGrid && sortedTrails.length) { new TrailGrid({ target: trailDiv, props, }); } - if (settings.showPrevNext && (next.length || prev.length)) { + if (showPrevNext && (next.length || prev.length)) { new NextPrev({ target: trailDiv, props: { app: this.app, plugin: this, next, prev }, diff --git a/src/BreadcrumbsSettingTab.ts b/src/BreadcrumbsSettingTab.ts index dbe03dc0..04b4ec8d 100644 --- a/src/BreadcrumbsSettingTab.ts +++ b/src/BreadcrumbsSettingTab.ts @@ -361,6 +361,21 @@ export class BCSettingTab extends PluginSettingTab { }) ); + new Setting(trailDetails) + .setName("Show Breadcrumbs in Edit/Live-Preview Mode") + .setDesc( + "It always shows in preview mode, but should it also show in the other two?\n\nKeep in mind that there is currently a limitation where the Breadcrumbs view will be stuck to the top of the note in edit/LP mode, even if you scroll down." + ) + .addToggle((toggle) => + toggle + .setValue(settings.showBCsInEditLPMode) + .onChange(async (value) => { + settings.showBCsInEditLPMode = value; + await plugin.saveSettings(); + await plugin.drawTrail(); + }) + ); + const limitTrailFieldsDiv = trailDetails.createDiv({ cls: "limit-ML-fields", }); diff --git a/src/constants.ts b/src/constants.ts index 976d2b0d..42834233 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -107,6 +107,7 @@ export const DEFAULT_SETTINGS: BCSettings = { showRelationType: true, rlLeaf: true, showBCs: true, + showBCsInEditLPMode: false, showTrail: true, showGrid: true, showPrevNext: true, diff --git a/src/interfaces.ts b/src/interfaces.ts index 8e2a50a5..15c02862 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -35,6 +35,7 @@ export interface BCSettings { superDebugMode: boolean; rlLeaf: boolean; showBCs: boolean; + showBCsInEditLPMode: boolean; showAll: boolean; showGrid: boolean; showPrevNext: boolean; diff --git a/src/main.ts b/src/main.ts index 0b899c28..d7aad8f5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -71,17 +71,19 @@ export default class BCPlugin extends Plugin { refreshIntervalID: number; mainG: MultiGraph; activeLeafChange: EventRef = undefined; + layoutChange: EventRef = undefined; statusBatItemEl: HTMLElement = undefined; async refreshIndex() { - if (!this.activeLeafChange) this.registerActiveLeafEvent(); + if (!this.activeLeafChange) this.registerActiveLeafChangeEvent(); + if (!this.layoutChange) this.registerLayoutChangeEvent(); this.mainG = await this.initGraphs(); for (const view of VIEWS) await this.getActiveTYPEView(view.type)?.draw(); if (this.settings.showTrail) await this.drawTrail(); new Notice("Index refreshed"); } - registerActiveLeafEvent() { + registerActiveLeafChangeEvent() { this.activeLeafChange = this.app.workspace.on( "active-leaf-change", async () => { @@ -97,6 +99,13 @@ export default class BCPlugin extends Plugin { this.registerEvent(this.activeLeafChange); } + registerLayoutChangeEvent() { + this.layoutChange = this.app.workspace.on("layout-change", async () => { + if (this.settings.showBCs) await this.drawTrail(); + }); + this.registerEvent(this.layoutChange); + } + initEverything = async () => { const { settings } = this; this.mainG = await this.initGraphs(); @@ -108,7 +117,8 @@ export default class BCPlugin extends Plugin { if (settings.showBCs) await this.drawTrail(); - this.registerActiveLeafEvent(); + this.registerActiveLeafChangeEvent(); + this.registerLayoutChangeEvent(); }; async onload(): Promise { @@ -993,38 +1003,65 @@ export default class BCPlugin extends Plugin { async drawTrail(): Promise { const { settings } = this; + const { + showBCs, + hideTrailField, + noPathMessage, + respectReadableLineLength, + showTrail, + showGrid, + showPrevNext, + } = settings; debugGroupStart(settings, "debugMode", "Draw Trail"); const activeMDView = this.app.workspace.getActiveViewOfType(MarkdownView); - if (!settings.showBCs || !activeMDView) { + if (!showBCs || !activeMDView) { debugGroupEnd(settings, "debugMode"); return; } - - const currFile = activeMDView.file; - const currMetadata = this.app.metadataCache.getFileCache(currFile); - - const previewView = activeMDView.contentEl.querySelector( - ".markdown-preview-view" - ); - previewView.querySelector("div.BC-trail")?.remove(); - if (currMetadata.frontmatter?.hasOwnProperty(settings.hideTrailField)) { + const mode = activeMDView.getMode(); + if ( + (mode === "source" || mode === "live") && + !settings.showBCsInEditLPMode + ) { debugGroupEnd(settings, "debugMode"); return; } - const frontm = - this.app.metadataCache.getFileCache(currFile)?.frontmatter ?? {}; - if (frontm["kanban-plugin"]) { + const { file } = activeMDView; + const { frontmatter } = this.app.metadataCache.getFileCache(file) ?? {}; + + if (frontmatter?.[hideTrailField] || frontmatter?.["kanban-plugin"]) { debugGroupEnd(settings, "debugMode"); return; } + let view: HTMLElement; + switch (mode) { + case "source": + view = activeMDView.contentEl.querySelector("div.markdown-source-view"); + break; + case "preview": + view = activeMDView.contentEl.querySelector( + "div.markdown-preview-view[tabindex='-1']" + ); + break; + case "live": + view = activeMDView.contentEl.querySelector( + "div.markdown-source-view.is-live-preview" + ); + break; + } + + activeMDView.containerEl + .querySelectorAll(".BC-trail") + ?.forEach((trail) => trail.remove()); + const closedUp = this.getLimitedTrailSub(); - const sortedTrails = this.getBreadcrumbs(closedUp, currFile); + const sortedTrails = this.getBreadcrumbs(closedUp, file); this.debug({ sortedTrails }); - const { basename } = currFile; + const { basename } = file; const { next: { reals: rNext, implieds: iNext }, @@ -1048,46 +1085,65 @@ export default class BCPlugin extends Plugin { const noItems = sortedTrails.length === 0 && next.length === 0 && prev.length === 0; - if (noItems && settings.noPathMessage === "") { + if (noItems && noPathMessage === "") { debugGroupEnd(settings, "debugMode"); return; } + const max_width = getComputedStyle( + document.querySelector( + ".markdown-preview-view.is-readable-line-width .markdown-preview-sizer" + ) + ).getPropertyValue("max-width"); + const trailDiv = createDiv({ cls: `BC-trail ${ - settings.respectReadableLineLength + respectReadableLineLength ? "is-readable-line-width markdown-preview-sizer markdown-preview-section" : "" }`, + attr: { + style: + (mode !== "preview" ? `max-width: ${max_width};` : "") + + "margin: 0 auto", + }, }); - this.visited.push([currFile.path, trailDiv]); + this.visited.push([file.path, trailDiv]); - previewView.querySelector(".markdown-preview-sizer").before(trailDiv); + if (mode === "preview") { + view.querySelector("div.markdown-preview-sizer").before(trailDiv); + } else if (mode === "live") { + const editorDiv = view.querySelector("div.cm-editor"); + editorDiv.before(trailDiv); + } else { + const editorDiv = view.querySelector("div.CodeMirror-sizer"); + editorDiv.before(trailDiv); + } trailDiv.empty(); if (noItems) { - trailDiv.innerText = settings.noPathMessage; + trailDiv.innerText = noPathMessage; debugGroupEnd(settings, "debugMode"); return; } const props = { sortedTrails, app: this.app, plugin: this }; - if (settings.showTrail && sortedTrails.length) { + if (showTrail && sortedTrails.length) { new TrailPath({ target: trailDiv, props, }); } - if (settings.showGrid && sortedTrails.length) { + if (showGrid && sortedTrails.length) { new TrailGrid({ target: trailDiv, props, }); } - if (settings.showPrevNext && (next.length || prev.length)) { + if (showPrevNext && (next.length || prev.length)) { new NextPrev({ target: trailDiv, props: { app: this.app, plugin: this, next, prev }, diff --git a/styles.css b/styles.css index 3804afa6..be4fe8dd 100644 --- a/styles.css +++ b/styles.css @@ -1,4 +1,4 @@ -div.BC-trail { +.BC-trail { border: 1px solid var(--background-modifier-border); border-radius: 5px; padding: 5px;