diff --git a/content/signup-page.js b/content/signup-page.js index 797236a..9f5e152 100644 --- a/content/signup-page.js +++ b/content/signup-page.js @@ -3484,6 +3484,10 @@ function summarizePhoneInputCandidate(element, options = {}) { const normalizedName = summary.name.toLowerCase(); const normalizedId = summary.id.toLowerCase(); const combinedText = `${normalizedName} ${normalizedId} ${summary.placeholder} ${summary.ariaLabel}`; + if (isLoginEmailLikeInput(element)) { + summary.skipReason = 'email_like'; + return summary; + } if ( summary.type === 'tel' || summary.autocomplete === 'tel' @@ -3517,14 +3521,50 @@ function findUsablePhoneInput(selector, options = {}) { .find((element) => isUsablePhoneInputElement(element, options)) || null; } +function getLoginInputAttributeText(input) { + return { + type: String(input?.getAttribute?.('type') || input?.type || '').trim().toLowerCase(), + autocomplete: String(input?.getAttribute?.('autocomplete') || '').trim().toLowerCase(), + name: String(input?.getAttribute?.('name') || input?.name || '').trim(), + id: String(input?.getAttribute?.('id') || input?.id || '').trim(), + placeholder: String(input?.getAttribute?.('placeholder') || '').trim(), + ariaLabel: String(input?.getAttribute?.('aria-label') || '').trim(), + }; +} + +function isLoginEmailLikeInput(input) { + const summary = getLoginInputAttributeText(input); + const nameId = `${summary.name} ${summary.id}`; + const labelText = `${summary.placeholder} ${summary.ariaLabel}`; + return summary.type === 'email' + || summary.autocomplete === 'email' + || /email/i.test(nameId) + || /email|电子邮件|邮箱/i.test(labelText); +} + function getLoginEmailInput() { - const input = document.querySelector( - 'input[type="email"], input[name="email"], input[name="username"], input[id*="email"], input[placeholder*="email" i], input[placeholder*="Email"]' - ); - if (isLoginPhoneUsernameKind() || isLoginPhoneEntryPageText()) { + const input = Array.from(document.querySelectorAll([ + 'input[type="email"]', + 'input[autocomplete="email"]', + 'input[name="email"]', + 'input[name="username"]', + 'input[autocomplete="username"]', + 'input[id*="email" i]', + 'input[placeholder*="email" i]', + 'input[placeholder*="Email"]', + 'input[placeholder*="电子邮件"]', + 'input[placeholder*="邮箱"]', + 'input[aria-label*="email" i]', + 'input[aria-label*="电子邮件"]', + 'input[aria-label*="邮箱"]', + ].join(', '))).find((candidate) => isVisibleElement(candidate)) || null; + if (!input) { return null; } - return input && isVisibleElement(input) ? input : null; + if ((isLoginPhoneUsernameKind() || isLoginPhoneEntryPageText()) && !isLoginEmailLikeInput(input)) { + return null; + } + return input; } function getLoginPhoneInput() { diff --git a/tests/step7-phone-login-entry.test.js b/tests/step7-phone-login-entry.test.js index 832ec1f..92f45d7 100644 --- a/tests/step7-phone-login-entry.test.js +++ b/tests/step7-phone-login-entry.test.js @@ -135,14 +135,18 @@ ${extractFunction('getPageTextSnapshot')} ${extractFunction('isLoginPhoneUsernameKind')} ${extractFunction('isLoginPhoneEntryPageText')} ${extractFunction('isInsideHiddenPhoneControl')} +${extractFunction('getLoginInputAttributeText')} +${extractFunction('isLoginEmailLikeInput')} ${extractFunction('summarizePhoneInputCandidate')} ${extractFunction('isUsablePhoneInputElement')} ${extractFunction('collectPhoneInputCandidates')} ${extractFunction('findUsablePhoneInput')} +${extractFunction('getLoginEmailInput')} ${extractFunction('getLoginPhoneInput')} ${extractFunction('isAddPhonePageReady')} return { + getLoginEmailInput, getLoginPhoneInput, isAddPhonePageReady, }; @@ -168,6 +172,18 @@ test('step 7 does not mistake email entry with a phone switch action for phone i assert.equal(api.isAddPhonePageReady(), false); }); +test('step 7 treats unified OpenAI login page as email input despite phone option text', () => { + const api = createPhoneLoginEntryApi({ + href: 'https://auth.openai.com/log-in-or-create-account', + pathname: '/log-in-or-create-account', + pageText: '\u767b\u5f55\u6216\u6ce8\u518c \u7535\u5b50\u90ae\u4ef6\u5730\u5740 \u7ee7\u7eed \u4f7f\u7528\u7535\u8bdd\u53f7\u7801\u7ee7\u7eed', + inputAttributes: { type: 'text', placeholder: '\u7535\u5b50\u90ae\u4ef6\u5730\u5740' }, + }); + + assert.ok(api.getLoginEmailInput(), 'unified login email input should be detected'); + assert.equal(api.getLoginPhoneInput(), null, 'phone option button must not turn email input into phone input'); +}); + test('step 7 detects username text input when usernameKind is phone_number', () => { const api = createPhoneLoginEntryApi({ phoneUsernameKind: true,