Merge remote-tracking branch 'origin/master'

# Conflicts:
#	content/signup-page.js
#	tests/step6-login-state.test.js
This commit is contained in:
sh2001sh
2026-04-22 10:06:10 +08:00
42 changed files with 3209 additions and 478 deletions
+58
View File
@@ -0,0 +1,58 @@
(function attachSidepanelAccountPoolUi(globalScope) {
function createAccountPoolFormController(options = {}) {
const {
formShell = null,
toggleButton = null,
hiddenLabel = '添加账号',
visibleLabel = '取消添加',
onClear = null,
onFocus = null,
} = options;
let visible = false;
function sync() {
if (formShell) {
formShell.hidden = !visible;
}
if (toggleButton) {
toggleButton.textContent = visible ? visibleLabel : hiddenLabel;
toggleButton.setAttribute('aria-expanded', String(visible));
}
}
function setVisible(nextVisible, controlOptions = {}) {
const {
clearForm = false,
focusField = false,
} = controlOptions;
visible = Boolean(nextVisible);
if (clearForm && typeof onClear === 'function') {
onClear();
}
sync();
if (visible && focusField && typeof onFocus === 'function') {
onFocus();
}
}
function isVisible() {
return visible;
}
sync();
return {
isVisible,
setVisible,
sync,
};
}
globalScope.SidepanelAccountPoolUi = {
createAccountPoolFormController,
};
})(window);
+30 -1
View File
@@ -12,6 +12,7 @@
const expandedStorageKey = constants.expandedStorageKey || 'multipage-hotmail-list-expanded';
const displayTimeZone = constants.displayTimeZone || 'Asia/Shanghai';
const copyIcon = constants.copyIcon || '';
const createAccountPoolFormController = globalScope.SidepanelAccountPoolUi?.createAccountPoolFormController;
let actionInFlight = false;
let listExpanded = false;
@@ -177,6 +178,25 @@
dom.inputHotmailRefreshToken.value = '';
}
const formController = typeof createAccountPoolFormController === 'function'
? createAccountPoolFormController({
formShell: dom.hotmailFormShell,
toggleButton: dom.btnToggleHotmailForm,
hiddenLabel: '添加账号',
visibleLabel: '取消添加',
onClear: () => {
clearHotmailForm();
},
onFocus: () => {
dom.inputHotmailEmail?.focus?.();
},
})
: {
isVisible: () => false,
setVisible() {},
sync() {},
};
function renderHotmailAccounts() {
if (!dom.hotmailAccountsList) return;
const latestState = state.getLatestState();
@@ -318,7 +338,7 @@
}
helpers.showToast(`已保存 Hotmail 账号 ${email}`, 'success', 1800);
clearHotmailForm();
formController.setVisible(false, { clearForm: true });
} catch (err) {
helpers.showToast(`保存 Hotmail 账号失败:${err.message}`, 'error');
} finally {
@@ -474,6 +494,14 @@
setHotmailListExpanded(!listExpanded);
});
dom.btnToggleHotmailForm?.addEventListener('click', () => {
if (formController.isVisible()) {
formController.setVisible(false, { clearForm: true });
return;
}
formController.setVisible(true, { focusField: true });
});
dom.btnHotmailUsageGuide?.addEventListener('click', async () => {
await helpers.openConfirmModal({
title: '使用教程',
@@ -514,6 +542,7 @@
dom.btnAddHotmailAccount?.addEventListener('click', handleAddHotmailAccount);
dom.btnImportHotmailAccounts?.addEventListener('click', handleImportHotmailAccounts);
dom.hotmailAccountsList?.addEventListener('click', handleAccountListClick);
formController.sync();
}
return {
+33 -9
View File
@@ -12,6 +12,7 @@
const expandedStorageKey = constants.expandedStorageKey || 'multipage-mail2925-list-expanded';
const displayTimeZone = constants.displayTimeZone || 'Asia/Shanghai';
const copyIcon = constants.copyIcon || '';
const createAccountPoolFormController = globalScope.SidepanelAccountPoolUi?.createAccountPoolFormController;
let actionInFlight = false;
let listExpanded = false;
@@ -118,13 +119,29 @@
if (dom.inputMail2925Password) dom.inputMail2925Password.value = '';
}
const formController = typeof createAccountPoolFormController === 'function'
? createAccountPoolFormController({
formShell: dom.mail2925FormShell,
toggleButton: dom.btnToggleMail2925Form,
hiddenLabel: '添加账号',
visibleLabel: '取消添加',
onClear: () => {
stopEditingAccount({ clearForm: true });
},
onFocus: () => {
dom.inputMail2925Email?.focus?.();
},
})
: {
isVisible: () => false,
setVisible() {},
sync() {},
};
function syncEditUi() {
if (dom.btnAddMail2925Account) {
dom.btnAddMail2925Account.textContent = editingAccountId ? '保存修改' : '添加账号';
}
if (dom.btnCancelMail2925Edit) {
dom.btnCancelMail2925Edit.style.display = editingAccountId ? '' : 'none';
}
}
function startEditingAccount(account) {
@@ -132,6 +149,7 @@
editingAccountId = account.id;
if (dom.inputMail2925Email) dom.inputMail2925Email.value = String(account.email || '').trim();
if (dom.inputMail2925Password) dom.inputMail2925Password.value = String(account.password || '');
formController.setVisible(true, { focusField: false });
syncEditUi();
}
@@ -234,7 +252,7 @@
}
applyMail2925AccountMutation(response.account);
stopEditingAccount();
formController.setVisible(false, { clearForm: true });
helpers.showToast(
updatingExisting
? `已更新 2925 账号 ${email}`
@@ -332,7 +350,7 @@
mail2925Accounts: [],
currentMail2925AccountId: null,
});
stopEditingAccount();
formController.setVisible(false, { clearForm: true });
refreshManagedAliasBaseEmail();
renderMail2925Accounts();
helpers.showToast(`已删除全部 ${response.deletedCount || 0} 个 2925 账号`, 'success', 2200);
@@ -460,7 +478,7 @@
}
state.syncLatestState(nextState);
if (editingAccountId === accountId) {
stopEditingAccount();
formController.setVisible(false, { clearForm: true });
}
refreshManagedAliasBaseEmail();
renderMail2925Accounts();
@@ -479,6 +497,14 @@
setMail2925ListExpanded(!listExpanded);
});
dom.btnToggleMail2925Form?.addEventListener('click', () => {
if (formController.isVisible()) {
formController.setVisible(false, { clearForm: true });
return;
}
formController.setVisible(true, { clearForm: !editingAccountId, focusField: true });
});
dom.btnDeleteAllMail2925Accounts?.addEventListener('click', async () => {
if (actionInFlight) return;
actionInFlight = true;
@@ -493,12 +519,10 @@
});
dom.btnAddMail2925Account?.addEventListener('click', handleAddMail2925Account);
dom.btnCancelMail2925Edit?.addEventListener('click', () => {
stopEditingAccount();
});
dom.btnImportMail2925Accounts?.addEventListener('click', handleImportMail2925Accounts);
dom.mail2925AccountsList?.addEventListener('click', handleAccountListClick);
syncEditUi();
formController.sync();
}
return {
+28 -12
View File
@@ -243,33 +243,35 @@ header {
color: var(--orange);
}
.contribution-entry {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 6px;
position: relative;
.contribution-update-layer {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 1400;
}
.contribution-update-hint {
position: relative;
--contribution-update-arrow-left: 20px;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: flex-start;
gap: 8px;
max-width: 220px;
margin-left: 6px;
max-width: min(220px, calc(100vw - 24px));
padding: 8px 10px;
background: color-mix(in srgb, var(--amber) 10%, var(--bg-base));
border: 1px solid color-mix(in srgb, var(--amber) 34%, var(--border));
border-radius: 10px;
box-shadow: var(--shadow-sm);
pointer-events: auto;
}
.contribution-update-hint::before {
content: '';
position: absolute;
top: -7px;
left: 14px;
left: calc(var(--contribution-update-arrow-left) - 6px);
width: 12px;
height: 12px;
background: inherit;
@@ -436,7 +438,7 @@ header {
.run-group {
display: flex;
align-items: flex-start;
align-items: center;
gap: 4px;
flex-wrap: wrap;
}
@@ -1112,6 +1114,20 @@ header {
visibility: hidden;
}
.account-pool-form-shell {
display: flex;
flex-direction: column;
gap: 10px;
}
.account-pool-actions-inline {
width: 100%;
}
.account-pool-import-action {
margin-left: auto;
}
.hotmail-import-row {
align-items: flex-start;
}
@@ -1134,7 +1150,7 @@ header {
}
.hotmail-list-shell.is-collapsed {
max-height: 236px;
max-height: 176px;
}
.hotmail-list-shell.is-expanded {
+80 -66
View File
@@ -34,18 +34,9 @@
</div>
<div class="header-btns">
<div class="run-group">
<div class="contribution-entry">
<button id="btn-contribution-mode" class="btn btn-outline btn-sm btn-contribution-mode" type="button"
aria-pressed="false" title="进入贡献模式并打开上传页">贡献/使用</button>
<div id="contribution-update-hint" class="contribution-update-hint" aria-live="polite" hidden>
<p id="contribution-update-hint-text" class="contribution-update-hint-text">
公告 / 使用教程有更新了,可点上方“贡献/使用”查看。
</p>
<button id="btn-dismiss-contribution-update-hint" class="contribution-update-hint-close" type="button"
aria-label="关闭更新提示" title="关闭更新提示">×</button>
</div>
</div>
<input type="number" id="input-run-count" class="run-count-input" value="1" min="1" max="50" title="运行次数" />
<button id="btn-contribution-mode" class="btn btn-outline btn-sm btn-contribution-mode" type="button"
aria-pressed="false" title="进入贡献模式并打开上传页">贡献/使用</button>
<input type="number" id="input-run-count" class="run-count-input" value="1" min="1" title="运行次数" />
<button id="btn-auto-run" class="btn btn-success" title="自动执行全部步骤">
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
<polygon points="5 3 19 12 5 21 5 3" />
@@ -90,6 +81,16 @@
</div>
</header>
<div id="contribution-update-layer" class="contribution-update-layer" hidden>
<div id="contribution-update-hint" class="contribution-update-hint" aria-live="polite" hidden>
<p id="contribution-update-hint-text" class="contribution-update-hint-text">
公告 / 使用教程有更新了,可点上方“贡献/使用”查看。
</p>
<button id="btn-dismiss-contribution-update-hint" class="contribution-update-hint-close" type="button"
aria-label="关闭更新提示" title="关闭更新提示">×</button>
</div>
</div>
<section id="update-section" hidden>
<div class="update-card">
<div class="update-card-header">
@@ -268,20 +269,25 @@
<button id="btn-cf-domain-mode" class="btn btn-outline btn-sm data-inline-btn" type="button">添加</button>
</div>
</div>
<div class="data-row" id="row-email-prefix" style="display:none;">
<span class="data-label" id="label-email-prefix">别名基邮箱</span>
<div class="data-row" id="row-mail2925-pool-settings" style="display:none;">
<span class="data-label">2925 号池</span>
<div class="data-inline mail2925-base-inline">
<input type="text" id="input-email-prefix" class="data-input mail2925-base-input" placeholder="例如 yourname@example.com" />
<select id="select-mail2925-pool-account" class="data-select mail2925-pool-select" style="display:none;">
<option value="">请选择号池邮箱</option>
</select>
<label class="toggle-switch mail2925-pool-toggle" id="label-mail2925-use-account-pool" for="input-mail2925-use-account-pool" style="display:none;" title="开启后只能从号池中选择 2925 基邮箱">
<label class="toggle-switch mail2925-pool-toggle" id="label-mail2925-use-account-pool" for="input-mail2925-use-account-pool" style="display:none;" title="开启后启用 2925 账号池">
<input type="checkbox" id="input-mail2925-use-account-pool" />
<span class="toggle-switch-track" aria-hidden="true">
<span class="toggle-switch-thumb"></span>
</span>
<span>号池</span>
</label>
<select id="select-mail2925-pool-account" class="data-select mail2925-pool-select" style="display:none;">
<option value="">请选择号池邮箱</option>
</select>
</div>
</div>
<div class="data-row" id="row-email-prefix" style="display:none;">
<span class="data-label" id="label-email-prefix">别名基邮箱</span>
<div class="data-inline">
<input type="text" id="input-email-prefix" class="data-input mail2925-base-input" placeholder="例如 yourname@example.com" />
</div>
</div>
<div class="data-row" id="row-inbucket-host" style="display:none;">
@@ -403,6 +409,7 @@
<span class="section-label">Hotmail 账号池</span>
</div>
<div class="section-mini-actions">
<button id="btn-toggle-hotmail-form" class="btn btn-outline btn-xs" type="button" aria-expanded="false">添加账号</button>
<button id="btn-hotmail-usage-guide" class="btn btn-ghost btn-xs" type="button">使用教程</button>
<button id="btn-clear-used-hotmail-accounts" class="btn btn-ghost btn-xs" type="button">清空已用</button>
<button id="btn-delete-all-hotmail-accounts" class="btn btn-ghost btn-xs" type="button">全部删除</button>
@@ -425,33 +432,37 @@
<span class="data-label">本地助手</span>
<input type="text" id="input-hotmail-local-base-url" class="data-input mono" placeholder="http://127.0.0.1:17373" />
</div>
<div class="data-row">
<span class="data-label">邮箱</span>
<input type="text" id="input-hotmail-email" class="data-input" placeholder="name@hotmail.com" />
</div>
<div class="data-row">
<span class="data-label">客户端 ID</span>
<input type="text" id="input-hotmail-client-id" class="data-input mono" placeholder="微软应用客户端 ID" />
</div>
<div class="data-row">
<span class="data-label">邮箱密码</span>
<input type="password" id="input-hotmail-password" class="data-input" placeholder="可选,仅用于记录" />
</div>
<div class="data-row">
<span class="data-label">刷新令牌</span>
<input type="password" id="input-hotmail-refresh-token" class="data-input mono"
placeholder="必填,粘贴刷新令牌(refresh token" />
</div>
<div class="data-row hotmail-actions-row">
<span class="data-label"></span>
<button id="btn-add-hotmail-account" class="btn btn-primary btn-sm" type="button">添加账号</button>
</div>
<div class="data-row hotmail-import-row">
<span class="data-label">批量导入</span>
<div class="hotmail-import-box">
<textarea id="input-hotmail-import" class="data-textarea mono"
placeholder="账号----密码----客户端ID----刷新令牌&#10;name@hotmail.com----password----client-id----refresh-token"></textarea>
<button id="btn-import-hotmail-accounts" class="btn btn-outline btn-sm" type="button">导入</button>
<div id="hotmail-form-shell" class="account-pool-form-shell" hidden>
<div class="data-row">
<span class="data-label">邮箱</span>
<input type="text" id="input-hotmail-email" class="data-input" placeholder="name@hotmail.com" />
</div>
<div class="data-row">
<span class="data-label">客户端 ID</span>
<input type="text" id="input-hotmail-client-id" class="data-input mono" placeholder="微软应用客户端 ID" />
</div>
<div class="data-row">
<span class="data-label">邮箱密码</span>
<input type="password" id="input-hotmail-password" class="data-input" placeholder="可选,仅用于记录" />
</div>
<div class="data-row">
<span class="data-label">刷新令牌</span>
<input type="password" id="input-hotmail-refresh-token" class="data-input mono"
placeholder="必填,粘贴刷新令牌(refresh token" />
</div>
<div class="data-row hotmail-actions-row">
<span class="data-label"></span>
<div class="data-inline account-pool-actions-inline">
<button id="btn-add-hotmail-account" class="btn btn-primary btn-sm" type="button">添加账号</button>
<button id="btn-import-hotmail-accounts" class="btn btn-outline btn-sm account-pool-import-action" type="button">批量导入</button>
</div>
</div>
<div class="data-row hotmail-import-row">
<span class="data-label">批量导入</span>
<div class="hotmail-import-box">
<textarea id="input-hotmail-import" class="data-textarea mono"
placeholder="账号----密码----客户端ID----刷新令牌&#10;name@hotmail.com----password----client-id----refresh-token"></textarea>
</div>
</div>
</div>
<div id="hotmail-list-shell" class="hotmail-list-shell is-collapsed">
@@ -464,31 +475,33 @@
<span class="section-label">2925 账号池</span>
</div>
<div class="section-mini-actions">
<button id="btn-toggle-mail2925-form" class="btn btn-outline btn-xs" type="button" aria-expanded="false">添加账号</button>
<button id="btn-delete-all-mail2925-accounts" class="btn btn-ghost btn-xs" type="button">全部删除</button>
<button id="btn-toggle-mail2925-list" class="btn btn-ghost btn-xs" type="button" aria-expanded="false">展开列表</button>
</div>
</div>
<div class="data-row">
<span class="data-label">邮箱</span>
<input type="text" id="input-mail2925-email" class="data-input" placeholder="name@2925.com" />
</div>
<div class="data-row">
<span class="data-label">密码</span>
<input type="password" id="input-mail2925-password" class="data-input" placeholder="2925 登录密码" />
</div>
<div class="data-row hotmail-actions-row">
<span class="data-label"></span>
<div class="data-inline">
<button id="btn-add-mail2925-account" class="btn btn-primary btn-sm" type="button">添加账号</button>
<button id="btn-cancel-mail2925-edit" class="btn btn-outline btn-sm" type="button" style="display:none;">取消编辑</button>
<div id="mail2925-form-shell" class="account-pool-form-shell" hidden>
<div class="data-row">
<span class="data-label">邮箱</span>
<input type="text" id="input-mail2925-email" class="data-input" placeholder="name@2925.com" />
</div>
</div>
<div class="data-row hotmail-import-row">
<span class="data-label">批量导入</span>
<div class="hotmail-import-box">
<textarea id="input-mail2925-import" class="data-textarea mono"
placeholder="邮箱----密码&#10;name@2925.com----password"></textarea>
<button id="btn-import-mail2925-accounts" class="btn btn-outline btn-sm" type="button">导入</button>
<div class="data-row">
<span class="data-label">密码</span>
<input type="password" id="input-mail2925-password" class="data-input" placeholder="2925 登录密码" />
</div>
<div class="data-row hotmail-actions-row">
<span class="data-label"></span>
<div class="data-inline account-pool-actions-inline">
<button id="btn-add-mail2925-account" class="btn btn-primary btn-sm" type="button">添加账号</button>
<button id="btn-import-mail2925-accounts" class="btn btn-outline btn-sm account-pool-import-action" type="button">批量导入</button>
</div>
</div>
<div class="data-row hotmail-import-row">
<span class="data-label">批量导入</span>
<div class="hotmail-import-box">
<textarea id="input-mail2925-import" class="data-textarea mono"
placeholder="邮箱----密码&#10;name@2925.com----password"></textarea>
</div>
</div>
</div>
<div id="mail2925-list-shell" class="hotmail-list-shell is-collapsed">
@@ -734,6 +747,7 @@
<script src="../data/step-definitions.js"></script>
<script src="update-service.js"></script>
<script src="contribution-content-update-service.js"></script>
<script src="account-pool-ui.js"></script>
<script src="hotmail-manager.js"></script>
<script src="mail-2925-manager.js"></script>
<script src="icloud-manager.js"></script>
+122 -29
View File
@@ -57,6 +57,7 @@ const btnSaveSettings = document.getElementById('btn-save-settings');
const btnStop = document.getElementById('btn-stop');
const btnReset = document.getElementById('btn-reset');
const btnContributionMode = document.getElementById('btn-contribution-mode');
const contributionUpdateLayer = document.getElementById('contribution-update-layer');
const contributionUpdateHint = document.getElementById('contribution-update-hint');
const contributionUpdateHintText = document.getElementById('contribution-update-hint-text');
const btnDismissContributionUpdateHint = document.getElementById('btn-dismiss-contribution-update-hint');
@@ -97,6 +98,7 @@ const rowCustomPassword = document.getElementById('row-custom-password');
const selectMailProvider = document.getElementById('select-mail-provider');
const btnMailLogin = document.getElementById('btn-mail-login');
const rowMail2925Mode = document.getElementById('row-mail-2925-mode');
const rowMail2925PoolSettings = document.getElementById('row-mail2925-pool-settings');
const mail2925ModeButtons = Array.from(document.querySelectorAll('[data-mail2925-mode]'));
const rowEmailGenerator = document.getElementById('row-email-generator');
const selectEmailGenerator = document.getElementById('select-email-generator');
@@ -148,20 +150,23 @@ const inputHotmailRefreshToken = document.getElementById('input-hotmail-refresh-
const inputHotmailImport = document.getElementById('input-hotmail-import');
const btnAddHotmailAccount = document.getElementById('btn-add-hotmail-account');
const btnImportHotmailAccounts = document.getElementById('btn-import-hotmail-accounts');
const btnToggleHotmailForm = document.getElementById('btn-toggle-hotmail-form');
const btnHotmailUsageGuide = document.getElementById('btn-hotmail-usage-guide');
const btnClearUsedHotmailAccounts = document.getElementById('btn-clear-used-hotmail-accounts');
const btnDeleteAllHotmailAccounts = document.getElementById('btn-delete-all-hotmail-accounts');
const btnToggleHotmailList = document.getElementById('btn-toggle-hotmail-list');
const hotmailFormShell = document.getElementById('hotmail-form-shell');
const hotmailListShell = document.getElementById('hotmail-list-shell');
const hotmailAccountsList = document.getElementById('hotmail-accounts-list');
const inputMail2925Email = document.getElementById('input-mail2925-email');
const inputMail2925Password = document.getElementById('input-mail2925-password');
const inputMail2925Import = document.getElementById('input-mail2925-import');
const btnAddMail2925Account = document.getElementById('btn-add-mail2925-account');
const btnCancelMail2925Edit = document.getElementById('btn-cancel-mail2925-edit');
const btnToggleMail2925Form = document.getElementById('btn-toggle-mail2925-form');
const btnImportMail2925Accounts = document.getElementById('btn-import-mail2925-accounts');
const btnDeleteAllMail2925Accounts = document.getElementById('btn-delete-all-mail2925-accounts');
const btnToggleMail2925List = document.getElementById('btn-toggle-mail2925-list');
const mail2925FormShell = document.getElementById('mail2925-form-shell');
const mail2925ListShell = document.getElementById('mail2925-list-shell');
const mail2925AccountsList = document.getElementById('mail2925-accounts-list');
const inputLuckmailApiKey = document.getElementById('input-luckmail-api-key');
@@ -247,8 +252,7 @@ const DEFAULT_MAIL_2925_MODE = MAIL_2925_MODE_PROVIDE;
const AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-skip-failures-prompt-dismissed';
const AUTO_RUN_FALLBACK_RISK_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-run-fallback-risk-prompt-dismissed';
const CONTRIBUTION_CONTENT_PROMPT_DISMISSED_VERSION_STORAGE_KEY = 'multipage-contribution-content-prompt-dismissed-version';
const AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS = 15;
const AUTO_RUN_FALLBACK_RISK_RECOMMENDED_THREAD_INTERVAL_MINUTES = 5;
const AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS = 3;
const HOTMAIL_SERVICE_MODE_REMOTE = 'remote';
const HOTMAIL_SERVICE_MODE_LOCAL = 'local';
const ICLOUD_PROVIDER = 'icloud';
@@ -266,12 +270,24 @@ function getManagedAliasUtils() {
return window.MultiPageManagedAliasUtils || null;
}
function isManagedAliasProvider(provider = selectMailProvider.value) {
function isManagedAliasProvider(provider = selectMailProvider.value, mail2925Mode = getSelectedMail2925Mode()) {
const utils = getManagedAliasUtils();
if (utils?.usesManagedAliasGeneration) {
return utils.usesManagedAliasGeneration(provider, { mail2925Mode });
}
if (utils?.isManagedAliasProvider) {
const normalizedProvider = String(provider || '').trim().toLowerCase();
if (normalizedProvider === '2925') {
return utils.isManagedAliasProvider(provider)
&& normalizeMail2925Mode(mail2925Mode) === MAIL_2925_MODE_PROVIDE;
}
return utils.isManagedAliasProvider(provider);
}
return [GMAIL_PROVIDER, '2925'].includes(String(provider || '').trim().toLowerCase());
const normalizedProvider = String(provider || '').trim().toLowerCase();
if (normalizedProvider === '2925') {
return normalizeMail2925Mode(mail2925Mode) === MAIL_2925_MODE_PROVIDE;
}
return normalizedProvider === GMAIL_PROVIDER;
}
function parseManagedAliasBaseEmail(rawValue, provider = selectMailProvider.value) {
@@ -290,31 +306,34 @@ function isManagedAliasEmail(value, baseEmail = '', provider = selectMailProvide
return false;
}
function getManagedAliasProviderUiCopy(provider = selectMailProvider.value) {
function getManagedAliasProviderUiCopy(provider = selectMailProvider.value, mail2925Mode = getSelectedMail2925Mode()) {
if (!isManagedAliasProvider(provider, mail2925Mode)) {
return null;
}
const utils = getManagedAliasUtils();
if (utils?.getManagedAliasProviderUiCopy) {
return utils.getManagedAliasProviderUiCopy(provider);
}
if (String(provider || '').trim().toLowerCase() === GMAIL_PROVIDER) {
return {
baseLabel: 'Gmail 原邮箱',
baseLabel: '邮箱',
basePlaceholder: '例如 yourname@gmail.com',
buttonLabel: '生成',
successVerb: '生成',
label: 'Gmail +tag 邮箱',
placeholder: '点击生成 Gmail +tag 邮箱,或手动填写完整邮箱',
hint: '先填写 Gmail 原邮箱后点“生成”,也可以直接手动填写完整的 Gmail 邮箱。',
hint: '先填写邮箱后点“生成”,也可以直接手动填写完整的 Gmail 邮箱。',
};
}
if (String(provider || '').trim().toLowerCase() === '2925') {
return {
baseLabel: '2925 基邮箱',
baseLabel: '基邮箱',
basePlaceholder: '例如 yourname@2925.com',
buttonLabel: '生成',
successVerb: '生成',
label: '2925 邮箱',
placeholder: '点击生成 2925 邮箱,或手动填写完整邮箱',
hint: '先填写 2925 基邮箱后点“生成”,也可以直接手动填写完整的 2925 邮箱。',
hint: '先填写基邮箱后点“生成”,也可以直接手动填写完整的 2925 邮箱。',
};
}
return null;
@@ -379,7 +398,10 @@ async function syncSelectedMail2925PoolAccount(options = {}) {
throw new Error(response.error);
}
syncLatestState({ currentMail2925AccountId: response.account?.id || accountId });
syncLatestState({
currentMail2925AccountId: response.account?.id || accountId,
...(response.account?.email ? { mail2925BaseEmail: String(response.account.email).trim() } : {}),
});
setManagedAliasBaseEmailInputForProvider('2925', latestState);
if (!silent) {
showToast(`已切换当前 2925 号池邮箱为 ${response.account?.email || accountId}`, 'success', 1800);
@@ -591,7 +613,7 @@ const LOG_LEVEL_LABELS = {
};
function usesGeneratedAliasMailProvider(provider, mail2925Mode = getSelectedMail2925Mode()) {
return isManagedAliasProvider(provider);
return isManagedAliasProvider(provider, mail2925Mode);
}
function parseGmailBaseEmail(rawValue = '') {
@@ -880,14 +902,10 @@ async function openAutoSkipFailuresConfirmModal() {
};
}
async function openAutoRunFallbackRiskConfirmModal(totalRuns, fallbackThreadIntervalMinutes) {
const intervalLabel = Number.isFinite(fallbackThreadIntervalMinutes)
? `${fallbackThreadIntervalMinutes} 分钟`
: '未设置';
async function openAutoRunFallbackRiskConfirmModal(totalRuns) {
const result = await openConfirmModalWithOption({
title: '自动运行风险提醒',
message: `当前设置为 ${totalRuns} 轮自动化,已开启自动重试,线程间隔为 ${intervalLabel}。轮数过多时,可能会因为 IP 短时间注册过多而集中失败。建议控制在 ${AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS} 轮以下,并将线程间隔设置在 ${AUTO_RUN_FALLBACK_RISK_RECOMMENDED_THREAD_INTERVAL_MINUTES} 分钟以上。是否继续?`,
message: `当前轮数已经不适合单节点情况,请确保已经配置并打开节点轮询功能(若没有配置,请点击贡献/使用按钮,根据网页中使用教程进行配置),避免连续使用一个节点注册,导致出现手机号验证。`,
confirmLabel: '继续',
});
@@ -1162,7 +1180,7 @@ function formatAutoStepDelayInputValue(value) {
}
function getRunCountValue() {
return Math.min(50, Math.max(1, parseInt(inputRunCount.value, 10) || 1));
return Math.max(1, parseInt(inputRunCount.value, 10) || 1);
}
function updateFallbackThreadIntervalInputState() {
@@ -2317,9 +2335,40 @@ function getContributionUpdateHintMessage(snapshot = currentContributionContentS
return '公告 / 使用教程有更新了,可点上方“贡献/使用”查看。';
}
function positionContributionUpdateHint() {
if (!contributionUpdateLayer || !contributionUpdateHint || !btnContributionMode) {
return;
}
if (contributionUpdateLayer.hidden || contributionUpdateHint.hidden) {
return;
}
const buttonRect = btnContributionMode.getBoundingClientRect();
const viewportWidth = Math.max(document.documentElement?.clientWidth || 0, window.innerWidth || 0);
const viewportHeight = Math.max(document.documentElement?.clientHeight || 0, window.innerHeight || 0);
const hintWidth = contributionUpdateHint.offsetWidth || 220;
const hintHeight = contributionUpdateHint.offsetHeight || 56;
const viewportPadding = 12;
const gap = 10;
const maxLeft = Math.max(viewportPadding, viewportWidth - hintWidth - viewportPadding);
const left = Math.min(Math.max(viewportPadding, Math.round(buttonRect.left)), maxLeft);
const shouldPlaceAbove = (buttonRect.bottom + gap + hintHeight) > (viewportHeight - viewportPadding)
&& buttonRect.top > (hintHeight + gap + viewportPadding);
const top = shouldPlaceAbove
? Math.max(viewportPadding, Math.round(buttonRect.top - hintHeight - gap))
: Math.max(viewportPadding, Math.round(buttonRect.bottom + gap));
const buttonCenter = Math.round(buttonRect.left + (buttonRect.width / 2));
const arrowOffset = Math.min(Math.max(16, buttonCenter - left), Math.max(16, hintWidth - 16));
contributionUpdateHint.style.left = `${left}px`;
contributionUpdateHint.style.top = `${top}px`;
contributionUpdateHint.style.setProperty('--contribution-update-arrow-left', `${arrowOffset}px`);
}
function shouldShowContributionUpdateHint(snapshot = currentContributionContentSnapshot) {
const promptVersion = String(snapshot?.promptVersion || '').trim();
if (!contributionUpdateHint || !contributionUpdateHintText || !btnContributionMode) {
if (!contributionUpdateLayer || !contributionUpdateHint || !contributionUpdateHintText || !btnContributionMode) {
return false;
}
if (!promptVersion) {
@@ -2335,17 +2384,23 @@ function shouldShowContributionUpdateHint(snapshot = currentContributionContentS
}
function renderContributionUpdateHint(snapshot = currentContributionContentSnapshot) {
if (!contributionUpdateHint) {
if (!contributionUpdateLayer || !contributionUpdateHint) {
return;
}
const visible = shouldShowContributionUpdateHint(snapshot);
contributionUpdateLayer.hidden = !visible;
contributionUpdateHint.hidden = !visible;
if (!visible || !contributionUpdateHintText) {
return;
}
contributionUpdateHintText.textContent = getContributionUpdateHintMessage(snapshot);
if (typeof window.requestAnimationFrame === 'function') {
window.requestAnimationFrame(() => positionContributionUpdateHint());
return;
}
positionContributionUpdateHint();
}
function dismissContributionUpdateHint() {
@@ -2524,6 +2579,24 @@ function getCurrentMail2925Email(state = latestState) {
return String(getCurrentMail2925Account(state)?.email || '').trim();
}
function syncMail2925BaseEmailFromCurrentAccount(state = latestState, options = {}) {
const { persist = false } = options;
if (!isMail2925AccountPoolEnabled(state)) {
return false;
}
const currentEmail = getCurrentMail2925Email(state);
if (!currentEmail || currentEmail === String(state?.mail2925BaseEmail || '').trim()) {
return false;
}
syncLatestState({ mail2925BaseEmail: currentEmail });
if (persist) {
saveSettings({ silent: true }).catch(() => {});
}
return true;
}
function getCurrentLuckmailPurchase(state = latestState) {
return state?.currentLuckmailPurchase || null;
}
@@ -2674,13 +2747,18 @@ function updateMailProviderUI() {
const useIcloudProvider = isIcloudMailProvider();
const useEmailGenerator = !useHotmail && !useLuckmail && !useGeneratedAlias && !useCustomEmail;
const useCloudflareTempEmailProvider = selectMailProvider.value === 'cloudflare-temp-email';
const aliasUiCopy = useGeneratedAlias ? getManagedAliasProviderUiCopy(selectMailProvider.value) : null;
const aliasUiCopy = useGeneratedAlias
? getManagedAliasProviderUiCopy(selectMailProvider.value, mail2925Mode)
: null;
const uiCopy = getCurrentRegistrationEmailUiCopy();
updateMailLoginButtonState();
if (rowMail2925Mode) {
rowMail2925Mode.style.display = 'none';
rowMail2925Mode.style.display = use2925 ? '' : 'none';
}
rowEmailPrefix.style.display = useGeneratedAlias ? '' : 'none';
if (rowMail2925PoolSettings) {
rowMail2925PoolSettings.style.display = useMail2925 ? '' : 'none';
}
rowEmailPrefix.style.display = useGeneratedAlias && !useMail2925AccountPool ? '' : 'none';
const hotmailServiceMode = getSelectedHotmailServiceMode();
rowInbucketHost.style.display = useInbucket ? '' : 'none';
rowInbucketMailbox.style.display = useInbucket ? '' : 'none';
@@ -2743,8 +2821,8 @@ function updateMailProviderUI() {
selectMail2925PoolAccount.style.display = useMail2925AccountPool ? '' : 'none';
selectMail2925PoolAccount.disabled = !useMail2925AccountPool || getMail2925Accounts().length === 0;
}
inputEmailPrefix.style.display = useMail2925AccountPool ? 'none' : '';
inputEmailPrefix.readOnly = useMail2925AccountPool;
inputEmailPrefix.style.display = '';
inputEmailPrefix.readOnly = false;
selectEmailGenerator.disabled = useHotmail || useLuckmail || useGeneratedAlias || useCustomEmail;
if (useGmail) {
labelEmailPrefix.textContent = 'Gmail 原邮箱';
@@ -2795,7 +2873,9 @@ function updateMailProviderUI() {
}
if (autoHintText && useMail2925AccountPool) {
autoHintText.textContent = getMail2925Accounts().length
? '当前已启用 2925 号池模式,步骤 3 会基于下拉框选中的号池邮箱生成别名地址'
? (useGeneratedAlias
? '当前已启用 2925 号池模式,步骤 3 会基于下拉框选中的号池邮箱生成别名地址'
: '当前已启用 2925 号池模式,步骤 4 / 8 遇到登录页时会优先使用下拉框选中的账号自动登录')
: '当前已启用 2925 号池模式,请先在下方 2925 账号池中添加账号并选择邮箱';
}
if (autoHintText && showCloudflareTempEmailReceiveMailbox) {
@@ -3123,6 +3203,7 @@ async function fetchGeneratedEmail(options = {}) {
generateNew: true,
generator: selectEmailGenerator.value,
mailProvider: selectMailProvider.value,
mail2925Mode: getSelectedMail2925Mode(),
...buildManagedAliasBaseEmailPayload(),
},
});
@@ -3182,7 +3263,9 @@ const hotmailManager = window.SidepanelHotmailManager?.createHotmailManager({
btnDeleteAllHotmailAccounts,
btnHotmailUsageGuide,
btnImportHotmailAccounts,
btnToggleHotmailForm,
btnToggleHotmailList,
hotmailFormShell,
hotmailAccountsList,
hotmailListShell,
inputEmail,
@@ -3233,14 +3316,15 @@ const mail2925Manager = window.SidepanelMail2925Manager?.createMail2925Manager({
},
dom: {
btnAddMail2925Account,
btnCancelMail2925Edit,
btnDeleteAllMail2925Accounts,
btnImportMail2925Accounts,
btnToggleMail2925Form,
btnToggleMail2925List,
inputMail2925Email,
inputMail2925Import,
inputMail2925Password,
mail2925AccountsList,
mail2925FormShell,
mail2925ListShell,
},
helpers: {
@@ -3249,6 +3333,7 @@ const mail2925Manager = window.SidepanelMail2925Manager?.createMail2925Manager({
getMail2925Accounts,
openConfirmModal,
refreshManagedAliasBaseEmail: () => {
syncMail2925BaseEmailFromCurrentAccount(latestState, { persist: true });
setManagedAliasBaseEmailInputForProvider('2925', latestState);
},
showToast,
@@ -3860,7 +3945,7 @@ async function startAutoRunFromCurrentSettings() {
if (shouldWarnAutoRunFallbackRisk(totalRuns, autoRunSkipFailures)
&& !isAutoRunFallbackRiskPromptDismissed()) {
const result = await openAutoRunFallbackRiskConfirmModal(totalRuns, fallbackThreadIntervalMinutes);
const result = await openAutoRunFallbackRiskConfirmModal(totalRuns);
if (!result.confirmed) {
return false;
}
@@ -4822,6 +4907,14 @@ document.addEventListener('keydown', (event) => {
}
});
window.addEventListener('resize', () => {
positionContributionUpdateHint();
});
document.addEventListener('scroll', () => {
positionContributionUpdateHint();
}, true);
// ============================================================
// Init
// ============================================================