mirror of
https://github.com/callumalpass/tasknotes.git
synced 2026-07-22 12:50:26 +00:00
fix(#1419): Custom statuses and priorities now save correctly in settings
Text input fields used 'change' event which only fires on blur, so values were lost if modal closed without blurring. Changed to 'input' event for immediate value capture, and added hide() method to flush pending debounced saves when settings modal closes.
This commit is contained in:
parent
62eb7d0e53
commit
6f917b1eef
5 changed files with 53 additions and 9 deletions
|
|
@ -52,3 +52,9 @@ Example:
|
|||
- Updated `TAG_PATTERN` to include hyphens: `/#[\w/-]+/g`
|
||||
- Thanks to @JerryLu086 for reporting
|
||||
|
||||
- (#1419) Fixed custom statuses and priorities not saving in settings
|
||||
- Text input fields used `change` event which only fires on blur, losing values if modal closed without blurring
|
||||
- Changed to `input` event so values are captured on every keystroke
|
||||
- Added `hide()` method to settings tab to flush pending debounced saves when modal closes
|
||||
- Thanks to @s33a for reporting
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { App, PluginSettingTab, Platform, requireApiVersion } from "obsidian";
|
||||
import TaskNotesPlugin from "../main";
|
||||
import { debounce } from "./components/settingHelpers";
|
||||
import { debounce, DebouncedFunction } from "./components/settingHelpers";
|
||||
import { renderGeneralTab } from "./tabs/generalTab";
|
||||
import { renderTaskPropertiesTab } from "./tabs/taskPropertiesTab";
|
||||
import { renderModalFieldsTab } from "./tabs/modalFieldsTab";
|
||||
|
|
@ -19,7 +19,10 @@ export class TaskNotesSettingTab extends PluginSettingTab {
|
|||
plugin: TaskNotesPlugin;
|
||||
private activeTab = "general";
|
||||
private tabContents: Record<string, HTMLElement> = {};
|
||||
private debouncedSave = debounce(() => this.plugin.saveSettings(), 500);
|
||||
private debouncedSave: DebouncedFunction<() => Promise<void>> = debounce(
|
||||
() => this.plugin.saveSettings(),
|
||||
500
|
||||
);
|
||||
|
||||
constructor(app: App, plugin: TaskNotesPlugin) {
|
||||
super(app, plugin);
|
||||
|
|
@ -252,4 +255,12 @@ export class TaskNotesSettingTab extends PluginSettingTab {
|
|||
// Currently: ICS subscriptions and plugin integrations work on mobile
|
||||
return true; // ICS subscriptions are always available
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the settings tab is hidden/closed.
|
||||
* Flushes any pending debounced saves to ensure settings are persisted.
|
||||
*/
|
||||
hide(): void {
|
||||
this.debouncedSave.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -365,20 +365,36 @@ export function createListHeaders(
|
|||
return headersRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounced function interface with flush capability
|
||||
*/
|
||||
export interface DebouncedFunction<T extends (...args: any[]) => any> {
|
||||
(...args: Parameters<T>): void;
|
||||
/** Immediately execute any pending debounced call */
|
||||
flush: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debounce function for reducing save calls
|
||||
* Returns a debounced function with a flush() method to immediately execute pending calls
|
||||
*/
|
||||
export function debounce<T extends (...args: any[]) => any>(
|
||||
func: T,
|
||||
wait: number,
|
||||
immediate = false
|
||||
): (...args: Parameters<T>) => void {
|
||||
): DebouncedFunction<T> {
|
||||
let timeout: ReturnType<typeof setTimeout> | undefined;
|
||||
let lastArgs: Parameters<T> | undefined;
|
||||
let lastThis: any;
|
||||
|
||||
const debounced = function (this: any, ...args: Parameters<T>) {
|
||||
lastArgs = args;
|
||||
lastThis = this;
|
||||
|
||||
return function (this: any, ...args: Parameters<T>) {
|
||||
const later = () => {
|
||||
timeout = undefined;
|
||||
if (!immediate) func.apply(this, args);
|
||||
lastArgs = undefined;
|
||||
if (!immediate) func.apply(lastThis, args);
|
||||
};
|
||||
|
||||
const callNow = immediate && !timeout;
|
||||
|
|
@ -386,5 +402,16 @@ export function debounce<T extends (...args: any[]) => any>(
|
|||
timeout = setTimeout(later, wait);
|
||||
|
||||
if (callNow) func.apply(this, args);
|
||||
} as DebouncedFunction<T>;
|
||||
|
||||
debounced.flush = () => {
|
||||
if (timeout && lastArgs) {
|
||||
clearTimeout(timeout);
|
||||
timeout = undefined;
|
||||
func.apply(lastThis, lastArgs);
|
||||
lastArgs = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
return debounced;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -270,13 +270,13 @@ function renderPriorityList(
|
|||
},
|
||||
});
|
||||
|
||||
valueInput.addEventListener("change", () => {
|
||||
valueInput.addEventListener("input", () => {
|
||||
priority.value = valueInput.value;
|
||||
save();
|
||||
if (onPrioritiesChanged) onPrioritiesChanged();
|
||||
});
|
||||
|
||||
labelInput.addEventListener("change", () => {
|
||||
labelInput.addEventListener("input", () => {
|
||||
priority.label = labelInput.value;
|
||||
card.querySelector(".tasknotes-settings__card-primary-text")!.textContent =
|
||||
priority.label || priority.value || "untitled";
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ function renderStatusList(
|
|||
statusCard = createCard(container, cardConfig);
|
||||
updateDelayInputVisibility();
|
||||
|
||||
valueInput.addEventListener("change", () => {
|
||||
valueInput.addEventListener("input", () => {
|
||||
status.value = valueInput.value;
|
||||
statusCard.querySelector(".tasknotes-settings__card-primary-text")!.textContent =
|
||||
status.value || "untitled";
|
||||
|
|
@ -352,7 +352,7 @@ function renderStatusList(
|
|||
if (onStatusesChanged) onStatusesChanged();
|
||||
});
|
||||
|
||||
labelInput.addEventListener("change", () => {
|
||||
labelInput.addEventListener("input", () => {
|
||||
status.label = labelInput.value;
|
||||
statusCard.querySelector(".tasknotes-settings__card-secondary-text")!.textContent =
|
||||
status.label || "No label";
|
||||
|
|
|
|||
Loading…
Reference in a new issue