mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-20 23:52:31 -04:00
Attach autofill icon to first element based on dom order (#541)
This commit is contained in:
@@ -766,8 +766,20 @@ function injectIcons(): void {
|
||||
const forms = formDetector.detectForms();
|
||||
|
||||
forms.forEach(form => {
|
||||
// Determine which field to attach the icon to
|
||||
const targetField = form.emailField || form.usernameField || form.passwordField;
|
||||
// Find the first occurring field by comparing their positions in the DOM
|
||||
const fields = [
|
||||
{ type: 'email', element: form.emailField },
|
||||
{ type: 'username', element: form.usernameField },
|
||||
{ type: 'password', element: form.passwordField }
|
||||
].filter(f => f.element);
|
||||
|
||||
// Sort fields based on their DOM position
|
||||
fields.sort((a, b) => {
|
||||
if (!a.element || !b.element) return 0;
|
||||
return a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
|
||||
});
|
||||
|
||||
const targetField = fields[0]?.element;
|
||||
|
||||
if (targetField && !targetField.parentElement?.querySelector('.aliasvault-input-icon')) {
|
||||
const wrapper = document.createElement('div');
|
||||
|
||||
@@ -331,11 +331,11 @@ export class FormDetector {
|
||||
|
||||
if (radioButtons && radioButtons.length > 0) {
|
||||
// Map specific gender radio buttons
|
||||
const malePatterns = ['male', 'man', 'm', 'masculin', 'man'];
|
||||
const femalePatterns = ['female', 'woman', 'f', 'feminin', 'vrouw'];
|
||||
const otherPatterns = ['other', 'diverse', 'custom', 'prefer not', 'anders', 'iets'];
|
||||
const malePatterns = ['male', 'man', 'm', 'man', 'gender1'];
|
||||
const femalePatterns = ['female', 'woman', 'f', 'vrouw', 'gender2'];
|
||||
const otherPatterns = ['other', 'diverse', 'custom', 'prefer not', 'anders', 'iets', 'unknown', 'gender3'];
|
||||
|
||||
const findRadioByPatterns = (patterns: string[]) => {
|
||||
const findRadioByPatterns = (patterns: string[], isOther: boolean = false) => {
|
||||
return Array.from(radioButtons).find(radio => {
|
||||
const attributes = [
|
||||
radio.value,
|
||||
@@ -344,6 +344,14 @@ export class FormDetector {
|
||||
radio.labels?.[0]?.textContent || ''
|
||||
].map(attr => attr?.toLowerCase() || '');
|
||||
|
||||
// For "other" patterns, skip if it matches male or female patterns
|
||||
if (isOther && (
|
||||
malePatterns.some(pattern => attributes.some(attr => attr.includes(pattern))) ||
|
||||
femalePatterns.some(pattern => attributes.some(attr => attr.includes(pattern)))
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return patterns.some(pattern =>
|
||||
attributes.some(attr => attr.includes(pattern))
|
||||
);
|
||||
|
||||
@@ -25,6 +25,7 @@ const setupFormTest = (htmlFile: string) => {
|
||||
|
||||
enum FormField {
|
||||
Username = 'username',
|
||||
FirstName = 'firstName',
|
||||
LastName = 'lastName',
|
||||
Email = 'email',
|
||||
EmailConfirm = 'emailConfirm',
|
||||
@@ -106,6 +107,20 @@ describe('FormDetector', () => {
|
||||
testField(FormField.GenderOther, 'iets', htmlFile);
|
||||
});
|
||||
|
||||
describe('Dutch registration form 3 detection', () => {
|
||||
const htmlFile = 'nl-registration-form3.html';
|
||||
|
||||
testField(FormField.FirstName, 'firstName', htmlFile);
|
||||
testField(FormField.LastName, 'lastName', htmlFile);
|
||||
testField(FormField.Password, 'password', htmlFile);
|
||||
|
||||
testField(FormField.BirthDate, 'date', htmlFile);
|
||||
|
||||
testField(FormField.GenderMale, 'gender1', htmlFile);
|
||||
testField(FormField.GenderFemale, 'gender2', htmlFile);
|
||||
testField(FormField.GenderOther, 'gender3', htmlFile);
|
||||
});
|
||||
|
||||
describe('English registration form 1 detection', () => {
|
||||
const htmlFile = 'en-registration-form1.html';
|
||||
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
<main class="main-component_wrapper">
|
||||
<h1 class="title-component_title">Maak je account aan</h1>
|
||||
|
||||
<div style="display: flex; gap: 16px">
|
||||
<div style="display: flex; gap: 4px">
|
||||
<span style="line-height: 23px; text-align: center">Gratis account</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 4px">
|
||||
<span style="line-height: 23px; text-align: center">Binnen 1 minuut geregeld</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-validation-component_wrapper email-validation-component_error">
|
||||
|
||||
<div id="email-validation-component_valid" class="email-validation-component_hidden">
|
||||
<span>Je maakt een DPG Media account aan met:</span>
|
||||
<strong class="email-validation-component_email">shawns-1971@asdasd.nl</strong>
|
||||
</div>
|
||||
|
||||
<div id="email-validation-component_invalid" class="">
|
||||
<span>Je kunt geen account aanmaken met</span>
|
||||
<strong class="email-validation-component_email">shawns-1971@asdasd.nl</strong>
|
||||
|
||||
<div id="email-validation-component_suggestion" class="email-validation-component_hidden">
|
||||
<span>Misschien bedoelde je</span>
|
||||
<strong class="email-validation-component_email"></strong>
|
||||
</div>
|
||||
<div id="email-validation-component_no-suggestion" class="">
|
||||
<span class="email-validation-component_email-context">Vul een geldig e-mailadres in.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<a id="email-validation-component_change-email" href="#" data-selector="sel-registration" class="link-component">wijzig e-mailadres</a>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<form id="registration-form" action="#" method="post" class="form-component_form" novalidate="" autocomplete="on">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<input type="hidden" id="test" name="test" value="false">
|
||||
<input type="hidden" id="email" autocomplete="email" inputmode="email" name="email" value="shawns-1971@asdasd.nl">
|
||||
|
||||
<h2 class="title-component_section" data-ats-observing="">Maak een wachtwoord aan</h2>
|
||||
|
||||
<div>
|
||||
|
||||
<div class="text-input-component_wrapper">
|
||||
|
||||
<div class="text-input-component_input" onclick="inputComponentFocusOnInput(event)">
|
||||
<input type="password" id="password" autocomplete="new-password" aria-required="true" aria-label="Wachtwoord" inputmode="password" placeholder=" " required="required" autofocus="autofocus" class="required" name="password" value="">
|
||||
<label for="password">Wachtwoord</label>
|
||||
<span class="text-input-component_password-icon" onclick="inputComponentShowPassword(event)"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pswmeter" class="password-strength-meter"><div class="password-strength-meter-score"></div></div>
|
||||
<div class="pswmeter_message pwsmeter-container" id="pswmeter-message"><div>Gebruik minimaal 10 karakters</div><div class="pswmeter-constraints"><span>Probeer de volgende zaken nog toe te voegen:</span><ul><li class="pswmeter-constraint">Minimaal 10 karakters</li><li class="pswmeter-constraint">Kleine letter</li><li class="pswmeter-constraint">Hoofdletter</li><li class="pswmeter-constraint">Nummer</li><li class="pswmeter-constraint">Speciaal teken</li></ul></div></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<h2 class="title-component_section" data-ats-observing="">Persoonlijke gegevens</h2>
|
||||
|
||||
|
||||
|
||||
<div class="radiobutton-component_wrapper">
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="radiobutton-component-options-wrapper-vertical">
|
||||
|
||||
<label for="gender1">
|
||||
Meneer
|
||||
<input type="radio" value="m" onchange="try{document.getElementsByClassName('validation-error-' + this.name)[0].remove()}catch(e){}" id="gender1" name="gender">
|
||||
<span class="radiobutton-component_checkmark"></span>
|
||||
</label>
|
||||
|
||||
<label for="gender2">
|
||||
Mevrouw
|
||||
<input type="radio" value="f" onchange="try{document.getElementsByClassName('validation-error-' + this.name)[0].remove()}catch(e){}" id="gender2" name="gender">
|
||||
<span class="radiobutton-component_checkmark"></span>
|
||||
</label>
|
||||
|
||||
<label for="gender3">
|
||||
Liever geen van beide
|
||||
<input type="radio" value="u" onchange="try{document.getElementsByClassName('validation-error-' + this.name)[0].remove()}catch(e){}" id="gender3" name="gender">
|
||||
<span class="radiobutton-component_checkmark"></span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
<div class="radiobutton-component_label required">Aanspreekvorm</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="text-input-component_wrapper">
|
||||
|
||||
|
||||
|
||||
<div class="text-input-component_input" onclick="inputComponentFocusOnInput(event)">
|
||||
<div style="position: relative; display: inline-block; width: 100%;"><input type="text" id="firstName" autocomplete="firstName" aria-label="Voornaam" inputmode="text" placeholder=" " autofocus="autofocus" class="required" name="firstName" value="" style="width: 293px; display: block;"><div class="aliasvault-input-icon" style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
margin: auto;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
z-index: 999999;
|
||||
">
|
||||
<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA1MDAgNTAwIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MDAgNTAwIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJtNDU5Ljg3IDI5NC45NWMwLjAxNjIwNSA1LjQwMDUgMC4wMzI0MSAxMC44MDEtMC4zNTAyMiAxNi44NzMtMS4xMTEgNi4zMzkyLTEuMTk0MSAxMi4xNzMtMi42MzUxIDE3LjY0OS0xMC45MjIgNDEuNTA4LTM2LjczMSA2OS40ODEtNzcuMzUxIDgzLjQwOC03LjIxNTcgMi40NzM5LTE0Ljk3MiAzLjM3MDItMjIuNDc5IDQuOTk1LTIzLjYyOSAwLjA0MjIwNS00Ny4yNTcgMC4xMTQ1My03MC44ODYgMC4xMjAyNy00Ni43NjIgMC4wMTEzMjItOTMuNTIzLTAuMDE0MTYtMTQwLjk1LTAuNDM0MTEtOC41OS0yLjAwMjQtMTYuNzY2LTIuODM1Mi0yNC4zOTgtNS4zMzI2LTIxLjU5NS03LjA2NjYtMzkuNTIzLTE5LjY1Ni01My43MDgtMzcuNTUyLTEwLjIyNy0xMi45MDMtMTcuNTc5LTI3LjE3LTIxLjI4LTQzLjIyMS0xLjQ3NS02LjM5NjctMi40NzExLTEyLjkwNC0zLjY4NTItMTkuMzYxLTAuMDUxODQ5LTUuNzQ3LTAuMTAzNy0xMS40OTQgMC4yNjkxNS0xNy44ODYgNC4xNTktNDIuOTczIDI3LjY4LTcxLjYzOCA2My41NjItOTIuMTUzIDAtMC43MDc2MS0wLjAwMTk2MS0xLjY5ODggMy4xMmUtNCAtMi42OSAwLjAyMjQ4NC05LjgyOTMtMS4zMDcxLTE5Ljg5NCAwLjM1NjY0LTI5LjQzOCAzLjIzOTEtMTguNTc5IDExLjA4LTM1LjI3MiAyMy43NjMtNDkuNzczIDEyLjA5OC0xMy44MzIgMjYuNDU3LTIzLjk4OSA0My42MDktMzAuMDI5IDcuODEzLTIuNzUxMiAxNi4xNC00LjA0MTcgMjQuMjM0LTUuOTk0OCA3LjM5Mi0wLjAyNTczNCAxNC43ODQtMC4wNTE0NiAyMi44MzUgMC4zMjI1MyA0LjE5NTkgMC45NTM5MiA3Ljc5NDYgMS4yNTM4IDExLjI1OCAyLjEwNTMgMTcuMTYgNC4yMTkyIDMyLjI4NyAxMi4xNzYgNDUuNDY5IDI0LjEwNCAyLjI1NTggMi4wNDExIDQuMzcyIDYuNjI0MSA5LjYyMSAzLjg2OCAxNi44MzktOC44NDE5IDM0LjcxOC0xMS41OTcgNTMuNjAzLTguNTk0IDE2Ljc5MSAyLjY2OTkgMzEuNjAyIDkuNDMwOCA0NC4yMzYgMjAuNjM2IDExLjUzMSAxMC4yMjcgMTkuODQgMjIuODQxIDI1LjM5MyAzNy4yMzYgNi4zNDM2IDE2LjQ0NSAxMC4zODkgMzMuMTYzIDYuMDc5OCA0OS4zODkgNy45NTg3IDguOTMyMSAxNS44MDcgMTYuNzA0IDIyLjQyMSAyNS40MTQgOS4xNjIgMTIuMDY1IDE1LjMzIDI1Ljc0NiAxOC4xNDQgNDAuNzc2IDAuOTcwNDYgNS4xODQ4IDEuOTExMSAxMC4zNzUgMi44NjU0IDE1LjU2M20tNzEuNTk3IDcxLjAxMmM1LjU2MTUtNS4yMjg0IDEyLjAwMi05Ljc5ODYgMTYuNTA4LTE1LjgxNyAxMC40NzQtMTMuOTkyIDE0LjMzMy0yOS45MTYgMTEuMjg4LTQ3LjQ0Ni0yLjI0OTYtMTIuOTUtOC4xOTczLTI0LjA3Ni0xNy4yNDMtMzMuMDYzLTEyLjc0Ni0xMi42NjMtMjguODY1LTE4LjYxNC00Ni43ODYtMTguNTY5LTY5LjkxMiAwLjE3NzEyLTEzOS44MiAwLjU2ODMxLTIwOS43NCAwLjk2MTc2LTE1LjkyMiAwLjA4OTU5OS0yOS4xNjggNy40MjA5LTM5LjY4NSAxOC4yOTYtMTQuNDUgMTQuOTQ0LTIwLjQwOCAzMy4zNDMtMTYuNjU1IDU0LjM2OCAyLjI3NjMgMTIuNzU0IDguMjE2NyAyMy43NDggMTcuMTU4IDMyLjY2IDEzLjI5OSAxMy4yNTUgMzAuMDk3IDE4LjY1MyA0OC43MjggMTguNjUxIDU5LjMyMS0wLjAwNTE4OCAxMTguNjQgMC4wNDIzNTggMTc3Ljk2LTAuMDQ2NjAxIDkuNTkxMi0wLjAxNDM3NCAxOS4xODEtMC44NjU4OCAyOC43NzMtMC44ODg1NSAxMC42NDktMC4wMjUxNDYgMTkuOTc4LTMuODI1IDI5LjY4Ny05LjEwNzR6IiBmaWxsPSIjRUVDMTcwIi8+CjxwYXRoIGQ9Im0xNjIuNzcgMjkzYzE1LjY1NCA0LjM4ODMgMjAuNjI3IDIyLjk2NyAxMC4zMDQgMzQuOTgtNS4zMTA0IDYuMTc5NS0xNC44MTcgOC4zMjA4LTI0LjI3OCA1LjA0NzItNy4wNzIzLTIuNDQ3MS0xMi4zMzItMTAuMzYyLTEyLjg3Ni0xNy45MzMtMS4wNDUxLTE0LjU0MiAxMS4wODktMjMuMTc2IDIxLjcwNS0yMy4wNDYgMS41Nzk0IDAuMDE5Mjg3IDMuMTUxNyAwLjYxNTY2IDUuMTQ2MSAwLjk1MTg0eiIgZmlsbD0iI0VFQzE3MCIvPgo8cGF0aCBkPSJtMjI3LjE4IDI5My42NGM3Ljg0OTkgMi4zOTczIDExLjkzOCA4LjIxNDMgMTMuNTI0IDE1LjA3NyAxLjg1OTEgOC4wNDM5LTAuNDQ4MTcgMTUuNzA2LTcuMTU4OCAyMS4xMjEtNi43NjMzIDUuNDU3Mi0xNC40MTcgNi44Nzk0LTIyLjU3OCAzLjE0ODMtOC4yOTcyLTMuNzkzMy0xMi44MzYtMTAuODQ5LTEyLjczNi0xOS40MzggMC4xNjg3LTE0LjQ5NyAxNC4xMy0yNS4zNjggMjguOTQ4LTE5LjkwOHoiIGZpbGw9IiNFRUMxNzAiLz4KPHBhdGggZD0ibTI2MS41NyAzMTkuMDdjLTIuNDk1LTE0LjQxOCA0LjY4NTMtMjIuNjAzIDE0LjU5Ni0yNi4xMDggOS44OTQ1LTMuNDk5NSAyMy4xODEgMy40MzAzIDI2LjI2NyAxMy43NzkgNC42NTA0IDE1LjU5MS03LjE2NTEgMjkuMDY0LTIxLjY2NSAyOC4xNjEtOC41MjU0LTAuNTMwODgtMTcuMjAyLTYuNTA5NC0xOS4xOTgtMTUuODMxeiIgZmlsbD0iI0VFQzE3MCIvPgo8cGF0aCBkPSJtMzM2LjkxIDMzMy40MWMtOS4wMTc1LTQuMjQ5MS0xNS4zMzctMTQuMzQ5LTEzLjgyOS0yMS42ODIgMy4wODI1LTE0Ljk4OSAxMy4zNDEtMjAuMzA0IDIzLjAxOC0xOS41ODUgMTAuNjUzIDAuNzkxNDEgMTcuOTMgNy40MDcgMTkuNzY1IDE3LjU0NyAxLjk1ODggMTAuODI0LTQuMTE3MSAxOS45MzktMTMuNDk0IDIzLjcwMy01LjI3MiAyLjExNjItMTAuMDkxIDEuNTA4Ni0xNS40NiAwLjAxNzg4M3oiIGZpbGw9IiNFRUMxNzAiLz4KPC9zdmc+" style="width: 100%; height: 100%;">
|
||||
</div></div>
|
||||
<label for="firstName">Voornaam</label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="text-input-component_wrapper">
|
||||
|
||||
|
||||
|
||||
<div class="text-input-component_input" onclick="inputComponentFocusOnInput(event)">
|
||||
<input type="text" id="lastName" autocomplete="lastName" aria-label="Achternaam" inputmode="text" placeholder=" " autofocus="autofocus" class="required" name="lastName" value="">
|
||||
<label for="lastName">Achternaam</label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="date-picker-component_wrapper">
|
||||
|
||||
|
||||
|
||||
<div class="date-picker-component_input">
|
||||
<input inputmode="numeric" id="date" type="text" placeholder=" " required="required" class="required" name="birthDate" value="">
|
||||
<label for="date">Geboortedatum</label>
|
||||
<span class="date-picker-component_icon">dd - mm - jjjj</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div role="alert" class="validation-error_field validation-error-address inactive">
|
||||
<span>Dit is geen geldig adres.</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="country-postal-wrapper">
|
||||
|
||||
|
||||
|
||||
<div class="country-postal-component_wrapper">
|
||||
<div class="country-postal-component_input country-postal-component_input_country">
|
||||
<input placeholder=" " inputmode="text" type="text" onfocus="this.value=''" autocomplete="0" id="country" name="country" value="🇳🇱">
|
||||
<label for="country">Land</label>
|
||||
</div>
|
||||
<div class="country-postal-component_input country-postal-component_postcode">
|
||||
<input placeholder=" " inputmode="text" type="text" autocomplete="postal-code" class="required" id="postalCode" name="postalCode" value="">
|
||||
<label for="postalCode">Postcode</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="checkbox-component_wrapper">
|
||||
<label for="b428652f-189a-4bf2-9008-668bee04804e" class="checkbox-component_label">
|
||||
<input type="checkbox" class="checkbox-component_checkbox" id="b428652f-189a-4bf2-9008-668bee04804e" value="b428652f-189a-4bf2-9008-668bee04804e" name="offeringIds"><input type="hidden" name="_offeringIds" value="on">
|
||||
<span class="checkbox-component_check"></span>
|
||||
<span class="checkbox-component_labeltext">Ja, ik wil via e-mail aanbiedingen van NU.nl ontvangen.</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox-component_wrapper">
|
||||
<label for="9b498ca0-adf4-418c-90d7-c02ff4a9d0cd" class="checkbox-component_label">
|
||||
<input type="checkbox" class="checkbox-component_checkbox" id="9b498ca0-adf4-418c-90d7-c02ff4a9d0cd" value="9b498ca0-adf4-418c-90d7-c02ff4a9d0cd" name="offeringIds"><input type="hidden" name="_offeringIds" value="on">
|
||||
<span class="checkbox-component_check"></span>
|
||||
<span class="checkbox-component_labeltext">Ja, ik wil via e-mail productinformatie van NU.nl ontvangen (max 1x per week).</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="checkbox-component_wrapper">
|
||||
<label for="61c9d029405e342b7eb5d333" class="checkbox-component_label">
|
||||
<input type="checkbox" class="checkbox-component_checkbox" id="61c9d029405e342b7eb5d333" value="61c9d029405e342b7eb5d333" name="newsletterIds"><input type="hidden" name="_newsletterIds" value="on">
|
||||
<span class="checkbox-component_check"></span>
|
||||
<span class="checkbox-component_labeltext">Ja, ik ontvang graag elke middag het belangrijkste nieuws van NU.nl.</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<p class="paragraph-component_muted">Je bovenstaande gegevens kunnen worden toegevoegd aan jouw profiel in overeenstemming met ons privacy statement. Indien je hiermee ingestemd hebt, gebruiken wij je gegevens voor analyses en om je marketing en advertentie uitingen te tonen die voor jou relevant zijn. Je kunt dit altijd wijzigen via je privacy instellingen in onze websites en apps. Door dit account aan te maken, ga je akkoord met de <a href="#" target="_blank" class="link-component">gebruiksvoorwaarden</a>.</p>
|
||||
|
||||
<div style="margin-top: 8px;">
|
||||
<button type="submit" class="button-component_button button-component_submit">Maak mijn account aan</button>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
</main>
|
||||
Reference in New Issue
Block a user