mirror of
https://github.com/alberti42/obsidian-plugins-annotations.git
synced 2026-07-22 10:10:24 +00:00
Improved debounced saving. Fixed a bug when switching between preference pane and community plugins pane, where the settings were not stored properly.
This commit is contained in:
parent
393d40054a
commit
f5e42dad89
5 changed files with 66 additions and 29 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "plugins-annotations",
|
||||
"name": "Plugins Annotations",
|
||||
"version": "1.6.2",
|
||||
"version": "1.6.3",
|
||||
"minAppVersion": "1.5.0",
|
||||
"description": "Allows adding personal comments to each installed plugin.",
|
||||
"author": "Andrea Alberti",
|
||||
|
|
|
|||
|
|
@ -92,22 +92,12 @@ export class annotationControl {
|
|||
});
|
||||
|
||||
this.annotation_div.addEventListener('input', (event: Event) => {
|
||||
// If the user starts typing, it removes the state of placeholder if this was set
|
||||
if(this.plugin.settings.editable) this.isPlaceholder = false;
|
||||
});
|
||||
|
||||
// Add placeholder class back if no changes are made
|
||||
this.annotation_div.addEventListener('blur', (event:FocusEvent) => {
|
||||
if(!this.plugin.settings.editable) { return; }
|
||||
if(this.clickedLink) return;
|
||||
|
||||
const content = this.annotation_div.innerText.trim();
|
||||
|
||||
if (this.isPlaceholder || content === '') { // placeholder
|
||||
if (content === '') { // placeholder
|
||||
this.isPlaceholder = true;
|
||||
this.annotationDesc = '';
|
||||
this.plugin.removeAnnotation(this.pluginId);
|
||||
this.setPlaceholderClasses();
|
||||
} else {
|
||||
this.isPlaceholder = false;
|
||||
this.annotationDesc = content.trim();
|
||||
|
|
@ -115,10 +105,21 @@ export class annotationControl {
|
|||
desc: this.annotationDesc,
|
||||
name: this.pluginName,
|
||||
});
|
||||
}
|
||||
this.plugin.debouncedSaveAnnotations();
|
||||
});
|
||||
|
||||
// Add placeholder class back if no changes are made
|
||||
this.annotation_div.addEventListener('blur', (event:FocusEvent) => {
|
||||
if(!this.plugin.settings.editable) { return; }
|
||||
if(this.clickedLink) return;
|
||||
|
||||
if (this.isPlaceholder) { // placeholder
|
||||
this.setPlaceholderClasses();
|
||||
} else {
|
||||
this.removePlaceholderClasses();
|
||||
}
|
||||
this.renderAnnotation();
|
||||
this.plugin.debouncedSaveAnnotations();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
45
src/main.ts
45
src/main.ts
|
|
@ -41,10 +41,14 @@ export default class PluginsAnnotations extends Plugin {
|
|||
</svg>';
|
||||
|
||||
private mutationObserver: MutationObserver | null = null;
|
||||
private saveTimeout: number | null = null;
|
||||
private observedTab: SettingTab | null = null;
|
||||
private vaultPath: string | null = null;
|
||||
|
||||
/* For debounced saving */
|
||||
private saveTimeout: number | null = null;
|
||||
private savePromise: Promise<void> | null = null;
|
||||
private resolveSavePromise: (() => void) | null = null;
|
||||
|
||||
async onload() {
|
||||
|
||||
// console.clear();
|
||||
|
|
@ -199,8 +203,8 @@ export default class PluginsAnnotations extends Plugin {
|
|||
});
|
||||
|
||||
// Merge imported backups with backups created while importing the data
|
||||
importedSettings.backups = [...importedSettings.backups, ...importBackups];
|
||||
|
||||
importedSettings.backups = [...importBackups, ...importedSettings.backups];
|
||||
|
||||
// Merge loaded settings with default settings
|
||||
this.settings = Object.assign({}, structuredClone(DEFAULT_SETTINGS), importedSettings);
|
||||
|
||||
|
|
@ -223,6 +227,7 @@ export default class PluginsAnnotations extends Plugin {
|
|||
|
||||
let isRestoreOperation;
|
||||
if(data === undefined) {
|
||||
this.waitForSaveToComplete();
|
||||
data = await this.loadData();
|
||||
isRestoreOperation = false;
|
||||
} else {
|
||||
|
|
@ -541,18 +546,38 @@ export default class PluginsAnnotations extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
debouncedSaveAnnotations(callback: ()=>void = ():void => {}) {
|
||||
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<void>((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;
|
||||
}
|
||||
|
||||
this.saveTimeout = window.setTimeout(async () => {
|
||||
await this.saveSettings();
|
||||
callback();
|
||||
this.saveTimeout = null;
|
||||
}, timeout_ms);
|
||||
}
|
||||
|
||||
removeCommentsFromTab() {
|
||||
|
|
|
|||
|
|
@ -437,6 +437,7 @@ export class PluginsAnnotationsSettingTab extends PluginSettingTab {
|
|||
|
||||
class BackupManager {
|
||||
private backupTableContainer: HTMLElement;
|
||||
private UNTITLED_BACKUP = 'Untitled backup';
|
||||
|
||||
constructor(private plugin:PluginsAnnotations, private containerEl:HTMLElement) {
|
||||
|
||||
|
|
@ -468,7 +469,7 @@ class BackupManager {
|
|||
.setButtonText('Create Backup')
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
const backupName = 'Untitled backup';
|
||||
const backupName = this.UNTITLED_BACKUP;
|
||||
await backupSettings(backupName,this.plugin.settings,this.plugin.settings.backups);
|
||||
await this.plugin.saveSettings();
|
||||
this.updateListBackups();
|
||||
|
|
@ -554,9 +555,18 @@ class BackupManager {
|
|||
const nameDiv = nameCell.createDiv({ text: backup.name, attr: { contenteditable: 'true' } });
|
||||
|
||||
// Handle saving the updated name when editing is complete
|
||||
nameDiv.addEventListener('blur', async () => {
|
||||
const newName = nameDiv.textContent?.trim() || 'Unnamed Backup';
|
||||
backup.name = newName;
|
||||
nameDiv.addEventListener('input', () => {
|
||||
const newName = nameDiv.innerText.trim();
|
||||
backup.name = newName === '' ? this.UNTITLED_BACKUP : newName;
|
||||
this.plugin.debouncedSaveAnnotations();
|
||||
});
|
||||
|
||||
// Handle saving the updated name when editing is complete
|
||||
nameDiv.addEventListener('blur', () => {
|
||||
const newName = nameDiv.innerText.trim();
|
||||
if(newName === '') {
|
||||
nameDiv.innerText = backup.name;
|
||||
}
|
||||
this.plugin.debouncedSaveAnnotations();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -221,8 +221,9 @@ export async function backupSettings(backupName: string, toBeBackedUp: unknown,
|
|||
// Deep copy
|
||||
const deepCopiedSettings = structuredClone(settingsWithoutBackup);
|
||||
|
||||
// Add the backup with the deep-copied settings
|
||||
destBackups.push({
|
||||
// Add the deep-copy of the settings to the beginning of the array
|
||||
// See: https://stackoverflow.com/a/8073687/4216175
|
||||
destBackups.unshift({
|
||||
name: backupName,
|
||||
date: new Date(),
|
||||
settings: deepCopiedSettings
|
||||
|
|
|
|||
Loading…
Reference in a new issue