import { DEFAULT_SETTINGS } from "../lib/defaults.js"; import { load, save } from "../lib/settings.js"; const SAVE_DEBOUNCE_MS = 400; const STATUS_CLEAR_MS = 1500; const field = (id) => document.getElementById(id); let saveTimer = null; let statusTimer = null; function render(settings) { for (const [id, value] of Object.entries(settings)) { const element = field(id); // Never overwrite the control the user is actively editing — this page's // own saves echo back through storage.onChanged (see below). if (element === document.activeElement) { continue; } if (typeof value === "boolean") { element.checked = value; } else { element.value = value; } } } function collect() { return { model: field("model").value, temporaryChat: field("temporaryChat").checked, webSearch: field("webSearch").checked, openIn: field("openIn").value, promptTemplate: field("promptTemplate").value, }; } function showStatus(message) { field("status").textContent = message; clearTimeout(statusTimer); statusTimer = setTimeout(() => { field("status").textContent = ""; }, STATUS_CLEAR_MS); } async function persist(settings) { try { await save(settings); showStatus("Saved"); } catch { // storage.sync sanitises its errors, so there is nothing specific to report. showStatus("Could not save settings"); } } // Debounced so typing in a text field cannot approach any write-rate quota. function scheduleSave() { clearTimeout(saveTimer); saveTimer = setTimeout(() => persist(collect()), SAVE_DEBOUNCE_MS); } // Module scripts are deferred, so the DOM is already parsed here. render(await load()); for (const id of Object.keys(DEFAULT_SETTINGS)) { field(id).addEventListener("input", scheduleSave); field(id).addEventListener("change", scheduleSave); } field("restore").addEventListener("click", () => { clearTimeout(saveTimer); // Restoring defaults is an explicit user action, so it should reset every // field even if one currently has focus. Blur first so render()'s // activeElement guard (see below) has nothing to skip. document.activeElement?.blur(); render(DEFAULT_SETTINGS); persist({ ...DEFAULT_SETTINGS }); }); // browser.storage.onChanged fires for every write to the "sync" area, not just // a remote sync landing on another device — this page's own debounced // autosaves and its Restore-defaults save re-enter this listener too, which // render()'s activeElement guard makes safe to react to unconditionally. browser.storage.onChanged.addListener(async (changes, area) => { if (area !== "sync") { return; } render(await load()); });