diff --git a/src/main.ts b/src/main.ts index 0f19238..286f1b6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -30,7 +30,7 @@ export default class PluginsAnnotations extends Plugin { pluginIdToNameMap: Record = {}; sortedPluginIds: string[] = []; - svg_unlocked = ' | null = null; private resolveSavePromise: (() => void) | null = null; - // public debouncedSaveAnnotations: (callback: () => void = (): void => {}): void; + // Declare class methods that will be initialized in the constructor + debouncedSaveAnnotations: (callback?: () => void) => void; + waitForSaveToComplete: () => Promise; constructor(app:App, manifest:PluginManifest) { super(app, manifest); - // const { waitFnc, debouncedFct } = debounceFactoryWithWaitMechanism(async (...args: unknown[]): Promise => { - // // Extract the callback if it's provided, otherwise default to a no-op function - // const callback = typeof args[0] === 'function' ? args[0] as () => void : () => {}; - - // await this.saveSettings(); - // callback(); // Call the callback after saving settings - // }, 100); + // Set up debounced saving functions + const timeout_debounced_saving_ms = 100; + const { debouncedFct, waitFnc } = debounceFactoryWithWaitMechanism( + async (callback: () => void = (): void => {}) => { + await this.saveSettings(); + if(callback) callback(); + console.log("FINISHED SAVING ANNOTATIONS"); + }, timeout_debounced_saving_ms); + this.debouncedSaveAnnotations = debouncedFct; + this.waitForSaveToComplete = waitFnc; } async onload() { @@ -93,28 +101,6 @@ export default class PluginsAnnotations extends Plugin { } } }); - - const asyncFunc = async (msg: string) => { - console.log("Processing:", msg); - return `Processed: ${msg}`; - }; - - const { debouncedFct, waitFnc } = debounceFactoryWithWaitMechanism(async (msg: string) => { - console.log("Saving settings for:", msg); - await new Promise(resolve => setTimeout(resolve, 500)); // Simulate async work - console.log("Settings saved for:", msg); - }, 1000); - - // Trigger debounced function calls - debouncedFct("User 1"); - debouncedFct("User 2"); - - // Wait for the last debounced function call to complete - waitFnc().then(() => { - console.log("All debounced calls have been completed."); - }); - - } /* Load settings for different versions */ @@ -555,23 +541,25 @@ export default class PluginsAnnotations extends Plugin { } } - addAnnotation(plugin: Element) { - const settingItemInfo = plugin.querySelector('.setting-item-info'); + addAnnotation(pluginDOMElement: Element) { + const pluginNameDiv = pluginDOMElement.querySelector('.setting-item-name'); + const pluginName = pluginNameDiv ? pluginNameDiv.textContent : null; + + if (!pluginName) { + console.warn('Plugin name not found'); + return; + } + + const pluginId = this.pluginNameToIdMap[pluginName]; + if (!pluginId) { + console.warn(`Plugin ID not found for plugin name: ${pluginName}`); + return; + } + + const manifest = this.app.plugins.manifests[pluginId]; + + const settingItemInfo = pluginDOMElement.querySelector('.setting-item-info'); if (settingItemInfo) { - const pluginNameDiv = plugin.querySelector('.setting-item-name'); - const pluginName = pluginNameDiv ? pluginNameDiv.textContent : null; - - if (!pluginName) { - console.warn('Plugin name not found'); - return; - } - - const pluginId = this.pluginNameToIdMap[pluginName]; - if (!pluginId) { - console.warn(`Plugin ID not found for plugin name: ${pluginName}`); - return; - } - const descriptionDiv = settingItemInfo.querySelector('.setting-item-description'); if (descriptionDiv) { const commentDiv = descriptionDiv.querySelector('.plugin-comment'); @@ -584,56 +572,38 @@ export default class PluginsAnnotations extends Plugin { descriptionDiv.appendChild(annotation_container); } } + } + const controlDiv = pluginDOMElement.querySelector('.setting-item-control'); + if (controlDiv) { + const GitHubDiv = document.createElement('div'); + GitHubDiv.classList.add('clickable-icon', 'extra-setting-button'); + GitHubDiv.setAttribute('aria-label', 'Open plugin\'s GitHub page'); + GitHubDiv.innerHTML = this.svg_github_light; - const controlDiv = settingItemInfo.querySelector('.setting-item-control'); - console.log(controlDiv); + // Get all elements with the class .clickable-icon inside controlDiv + const clickableIcons = controlDiv.querySelectorAll('.clickable-icon'); + console.log(manifest); + // Insert the new icon as the second last of all clickable icons + if (clickableIcons.length > 0) { + const lastIcon = clickableIcons[clickableIcons.length - 1]; + controlDiv.insertBefore(GitHubDiv, lastIcon); + } else { + // If no clickable icons are found, append it as the first child + controlDiv.insertBefore(GitHubDiv, controlDiv.firstChild); + } } } addAnnotations(tab: SettingTab) { const pluginsContainer = tab.containerEl.querySelector('.installed-plugins-container'); if (!pluginsContainer) return; - - const plugins = pluginsContainer.querySelectorAll('.setting-item'); - plugins.forEach(plugin => { - this.addAnnotation(plugin); + + const pluginDOMElements = pluginsContainer.querySelectorAll('.setting-item'); + pluginDOMElements.forEach(pluginDOMElement => { + this.addAnnotation(pluginDOMElement); }); } - debouncedSaveAnnotations(callback: () => void = (): void => {}) { - const timeout_ms = 100; - - // Clear the previous timeout and resolve the previous promise if necessary - if (this.saveTimeout) { - clearTimeout(this.saveTimeout); - - // By stopping the timer, the promise is unlikely to be resolved. So, we need to resolve it manually. - if (this.resolveSavePromise) { - this.resolveSavePromise(); // Ensure the previous promise is resolved to avoid memory leaks - } - } - - // Create a new promise and store the resolve function - this.savePromise = new Promise((resolve) => { - this.resolveSavePromise = resolve; // Store the resolve function - - this.saveTimeout = window.setTimeout(async () => { - await this.saveSettings(); - callback(); - this.saveTimeout = null; - resolve(); // Resolve the promise when the timer completes - }, timeout_ms); - }); - } - - // Helper method to check if a save is in progress and wait for it - async waitForSaveToComplete() { - if (this.saveTimeout && this.savePromise) { - // Wait for the existing promise to resolve - await this.savePromise; - } - } - removeCommentsFromTab() { if (this.observedTab) { const commentElements = this.observedTab.containerEl.querySelectorAll('.plugin-comment'); @@ -646,14 +616,14 @@ export default class PluginsAnnotations extends Plugin { onunload() { // console.log('Unloading Plugins Annotations'); - // // Remove all comments - // this.removeCommentsFromTab(); + // Remove all comments + this.removeCommentsFromTab(); - // // Just in case, disconnect observers if they still exist - // this.disconnectObservers(); + // Just in case, disconnect observers if they still exist + this.disconnectObservers(); - // // Remove icons - // this.removeIcon(); + // Remove icons + this.removeIcon(); } getUninstalledPlugins(): PluginAnnotationDict { diff --git a/src/utils.ts b/src/utils.ts index 86e71de..d932059 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -122,7 +122,7 @@ export function debounceFactory unknown>(func: }; } -export function debounceFactoryWithWaitMechanism void | Promise>(func: F, wait: number) { +export function debounceFactoryWithWaitMechanism void | Promise>(func: F, wait: number) { let timeout: ReturnType | null = null; let promise: Promise | null = null; let resolvePromise: (() => void) | null = null; @@ -149,16 +149,14 @@ export function debounceFactoryWithWaitMechanism((resolve, reject) => { // Set the new resolvePromise function resolvePromise = () => { - console.log("Resolved old promise") - resolve(); // Reject with a specific cancellation error + resolve(); // Resolve to indicate that the previous execution was cancelled }; // Schedule the function to run after the debounce delay timeout = setTimeout(async () => { try { - // Await the result of the function and cast it to the expected return type - (await func(...args)) as ReturnType; - resolve(); // Resolve with the result of the function (sync or async) + await func(...args); // Execute the debounced function + resolve(); // Resolve the promise once the function is done } catch (error) { reject(error); // Reject the promise if the function throws an error } @@ -169,17 +167,14 @@ export function debounceFactoryWithWaitMechanism { private files:TFile[] = [];