diff --git a/src/events/FrontMatterTitle.ts b/src/events/FrontMatterTitle.ts index 8a66190..966837f 100644 --- a/src/events/FrontMatterTitle.ts +++ b/src/events/FrontMatterTitle.ts @@ -33,7 +33,7 @@ export class FrontMatterTitlePluginHandler { const event: Listener = { name: 'manager:update', cb: (data) => { - this.handleRename(data as any, true); + this.fmptUpdateFileName(data as any, true); }, }; // Keep ref to remove listener @@ -41,10 +41,10 @@ export class FrontMatterTitlePluginHandler { if (ref) { this.eventRef = ref; } - this.plugin.app.vault.getFiles().forEach((file) => { - this.handleRename({ id: '', result: false, path: file.path }, false); - }); - this.plugin.updateBreadcrumbs(); + // this.plugin.app.vault.getFiles().forEach((file) => { + // this.handleRename({ id: '', result: false, path: file.path }, false); + // }); + this.plugin.updateAllBreadcrumbs(); })(); } deleteEvent() { @@ -52,10 +52,12 @@ export class FrontMatterTitlePluginHandler { this.dispatcher.removeListener(this.eventRef); } } - async handleRename(data: { + async fmptUpdateFileName(data: { id: string; result: boolean; path: string; + pathOnly: boolean; + breadcrumb?: HTMLElement; }, isEvent: boolean) { if ((data as any).data) data = (data as any).data; const file = this.app.vault.getAbstractFileByPath(data.path); @@ -69,12 +71,19 @@ export class FrontMatterTitlePluginHandler { const folderNote = getFolderNote(this.plugin, folder.path); if (!folderNote) { return; } if (folderNote !== file) { return; } + if (!data.pathOnly) { + this.plugin.changeFolderNameInExplorer(folder, newName); + } + + const breadcrumb = data.breadcrumb; + if (breadcrumb) { + this.plugin.changeFolderNameInPath(folder, newName, breadcrumb); + } if (isEvent) { - this.plugin.changeName(folder, newName, true); - } else { - this.plugin.changeName(folder, newName, false); + this.plugin.updateAllBreadcrumbs(); } + if (newName) { folder.newName = newName; this.modifiedFolders.set(folder.path, folder); @@ -84,4 +93,34 @@ export class FrontMatterTitlePluginHandler { } } + + async fmptUpdateFolderName(data: { + id: string; + result: boolean; + path: string; + pathOnly: boolean; + breadcrumb?: HTMLElement; + }, replacePath: boolean) { + if ((data as any).data) data = (data as any).data; + const folder = this.app.vault.getAbstractFileByPath(data.path); + if (!(folder instanceof TFolder)) { return; } + const folderNote = getFolderNote(this.plugin, folder.path); + if (!folderNote) { return; } + + const resolver = this.api?.getResolverFactory()?.createResolver('#feature-id#'); + const newName = resolver?.resolve(folderNote?.path ?? ''); + if (!newName) return; + + if (!data.pathOnly) { + this.plugin.changeFolderNameInExplorer(folder, newName); + } + + const breadcrumb = data.breadcrumb; + if (breadcrumb) { + this.plugin.changeFolderNameInPath(folder, newName, breadcrumb); + } + + folder.newName = newName; + this.modifiedFolders.set(folder.path, folder); + } } diff --git a/src/events/MutationObserver.ts b/src/events/MutationObserver.ts index 39a841d..5b9b66e 100644 --- a/src/events/MutationObserver.ts +++ b/src/events/MutationObserver.ts @@ -1,96 +1,133 @@ +import { Keymap, Platform } from 'obsidian'; import FolderNotesPlugin from 'src/main'; -import { Platform, Keymap } from 'obsidian'; import { getFolderNote } from 'src/functions/folderNoteFunctions'; import { handleFolderClick, handleViewHeaderClick } from './handleClick'; import { getExcludedFolder } from 'src/ExcludeFolders/functions/folderFunctions'; import { applyCSSClassesToFolder } from 'src/functions/styleFunctions'; -export async function addObserver(plugin: FolderNotesPlugin) { - plugin.observer = new MutationObserver((mutations: MutationRecord[]) => { - mutations.forEach((rec) => { - if (rec.type === 'childList') { - (rec.target).querySelectorAll('div.nav-folder') - .forEach(async (element: HTMLElement) => { - let folderTitle = element.querySelector('div.nav-folder-title-content') as HTMLElement; - const filePath = folderTitle.parentElement?.getAttribute('data-path') || ''; +let fileExplorerMutationObserver: MutationObserver | null = null; - applyCSSClassesToFolder(filePath, plugin); +export function registerFileExplorerObserver(plugin: FolderNotesPlugin) { + // Run once on initial layout + plugin.app.workspace.onLayoutReady(() => { + initializeFolderNoteFeatures(plugin); + initializeBreadcrumbs(plugin); + }); - if (folderTitle) { - await initializeFolderTitle(folderTitle, plugin); - } else { + // Re-run when layout changes (e.g. File Explorer is reopened) + plugin.registerEvent( + plugin.app.workspace.on('layout-change', () => { + initializeFolderNoteFeatures(plugin); - const observer = new MutationObserver(async (mutations, obs) => { - folderTitle = element.querySelector('div.nav-folder-title-content') as HTMLElement; + const activeLeaf = plugin.app.workspace.getActiveFileView()?.containerEl; + if (!activeLeaf) return; - if (folderTitle) { - await initializeFolderTitle(folderTitle, plugin); - obs.disconnect(); - } - }); + const titleContainer = activeLeaf.querySelector('.view-header-title-container'); + if (!(titleContainer instanceof HTMLElement)) return; - observer.observe(element, { childList: true, subtree: true }); - } - }); - if (!plugin.settings.openFolderNoteOnClickInPath) { return; } - // (rec.target).querySelectorAll('div.nav-file-title-content') - // .forEach(async (element: HTMLElement) => { - // const filePath = element.parentElement?.getAttribute('data-path') || ''; - // applyCSSClassesToFolderNote(filePath, plugin); - // }); - (rec.target).querySelectorAll('span.view-header-breadcrumb') - .forEach((element: HTMLElement) => { - const breadcrumbs = element.parentElement?.querySelectorAll('span.view-header-breadcrumb'); - if (!breadcrumbs) return; - let path = ''; - breadcrumbs.forEach(async (breadcrumb: HTMLElement) => { - if (breadcrumb.hasAttribute('old-name')) { - path += breadcrumb.getAttribute('old-name') + '/'; - } else { - path += breadcrumb.innerText.trim() + '/'; - } - const folderPath = path.slice(0, -1); - breadcrumb.setAttribute('data-path', folderPath); - const folder = plugin.fmtpHandler?.modifiedFolders.get(folderPath); - if (folder && plugin.settings.frontMatterTitle.path && plugin.settings.frontMatterTitle.enabled) { - breadcrumb.setAttribute('old-name', folder.name || ''); - breadcrumb.innerText = folder.newName || ''; - } - const excludedFolder = getExcludedFolder(plugin, folderPath, true); - if (excludedFolder?.disableFolderNote) return; - const folderNote = getFolderNote(plugin, folderPath); - if (folderNote) { - breadcrumb.classList.add('has-folder-note'); - } - }); - element.parentElement?.setAttribute('data-path', path.slice(0, -1)); - if (breadcrumbs.length > 0) { - breadcrumbs.forEach((breadcrumb: HTMLElement) => { - if (breadcrumb.onclick) return; - breadcrumb.addEventListener('click', (e) => { - handleViewHeaderClick(e, plugin); - }, { capture: true }); - }); - } - }); - } - }); + updateFolderNamesInPath(plugin, titleContainer); + }) + ); +} + +export function unregisterFileExplorerObserver() { + if (fileExplorerMutationObserver) { + fileExplorerMutationObserver.disconnect(); + fileExplorerMutationObserver = null; + } +} + +function initializeFolderNoteFeatures(plugin: FolderNotesPlugin) { + const explorer = document.querySelector('.workspace-leaf-content[data-type="file-explorer"] .nav-files-container'); + if (!explorer) return; + + initializeAllFolderTitles(explorer, plugin); + observeFolderTitleMutations(explorer, plugin); +} + +function initializeBreadcrumbs(plugin: FolderNotesPlugin) { + const titleContainers = document.querySelectorAll('.view-header-title-container'); + if (!titleContainers.length) return; + titleContainers.forEach((container) => { + if (!(container instanceof HTMLElement)) return; + scheduleIdle(() => updateFolderNamesInPath(plugin, container), { timeout: 1000 }); }); } -async function initializeFolderTitle(folderTitle: HTMLElement, plugin: any) { - if (folderTitle.onclick) return; +/** + * Observes the File Explorer for newly added folder elements and applies plugin logic (e.g., styles, event listeners) + * automatically when folders are created, expanded, or when the File Explorer view is reopened. + */ +function observeFolderTitleMutations(container: Element, plugin: FolderNotesPlugin) { + if (fileExplorerMutationObserver) { + fileExplorerMutationObserver.disconnect(); + } + fileExplorerMutationObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + for (const node of Array.from(mutation.addedNodes)) { + if (!(node instanceof HTMLElement)) continue; + processAddedFolders(node, plugin); + } + } + }); + + fileExplorerMutationObserver.observe(container, { childList: true, subtree: true }); +} + +function initializeAllFolderTitles(container: Element, plugin: FolderNotesPlugin) { + const allTitles = container.querySelectorAll('.nav-folder-title-content'); + for (const title of Array.from(allTitles)) { + const folderTitle = title as HTMLElement; + const folderEl = folderTitle.closest('.nav-folder-title'); + if (!folderEl) continue; + + const folderPath = folderEl.getAttribute('data-path') || ''; + setTimeout(() => { + setupFolderTitle(folderTitle, plugin, folderPath); + }, 1000); + } +} + +function processAddedFolders(node: HTMLElement, plugin: FolderNotesPlugin) { + const titles: HTMLElement[] = []; + if (node.matches('.nav-folder-title-content')) { + titles.push(node); + } + node.querySelectorAll('.nav-folder-title-content').forEach((el) => { + titles.push(el as HTMLElement); + }); + + titles.forEach((folderTitle) => { + const folderEl = folderTitle.closest('.nav-folder-title'); + const folderPath = folderEl?.getAttribute('data-path') || ''; + if (!folderEl || !folderPath) { + setTimeout(() => { + const retryFolderEl = folderTitle.closest('.nav-folder-title'); + const retryFolderPath = retryFolderEl?.getAttribute('data-path') || ''; + if (retryFolderEl && retryFolderPath) { + setupFolderTitle(folderTitle, plugin, retryFolderPath); + } + }, 50); + return; + } + setupFolderTitle(folderTitle, plugin, folderPath); + }); +} + +async function setupFolderTitle(folderTitle: HTMLElement, plugin: FolderNotesPlugin, folderPath: string) { + if (folderTitle.dataset.initialized === 'true') return; + if (!folderPath) return; if (Platform.isMobile && plugin.settings.disableOpenFolderNoteOnClick) return; - const folderPath = folderTitle.parentElement?.getAttribute('data-path') || ''; - + folderTitle.dataset.initialized = 'true'; await applyCSSClassesToFolder(folderPath, plugin); - // Handle middle click (auxclick) + if (plugin.settings.frontMatterTitle.enabled) { + plugin.fmtpHandler?.fmptUpdateFolderName({ id: '', result: false, path: folderPath, pathOnly: false }, false); + } + folderTitle.addEventListener('auxclick', (event: MouseEvent) => { - if (event.button === 1) { - handleFolderClick(event, plugin); - } + if (event.button === 1) handleFolderClick(event, plugin); }, { capture: true }); folderTitle.onclick = (event: MouseEvent) => handleFolderClick(event, plugin); @@ -102,17 +139,16 @@ async function initializeFolderTitle(folderTitle: HTMLElement, plugin: any) { if (!Keymap.isModEvent(event)) return; if (!(event.target instanceof HTMLElement)) return; - const folderPath = event?.target.parentElement?.getAttribute('data-path') || ''; const folderNote = getFolderNote(plugin, folderPath); if (!folderNote) return; plugin.app.workspace.trigger('hover-link', { - event: event, + event, source: 'preview', hoverParent: { file: folderNote }, targetEl: event.target, - linktext: folderNote?.basename, - sourcePath: folderNote?.path, + linktext: folderNote.basename, + sourcePath: folderNote.path, }); plugin.hoverLinkTriggered = true; }); @@ -123,3 +159,40 @@ async function initializeFolderTitle(folderTitle: HTMLElement, plugin: any) { plugin.hoverLinkTriggered = false; }); } + +async function updateFolderNamesInPath(plugin: FolderNotesPlugin, titleContainer: HTMLElement) { + const headers = titleContainer.querySelectorAll('span.view-header-breadcrumb'); + let path = ''; + headers.forEach(async (breadcrumb: HTMLElement) => { + path += breadcrumb.getAttribute('old-name') ?? (breadcrumb as HTMLElement).innerText.trim(); + path += '/'; + const folderPath = path.slice(0, -1); + + const excludedFolder = getExcludedFolder(plugin, folderPath, true); + if (excludedFolder?.disableFolderNote) return; + const folderNote = getFolderNote(plugin, folderPath); + if (folderNote) breadcrumb.classList.add('has-folder-note'); + + breadcrumb?.setAttribute('data-path', path.slice(0, -1)); + if (!breadcrumb.onclick) { + breadcrumb.addEventListener('click', (e) => { + handleViewHeaderClick(e as MouseEvent, plugin); + }, { capture: true }); + } + + if (plugin.settings.frontMatterTitle.enabled) { + plugin.fmtpHandler?.fmptUpdateFolderName({ id: '', result: false, path: folderPath, pathOnly: true, breadcrumb: breadcrumb }, true); + } + }); +} + +// Schedules a callback to run when the browser is idle, or after a timeout as a fallback. +// - callback: The function to execute when idle or after the timeout. +// - options: Optional object with a 'timeout' property (in milliseconds). +function scheduleIdle(callback: () => void, options?: { timeout: number }) { + if ('requestIdleCallback' in window) { + (window as any).requestIdleCallback(callback, options); + } else { + setTimeout(callback, options?.timeout || 200); + } +} diff --git a/src/events/handleRename.ts b/src/events/handleRename.ts index ba9e1b1..e0753df 100644 --- a/src/events/handleRename.ts +++ b/src/events/handleRename.ts @@ -36,7 +36,7 @@ export function handleRename(file: TAbstractFile, oldPath: string, plugin: Folde } } else if (file instanceof TFile) { if (isRename) { - return handleFileRename(file, oldPath, plugin); + return fmptUpdateFileName(file, oldPath, plugin); } else { return handleFileMove(file, oldPath, plugin); } @@ -129,7 +129,7 @@ export async function handleFolderRename(file: TFolder, oldPath: string, plugin: plugin.app.fileManager.renameFile(folderNote, newPath); } -export async function handleFileRename(file: TFile, oldPath: string, plugin: FolderNotesPlugin) { +export async function fmptUpdateFileName(file: TFile, oldPath: string, plugin: FolderNotesPlugin) { const oldFileName = removeExtension(getFileNameFromPathString(oldPath)); const newFileName = file.basename; if (oldFileName === newFileName) { return; } diff --git a/src/functions/styleFunctions.ts b/src/functions/styleFunctions.ts index eecea5b..a1cf620 100644 --- a/src/functions/styleFunctions.ts +++ b/src/functions/styleFunctions.ts @@ -5,7 +5,7 @@ import { getFolder, getFolderNote } from 'src/functions/folderNoteFunctions'; import { getFileExplorer } from './utils'; import FolderOverviewPlugin from 'src/obsidian-folder-overview/src/main'; -export function loadFileClasses(forceReload = false, plugin: FolderNotesPlugin) { +export function updateAllFileStyles(forceReload = false, plugin: FolderNotesPlugin) { if (plugin.activeFileExplorer === getFileExplorer(plugin) && !forceReload) { return; } plugin.activeFileExplorer = getFileExplorer(plugin); plugin.app.vault.getAllLoadedFiles().forEach(async (file) => { diff --git a/src/main.ts b/src/main.ts index 374ad2b..19bcf61 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import { DEFAULT_SETTINGS, FolderNotesSettings, SettingsTab } from './settings/S import { Commands } from './Commands'; import { FileExplorerWorkspaceLeaf } from './globals'; import { handleFolderClick } from './events/handleClick'; -import { addObserver } from './events/MutationObserver'; +import { registerFileExplorerObserver, unregisterFileExplorerObserver } from './events/MutationObserver'; import { handleRename } from './events/handleRename'; import { getFolderNote, getFolder, openFolderNote } from './functions/folderNoteFunctions'; import { handleCreate } from './events/handleCreate'; @@ -14,7 +14,7 @@ import { FolderOverview } from './obsidian-folder-overview/src/FolderOverview'; import { TabManager } from './events/TabManager'; import './functions/ListComponent'; import { handleDelete } from './events/handleDelete'; -import { addCSSClassToTitleEL, getEl, loadFileClasses } from './functions/styleFunctions'; +import { addCSSClassToTitleEL, getEl, updateAllFileStyles } from './functions/styleFunctions'; import { getExcludedFolder } from './ExcludeFolders/functions/folderFunctions'; import { FileExplorerView, InternalPlugin } from 'obsidian-typings'; import { getFocusedItem } from './functions/utils'; @@ -67,12 +67,10 @@ export default class FolderNotesPlugin extends Plugin { this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this)); - await addObserver(this); - - this.observer.observe(document.body, { - childList: true, - subtree: true, - }); + // this.observer.observe(document.body, { + // childList: true, + // subtree: true, + // }); if (!this.settings.persistentSettingsTab.afterRestart) { this.settings.settingsTab = 'general'; @@ -144,6 +142,7 @@ export default class FolderNotesPlugin extends Plugin { } onLayoutReady() { + registerFileExplorerObserver(this); this.registerView(FOLDER_OVERVIEW_VIEW, (leaf: WorkspaceLeaf) => { return new FolderOverviewView(leaf, this); }); @@ -285,13 +284,13 @@ export default class FolderNotesPlugin extends Plugin { return true; } - async changeName(folder: TFolder, name: string | null | undefined, replacePath: boolean, waitForCreate = false, count = 0) { - if (!name) name = folder.name; + async changeFolderNameInExplorer(folder: TFolder, newName: string | null | undefined, waitForCreate = false, count = 0) { + if (!newName) newName = folder.name; let fileExplorerItem = getEl(folder.path, this); if (!fileExplorerItem) { if (waitForCreate && count < 5) { await new Promise((r) => setTimeout(r, 500)); - this.changeName(folder, name, replacePath, waitForCreate, count + 1); + this.changeFolderNameInExplorer(folder, newName, waitForCreate, count + 1); return; } return; @@ -300,18 +299,26 @@ export default class FolderNotesPlugin extends Plugin { fileExplorerItem = fileExplorerItem?.querySelector('div.nav-folder-title-content'); if (!fileExplorerItem) { return; } if (this.settings.frontMatterTitle.explorer && this.settings.frontMatterTitle.enabled) { - fileExplorerItem.innerText = name; + fileExplorerItem.innerText = newName; fileExplorerItem.setAttribute('old-name', folder.name); } else { fileExplorerItem.innerText = folder.name; fileExplorerItem.removeAttribute('old-name'); } - if (replacePath) { - this.updateBreadcrumbs(); - } } - updateBreadcrumbs(remove?: boolean) { + async changeFolderNameInPath(folder: TFolder, newName: string | null | undefined, breadcrumb: HTMLElement) { + if (!newName) newName = folder.name; + + breadcrumb.textContent = folder.newName || folder.name; + breadcrumb.setAttribute('old-name', folder.name); + breadcrumb.setAttribute('data-path', folder.path); + } + + /** + * Updates all folder names in the path above the note editor + */ + updateAllBreadcrumbs(remove?: boolean) { if (!this.settings.frontMatterTitle.path && !remove) { return; } const viewHeaderItems = document.querySelectorAll('span.view-header-breadcrumb'); const files = this.app.vault.getAllLoadedFiles().filter((file) => file instanceof TFolder); @@ -340,8 +347,7 @@ export default class FolderNotesPlugin extends Plugin { } onunload() { - console.log('unloading folder notes plugin'); - this.observer.disconnect(); + unregisterFileExplorerObserver(); document.body.classList.remove('folder-notes-plugin'); document.body.classList.remove('folder-note-underline'); document.body.classList.remove('hide-folder-note'); @@ -379,7 +385,7 @@ export default class FolderNotesPlugin extends Plugin { await this.saveData(this.settings); // cleanup any css if we need too if ((!this.settingsOpened || reloadStyles === true) && reloadStyles !== false) { - loadFileClasses(true, this); + updateAllFileStyles(true, this); } } diff --git a/src/settings/FileExplorerSettings.ts b/src/settings/FileExplorerSettings.ts index b32475a..3cf99ca 100644 --- a/src/settings/FileExplorerSettings.ts +++ b/src/settings/FileExplorerSettings.ts @@ -91,7 +91,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab) { settingsTab.plugin.settings.frontMatterTitle.explorer = value; await settingsTab.plugin.saveSettings(); settingsTab.plugin.app.vault.getFiles().forEach((file) => { - settingsTab.plugin.fmtpHandler?.handleRename({ id: '', result: false, path: file.path }, false); + settingsTab.plugin.fmtpHandler?.fmptUpdateFileName({ id: '', result: false, path: file.path, pathOnly: false }, false); }); }) ); diff --git a/src/settings/GeneralSettings.ts b/src/settings/GeneralSettings.ts index 63406a1..5371df2 100644 --- a/src/settings/GeneralSettings.ts +++ b/src/settings/GeneralSettings.ts @@ -5,7 +5,7 @@ import AddSupportedFileModal from '../modals/AddSupportedFileType'; import { FrontMatterTitlePluginHandler } from '../events/FrontMatterTitle'; import ConfirmationModal from './modals/CreateFnForEveryFolder'; import { TemplateSuggest } from '../suggesters/TemplateSuggester'; -import { loadFileClasses } from '../functions/styleFunctions'; +import { updateAllFileStyles } from '../functions/styleFunctions'; import BackupWarningModal from './modals/BackupWarning'; import RenameFolderNotesModal from './modals/RenameFns'; @@ -186,7 +186,7 @@ export async function renderGeneral(settingsTab: SettingsTab) { settingsTab.plugin.settings.storageLocation = value; await settingsTab.plugin.saveSettings(); settingsTab.display(); - loadFileClasses(undefined, settingsTab.plugin); + updateAllFileStyles(undefined, settingsTab.plugin); }) ) .addButton((button) => @@ -429,7 +429,7 @@ export async function renderGeneral(settingsTab: SettingsTab) { ' with folder notes. It allows you to set the folder name to some name you set in the front matter.', ); - new Setting(containerEl) + const fmtpSetting = new Setting(containerEl) .setName('Enable front matter title plugin integration') .setDesc(desc1) .addToggle((toggle) => @@ -442,10 +442,10 @@ export async function renderGeneral(settingsTab: SettingsTab) { settingsTab.plugin.fmtpHandler = new FrontMatterTitlePluginHandler(settingsTab.plugin); } else { if (settingsTab.plugin.fmtpHandler) { - settingsTab.plugin.updateBreadcrumbs(true); + settingsTab.plugin.updateAllBreadcrumbs(true); } settingsTab.plugin.app.vault.getFiles().forEach((file) => { - settingsTab.plugin.fmtpHandler?.handleRename({ id: '', result: false, path: file.path }, false); + settingsTab.plugin.fmtpHandler?.fmptUpdateFileName({ id: '', result: false, path: file.path, pathOnly: false }, false); }); settingsTab.plugin.fmtpHandler?.deleteEvent(); settingsTab.plugin.fmtpHandler = null; @@ -453,6 +453,8 @@ export async function renderGeneral(settingsTab: SettingsTab) { settingsTab.display(); }) ); + fmtpSetting.infoEl.appendText('Requires a restart to take effect'); + fmtpSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; settingsTab.settingsPage.createEl('h3', { text: 'Session & Persistence' }); diff --git a/src/settings/PathSettings.ts b/src/settings/PathSettings.ts index 9916ff5..4915082 100644 --- a/src/settings/PathSettings.ts +++ b/src/settings/PathSettings.ts @@ -49,9 +49,9 @@ export async function renderPath(settingsTab: SettingsTab) { settingsTab.plugin.settings.frontMatterTitle.path = value; await settingsTab.plugin.saveSettings(); if (value) { - settingsTab.plugin.updateBreadcrumbs(); + settingsTab.plugin.updateAllBreadcrumbs(); } else { - settingsTab.plugin.updateBreadcrumbs(true); + settingsTab.plugin.updateAllBreadcrumbs(true); } }) );