feat: 增强 PayPal 标签页检测逻辑,支持自动接管已打开的 PayPal 页面,并优化登录流程的元素查找

This commit is contained in:
QLHazyCoder
2026-04-26 06:03:53 +08:00
parent 3271dc2f83
commit 9a63cba994
4 changed files with 332 additions and 7 deletions
+51 -2
View File
@@ -70,6 +70,22 @@ async function waitForDocumentComplete() {
function isVisibleElement(el) {
if (!el) return false;
let node = el;
while (node && node.nodeType === 1) {
if (node.hidden || node.getAttribute?.('aria-hidden') === 'true' || node.getAttribute?.('inert') !== null) {
return false;
}
const nodeStyle = window.getComputedStyle(node);
if (
nodeStyle.display === 'none'
|| nodeStyle.visibility === 'hidden'
|| nodeStyle.visibility === 'collapse'
|| Number(nodeStyle.opacity) === 0
) {
return false;
}
node = node.parentElement;
}
const style = window.getComputedStyle(el);
const rect = el.getBoundingClientRect();
return style.display !== 'none'
@@ -117,7 +133,7 @@ function findInputByPatterns(patterns) {
const inputs = getVisibleControls('input')
.filter((input) => {
const type = String(input.getAttribute('type') || input.type || '').trim().toLowerCase();
return !['hidden', 'checkbox', 'radio', 'submit', 'button', 'file'].includes(type);
return isEnabledControl(input) && !['hidden', 'checkbox', 'radio', 'submit', 'button', 'file'].includes(type);
});
return inputs.find((input) => {
const text = getActionText(input);
@@ -144,6 +160,21 @@ function findLoginNextButton() {
]);
}
function findEmailNextButton() {
return findClickableByText([
/next|btn\s*next|btnnext/i,
/下一页|下一步/i,
]);
}
function findPasswordLoginButton() {
const button = findClickableByText([
/login|log\s*in|sign\s*in/i,
/登录|登入/i,
]);
return button && button !== findEmailNextButton() ? button : null;
}
function findApproveButton() {
return findClickableByText([
/同意并继续|同意|继续|授权|确认并继续/i,
@@ -185,6 +216,11 @@ function hasPasskeyPrompt() {
}
function getPayPalLoginPhase(emailInput, passwordInput) {
const emailNextButton = findEmailNextButton();
const passwordLoginButton = findPasswordLoginButton();
if (emailInput && emailNextButton && isEnabledControl(emailNextButton) && (!passwordInput || !passwordLoginButton)) {
return 'email';
}
if (emailInput && passwordInput) return 'login_combined';
if (passwordInput) return 'password';
if (emailInput) return 'email';
@@ -202,13 +238,26 @@ async function submitPayPalLogin(payload = {}) {
let passwordInput = findPasswordInput();
const emailInput = findEmailInput();
const emailNextButton = findEmailNextButton();
if (emailInput && emailNextButton && isEnabledControl(emailNextButton) && (!passwordInput || !findPasswordLoginButton())) {
if (normalizeText(emailInput.value || '') !== email) {
fillInput(emailInput, email);
}
simulateClick(emailNextButton);
return {
submitted: false,
phase: 'email_submitted',
awaiting: 'password_page',
};
}
if (!passwordInput && emailInput && email) {
if (normalizeText(emailInput.value || '') !== email) {
fillInput(emailInput, email);
}
const nextButton = await waitUntil(() => {
const button = findLoginNextButton();
const button = findEmailNextButton() || findLoginNextButton();
return button && isEnabledControl(button) ? button : null;
}, {
intervalMs: 250,