/** * 添加配置表单:表单字段、草稿持久化(弹窗关闭后不丢失)、 * 添加按钮提交、"填入当前域名"按钮。 */ import { t } from "../i18n.js"; import { resolveAlias } from "../ui-utils.js"; import type { DomainConfig } from "../types.js"; import { $ } from "./dom"; import type { PopupCtx } from "./context"; const domainInput = $("domain"); const aliasInput = $("alias"); const usernameInput = $("username"); const passwordInput = $("password"); const autoSubmitSelect = $("autoSubmit"); const enabledCheckbox = $("enabled"); const delayMsInput = $("delayMs"); const usernameSelectorInput = $("usernameSelector"); const passwordSelectorInput = $("passwordSelector"); const submitSelectorInput = $("submitSelector"); const addBtn = $("addBtn"); const fillDomainBtn = $("fillDomain"); const DRAFT_KEY = "formDraft"; const draftFields = [ domainInput, aliasInput, usernameInput, passwordInput, autoSubmitSelect, usernameSelectorInput, passwordSelectorInput, submitSelectorInput, enabledCheckbox, delayMsInput, ]; export function initConfigForm(ctx: PopupCtx) { function saveDraft() { const draft = { domain: domainInput.value, alias: aliasInput.value, username: usernameInput.value, password: passwordInput.value, autoSubmit: autoSubmitSelect.value, usernameSelector: usernameSelectorInput.value, passwordSelector: passwordSelectorInput.value, submitSelector: submitSelectorInput.value, enabled: enabledCheckbox.checked, delayMs: delayMsInput.value, }; chrome.storage.local.set({ [DRAFT_KEY]: draft }); } async function loadDraft() { const data = await chrome.storage.local.get(DRAFT_KEY); const draft = data[DRAFT_KEY]; if (!draft) return; domainInput.value = draft.domain || ""; aliasInput.value = draft.alias || ""; usernameInput.value = draft.username || ""; passwordInput.value = draft.password || ""; autoSubmitSelect.value = draft.autoSubmit || "true"; usernameSelectorInput.value = draft.usernameSelector || ""; passwordSelectorInput.value = draft.passwordSelector || ""; submitSelectorInput.value = draft.submitSelector || ""; enabledCheckbox.checked = draft.enabled !== false; delayMsInput.value = draft.delayMs || ""; addBtn.textContent = t("addConfigBtn"); } function clearDraft() { chrome.storage.local.remove(DRAFT_KEY); } function resetForm() { domainInput.value = ""; aliasInput.value = ""; usernameInput.value = ""; passwordInput.value = ""; autoSubmitSelect.value = "true"; usernameSelectorInput.value = ""; passwordSelectorInput.value = ""; submitSelectorInput.value = ""; enabledCheckbox.checked = true; delayMsInput.value = ""; addBtn.textContent = t("addConfigBtn"); clearDraft(); } // 表单内容实时存入草稿,弹窗关闭后不丢失 draftFields.forEach((el) => { el.addEventListener("input", saveDraft); el.addEventListener("change", saveDraft); }); addBtn.addEventListener("click", async () => { const domain = domainInput.value.trim(); const username = usernameInput.value.trim(); const password = passwordInput.value; if (!domain || !username || !password) { ctx.showToast(t("toastRequired")); return; } // 申请站点访问权限必须紧跟用户手势,因此放在其它 await 之前 const authorized = await Perms.requestForDomain(domain); const config: DomainConfig = { id: EnvStore.genCfgId(), domain, alias: aliasInput.value.trim() || (await resolveAlias(domain)) || null, username, password, autoSubmit: autoSubmitSelect.value === "true", usernameSelector: usernameSelectorInput.value.trim() || null, passwordSelector: passwordSelectorInput.value.trim() || null, submitSelector: submitSelectorInput.value.trim() || null, enabled: enabledCheckbox.checked, delayMs: delayMsInput.value ? Number(delayMsInput.value) : null, }; const configs = await EnvStore.loadConfigs(); configs.push(config); ctx.showToast(authorized ? t("toastAdded") : t("toastUnauthorized")); await EnvStore.saveConfigs(configs); resetForm(); ctx.renderConfigList(); ctx.renderEnvSelect(); ctx.refreshEnvManage(); }); // 填入当前标签页域名 fillDomainBtn.addEventListener("click", async () => { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab) { ctx.showToast(t("toastNoTab")); return; } if (!tab.url) { // 未授权时读不到地址:提示用户点扩展图标重新授予 activeTab ctx.showToast(t("toastNoTabUrl")); return; } try { const u = new URL(tab.url); const host = u.host; if (!host) { ctx.showToast(t("toastNoDomain")); return; } const value = u.pathname && u.pathname !== "/" ? host + u.pathname : host; domainInput.value = value; if (tab.title) aliasInput.value = tab.title; saveDraft(); ctx.showToast(t("toastDomainFilled", value)); } catch { ctx.showToast(t("toastUrlParseFail")); } }); return { resetForm, saveDraft, loadDraft }; }