diff --git a/options/options.html b/options/options.html
index cebdd4a..07f9e8d 100644
--- a/options/options.html
+++ b/options/options.html
@@ -1,3 +1,4 @@
+
diff --git a/options/options.js b/options/options.js
index 3afa0a7..bd244f7 100644
--- a/options/options.js
+++ b/options/options.js
@@ -14,11 +14,19 @@ let applying = false;
function render(settings) {
applying = true;
- field("model").value = settings.model;
- field("temporaryChat").checked = settings.temporaryChat;
- field("webSearch").checked = settings.webSearch;
- field("openIn").value = settings.openIn;
- field("promptTemplate").value = settings.promptTemplate;
+ 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;
}
@@ -69,12 +77,18 @@ for (const id of Object.keys(DEFAULT_SETTINGS)) {
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 });
});
-// A remote sync landing while the panel is open must update the controls rather
-// than being clobbered by stale field values on the next edit.
+// 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;