@@ -1554,6 +1679,74 @@
}
});
});
+
+ let authReturnFocus = null;
+
+ function switchAuthMode(mode) {
+ const normalizedMode = mode === 'register' ? 'register' : 'login';
+ const modal = document.getElementById('authModal');
+ const isRegister = normalizedMode === 'register';
+ modal.dataset.mode = normalizedMode;
+ document.getElementById('loginPanel').hidden = isRegister;
+ document.getElementById('registerPanel').hidden = !isRegister;
+ document.getElementById('authLoginStory').hidden = isRegister;
+ document.getElementById('authRegisterStory').hidden = !isRegister;
+ document.getElementById('authLoginBenefits').hidden = isRegister;
+ document.getElementById('authRegisterBenefits').hidden = !isRegister;
+ modal.setAttribute('aria-labelledby', isRegister ? 'registerDialogTitle' : 'authDialogTitle');
+ requestAnimationFrame(() => {
+ const firstField = document.querySelector(isRegister ? '#registerForm input' : '#loginForm input');
+ if (firstField) firstField.focus();
+ });
+ }
+
+ function openAuthModal(mode) {
+ const modal = document.getElementById('authModal');
+ authReturnFocus = document.activeElement;
+ modal.hidden = false;
+ modal.setAttribute('aria-hidden', 'false');
+ document.body.classList.add('auth-modal-open');
+ switchAuthMode(mode);
+ }
+
+ function closeAuthModal() {
+ const modal = document.getElementById('authModal');
+ if (modal.hidden) return;
+ modal.hidden = true;
+ modal.setAttribute('aria-hidden', 'true');
+ document.body.classList.remove('auth-modal-open');
+ if (authReturnFocus && typeof authReturnFocus.focus === 'function') authReturnFocus.focus();
+ }
+
+ document.getElementById('authModal').addEventListener('keydown', function(event) {
+ if (event.key === 'Escape') { closeAuthModal(); return; }
+ if (event.key !== 'Tab') return;
+ const focusable = [...this.querySelectorAll('button:not([hidden]), input:not([hidden])')]
+ .filter(element => !element.closest('[hidden]') && !element.disabled && element.offsetParent !== null);
+ if (!focusable.length) return;
+ const first = focusable[0];
+ const last = focusable[focusable.length - 1];
+ if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
+ else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
+ });
+
+ document.getElementById('loginForm').addEventListener('submit', function(event) {
+ event.preventDefault();
+ isLoggedIn = true;
+ updateAuthUI();
+ closeAuthModal();
+ showToast(t('toast_login_ok'));
+ setTimeout(() => { window.location.href = 'workbench.html'; }, 700);
+ });
+
+ document.getElementById('registerForm').addEventListener('submit', function(event) {
+ event.preventDefault();
+ isLoggedIn = true;
+ updateAuthUI();
+ closeAuthModal();
+ showToast(t('toast_register_ok'));
+ setTimeout(() => { window.location.href = 'workbench.html'; }, 700);
+ });
// 退出登录
function doLogout() {
diff --git a/悦/官网头程下单/tests/address-selection.test.js b/悦/官网头程下单/tests/address-selection.test.js
new file mode 100644
index 0000000..567390f
--- /dev/null
+++ b/悦/官网头程下单/tests/address-selection.test.js
@@ -0,0 +1,67 @@
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const vm = require('node:vm');
+
+const html = fs.readFileSync('workbench.html', 'utf8');
+
+function extractFunction(name) {
+ const start = html.indexOf(`function ${name}(`);
+ assert.notEqual(start, -1, `${name} should exist`);
+ const bodyStart = html.indexOf('{', start);
+ let depth = 0;
+ for (let index = bodyStart; index < html.length; index += 1) {
+ if (html[index] === '{') depth += 1;
+ if (html[index] === '}') depth -= 1;
+ if (depth === 0) return html.slice(start, index + 1);
+ }
+ throw new Error(`Unable to extract ${name}`);
+}
+
+assert.match(html, /
地址名称<\/th>/);
+assert.match(html, / |