mirror of
https://git.zavage.net/Zavage-Software/search-with-chatgpt-powered-by-openai-extension.git
synced 2026-08-10 13:40:29 -06:00
98 lines
2.9 KiB
JavaScript
98 lines
2.9 KiB
JavaScript
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;
|
|
// Suppresses the change/input handlers while we are programmatically writing
|
|
// values into the form, so a remote sync cannot trigger a save loop.
|
|
let applying = false;
|
|
|
|
function render(settings) {
|
|
applying = true;
|
|
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;
|
|
}
|
|
}
|
|
applying = false;
|
|
}
|
|
|
|
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() {
|
|
if (applying) {
|
|
return;
|
|
}
|
|
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());
|
|
});
|