Files

62 lines
2.5 KiB
JavaScript

import { DEFAULT_SETTINGS, OPEN_IN_VALUES } from "./defaults.js";
export function normalizeLanguage(value) {
if (typeof value !== "string") return "";
const trimmed = value.trim();
return [...trimmed].length <= 100 && !/[\r\n\x00-\x1f]/u.test(trimmed) ? trimmed : "";
}
// Pure. Layers stored values over the defaults, dropping unknown keys and
// falling back on wrong types or out-of-range values. A fresh or signed-out
// profile returns {} from storage, which yields the defaults.
export function mergeSettings(stored) {
const merged = { ...DEFAULT_SETTINGS };
if (stored === null || typeof stored !== "object") {
return merged;
}
merged.contextMenuMode = ["off", "simple", "advanced"].includes(stored.contextMenuMode)
? stored.contextMenuMode : stored.showContextMenu === false ? "off" : "simple";
if (typeof stored.showTranslate === "boolean") merged.showTranslate = stored.showTranslate;
if (["ask", "preferred"].includes(stored.translationMode)) merged.translationMode = stored.translationMode;
merged.translationLanguage = normalizeLanguage(stored.translationLanguage);
if (typeof stored.temporaryChat === "boolean") {
merged.temporaryChat = stored.temporaryChat;
}
if (typeof stored.webSearch === "boolean") {
merged.webSearch = stored.webSearch;
}
if (OPEN_IN_VALUES.includes(stored.openIn)) {
merged.openIn = stored.openIn;
}
if (typeof stored.promptTemplate === "string") {
merged.promptTemplate = stored.promptTemplate;
}
return merged;
}
// storage.sync works with no Mozilla account (it behaves as local storage and
// syncs later if the user signs in), so no capability probe is needed. Any
// rejection falls back to defaults rather than blocking the user's action.
// Firefox sanitises all non-quota backend errors to a single generic string, so
// there is nothing useful to branch on.
export async function load() {
try {
const stored = await browser.storage.sync.get([...Object.keys(DEFAULT_SETTINGS), "showContextMenu"]);
return mergeSettings(stored);
} catch {
return mergeSettings(null);
}
}
export async function save(partial) {
const normalized = mergeSettings(partial);
const patch = {};
if (partial && typeof partial === "object") {
for (const key of Object.keys(DEFAULT_SETTINGS)) {
if (Object.hasOwn(partial, key)) patch[key] = normalized[key];
}
if (Object.hasOwn(partial, "showContextMenu")) patch.contextMenuMode = normalized.contextMenuMode;
}
await browser.storage.sync.set(patch);
}