generated from adobe/aem-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
438 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,69 @@ | ||
import { hideSideModal, i18nLookup } from '../../scripts/util.js'; | ||
|
||
const LOGIN_ERROR = 'There was a problem processing your request.'; | ||
const i18n = await i18nLookup(); | ||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | ||
const phoneRegex = /^\d{10}$/; | ||
|
||
function displayError(errors) { | ||
const message = document.body.querySelector('.contact-form.block').querySelector('.message'); | ||
const details = message.querySelector('.details'); | ||
const spans = []; | ||
[LOGIN_ERROR, ...errors].forEach((m) => { | ||
const span = document.createElement('span'); | ||
span.textContent = i18n(m); | ||
spans.push(span); | ||
}); | ||
details.replaceChildren(...spans); | ||
message.classList.add('error'); | ||
} | ||
|
||
function isValid(form) { | ||
const errors = []; | ||
const firstName = form.querySelector('input[name="first_name"]'); | ||
if (!firstName.value || firstName.value.trim().length === 0) { | ||
errors.push(i18n('First name is required.')); | ||
firstName.classList.add('error'); | ||
} | ||
|
||
const lastName = form.querySelector('input[name="last_name"]'); | ||
if (!lastName.value || lastName.value.trim().length === 0) { | ||
errors.push(i18n('Last name is required.')); | ||
lastName.classList.add('error'); | ||
} | ||
|
||
const email = form.querySelector('input[name="email"]'); | ||
if (!email.value || email.value.trim().length === 0) { | ||
errors.push(i18n('Email address is required.')); | ||
email.classList.add('error'); | ||
} | ||
if (!emailRegex.test(email)) { | ||
errors.push(i18n('Please enter an email address in the format: [email protected].')); | ||
email.classList.add('error'); | ||
} | ||
|
||
const phone = form.querySelector('input[name="phone"]'); | ||
if (!phone.value || phone.value.trim().length === 0) { | ||
errors.push(i18n('Email address is required.')); | ||
phone.classList.add('error'); | ||
} | ||
if (!phoneRegex.test(phone)) { | ||
errors.push(i18n('Please enter a 10 digit phone number.')); | ||
phone.classList.add('error'); | ||
} | ||
|
||
if (errors.length > 0) { | ||
displayError(errors); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
function submitContactForm(form) { | ||
console.log('submitted'); | ||
return isValid(form); | ||
} | ||
|
||
// eslint-disable no-console | ||
const addForm = async (block) => { | ||
const displayValue = block.style.display; | ||
|
@@ -14,6 +80,161 @@ const addForm = async (block) => { | |
} | ||
|
||
block.innerHTML = await data.text(); | ||
|
||
const submitBtn = block.querySelector('.cta a.submit'); | ||
if (submitBtn) { | ||
submitBtn.addEventListener('click', (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
submitContactForm(block.querySelector('form')); | ||
}); | ||
} | ||
|
||
const cancelBtn = block.querySelector('.cta a.cancel'); | ||
if (cancelBtn) { | ||
cancelBtn.addEventListener('click', (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
hideSideModal(); | ||
}); | ||
} | ||
|
||
[...block.querySelectorAll('input[name="first_name"], input[name="last_name"]')] | ||
.forEach((el) => { | ||
el.addEventListener('blur', (e) => { | ||
const { value } = e.currentTarget; | ||
if (!value || value.trim().length === 0) { | ||
e.currentTarget.classList.add('error'); | ||
} else { | ||
e.currentTarget.classList.remove('error'); | ||
} | ||
}); | ||
}); | ||
|
||
[...block.querySelectorAll('input[name="phone"]')] | ||
.forEach((el) => { | ||
el.addEventListener('blur', (e) => { | ||
const { value } = e.currentTarget; | ||
if (!value || value.trim().length === 0 || !phoneRegex.test(value)) { | ||
e.currentTarget.classList.add('error'); | ||
} else { | ||
e.currentTarget.classList.remove('error'); | ||
} | ||
}); | ||
}); | ||
|
||
[...block.querySelectorAll('input[name="email"]')] | ||
.forEach((el) => { | ||
el.addEventListener('blur', (e) => { | ||
const { value } = e.currentTarget; | ||
if (!value || value.trim().length === 0 || !emailRegex.test(value)) { | ||
e.currentTarget.classList.add('error'); | ||
} else { | ||
e.currentTarget.classList.remove('error'); | ||
} | ||
}); | ||
}); | ||
|
||
if (thankYou) { | ||
const form = block.querySelector('#contactForm'); | ||
const oldSubmit = form.onsubmit; | ||
thankYou.classList.add('form-thank-you'); | ||
form.onsubmit = function handleSubmit() { | ||
if (oldSubmit.call(this)) { | ||
const body = new FormData(this); | ||
const { action, method } = this; | ||
fetch(action, { method, body, redirect: 'manual' }).then((resp) => { | ||
/* eslint-disable-next-line no-console */ | ||
if (!resp.ok) console.error(`Form submission failed: ${resp.status} / ${resp.statusText}`); | ||
const firstContent = thankYou.firstElementChild; | ||
if (firstContent.tagName === 'A') { | ||
// redirect to thank you page | ||
window.location.href = firstContent.href; | ||
} else { | ||
// show thank you content | ||
const btn = thankYou.querySelector('a'); | ||
const sideModal = document.querySelector('.side-modal-form'); | ||
if (btn && sideModal) { | ||
btn.setAttribute('href', '#'); | ||
btn.addEventListener('click', (e) => { | ||
e.preventDefault(); | ||
hideSideModal(); | ||
}); | ||
sideModal?.replaceChildren(thankYou); | ||
} else { | ||
block.replaceChildren(thankYou); | ||
} | ||
} | ||
}); | ||
} | ||
return false; | ||
}; | ||
} | ||
|
||
// If the form has it's own styles, add them. | ||
const styles = block.querySelectorAll('style'); | ||
styles.forEach((styleSheet) => { | ||
document.head.appendChild(styleSheet); | ||
}); | ||
|
||
// If the form has it's own scripts, load them one by one to maintain execution order. | ||
// eslint-disable-next-line no-restricted-syntax | ||
for (const script of [...block.querySelectorAll('script')]) { | ||
let waitForLoad = Promise.resolve(); | ||
// The script element added by innerHTML is NOT executed. | ||
// The workaround is to create the new script tag, copy attibutes and content. | ||
const newScript = document.createElement('script'); | ||
newScript.setAttribute('type', 'text/javascript'); | ||
// Copy script attributes to the new element. | ||
script.getAttributeNames().forEach((attrName) => { | ||
const attrValue = script.getAttribute(attrName); | ||
newScript.setAttribute(attrName, attrValue); | ||
|
||
if (attrName === 'src') { | ||
waitForLoad = new Promise((resolve) => { | ||
newScript.addEventListener('load', resolve); | ||
}); | ||
} | ||
}); | ||
newScript.innerHTML = script.innerHTML; | ||
script.remove(); | ||
document.body.append(newScript); | ||
|
||
// eslint-disable-next-line no-await-in-loop | ||
await waitForLoad; | ||
} | ||
|
||
const inputs = block.querySelectorAll('input'); | ||
inputs.forEach((formEl) => { | ||
formEl.placeholder = i18n(formEl.placeholder); | ||
formEl.ariaLabel = i18n(formEl.ariaLabel); | ||
}); | ||
|
||
const taEl = block.querySelector('textarea'); | ||
if (taEl && taEl.placeholder) taEl.placeholder = i18n(taEl.placeholder); | ||
|
||
// Get all checkboxes with class 'checkbox' | ||
const checkboxes = document.querySelectorAll('input[type="checkbox"]'); | ||
|
||
// Define a function declaration to handle the change event | ||
function handleChange() { | ||
// Store the clicked checkbox in a variable | ||
const clickedCheckbox = this; | ||
|
||
// Uncheck all checkboxes that are not the clicked checkbox | ||
checkboxes.forEach((cb) => { | ||
if (cb !== clickedCheckbox) { | ||
cb.checked = false; | ||
} | ||
}); | ||
} | ||
|
||
// Add the change event listener to each checkbox using the function declaration | ||
checkboxes.forEach((checkbox) => { | ||
checkbox.addEventListener('change', handleChange); | ||
checkbox.nextElementSibling.addEventListener('change', handleChange); | ||
}); | ||
|
||
block.style.display = displayValue; | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<div class="contact-form"> | ||
<h1 id="contact-us">Contact Us</h1> | ||
<div class="company-name"></div> | ||
<div class="company-email"></div> | ||
<div class="company-phone">Direct: </div> | ||
<form id="contactForm" class="form-elements" method="post" action="https://www.commonmoves.com/bin/bhhs/websiteTopicServlet" onsubmit="return submitContactForm(this)"> | ||
<div class="message"> | ||
<svg class="icon error" role="presentation"> | ||
<use xlink:href="/icons/icons.svg#error"></use> | ||
</svg> | ||
<svg class="icon success" role="presentation"> | ||
<use xlink:href="/icons/icons.svg#success"></use> | ||
</svg> | ||
<div class="details"> | ||
<span></span> | ||
</div> | ||
</div> | ||
<div class="inputs"> | ||
<div class="name"> | ||
<input name="first_name" type="text" placeholder="First Name*" aria-label="first name" | ||
aria-required="true" autocomplete="given-name"> | ||
<input name="last_name" type="text" placeholder="Last Name*" aria-label="last name" | ||
aria-required="true" autocomplete="family-name"> | ||
</div> | ||
<div class="contact-info"> | ||
<input name="email" type="email" placeholder="Email Address*" aria-label="email address" | ||
aria-required="true" autocomplete="email"> | ||
<input name="phone" type="text" placeholder="Phone Number*" aria-label="phone number" | ||
aria-required="true" autocomplete="tel-national"> | ||
</div> | ||
<textarea name="comments" | ||
placeholder="Leave a comment or question and we'll get back to you shortly." | ||
autocomplete="off"></textarea> | ||
</div> | ||
<div class="agent"> | ||
<div class="question">Are you currently working with an agent?</div> | ||
<div class="agent-check"> | ||
<div> | ||
<input name="agentY" type="checkbox" aria-label="checkbox" tabindex="-1" value="" autocomplete="off" checked> | ||
<div class="checkbox"> | ||
<svg class="empty"> | ||
<use xlink:href="/icons/icons.svg#checkmark"></use> | ||
</svg> | ||
</div> | ||
<span class="label">yes</span> | ||
</div> | ||
<div> | ||
<input name="agentN" type="checkbox" aria-label="checkbox" tabindex="-1" value="" autocomplete="off"> | ||
<div class="checkbox"> | ||
<svg class="empty"> | ||
<use xlink:href="/icons/icons.svg#checkmark"></use> | ||
</svg> | ||
</div> | ||
<span class="label">no</span> | ||
</div> | ||
</div> | ||
<div class="disclaimer"></div> | ||
</div> | ||
<div id="captcha-20285" class="g-recaptcha contact-form-captcha" captcha-render="1"> | ||
<div style="width: 304px; height: 78px;"> | ||
<iframe title="reCAPTCHA" width="304" height="78" role="presentation" name="a-duze5gwmci0x" | ||
frameborder="0" scrolling="no" | ||
sandbox="allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation allow-modals allow-popups-to-escape-sandbox allow-storage-access-by-user-activation" | ||
src="https://www.google.com/recaptcha/api2/anchor?ar=2&k=6LebYaYUAAAAAC9SqASljwaF57MpKSvEkwDOzk6l&co=aHR0cHM6Ly93d3cuY29tbW9ubW92ZXMuY29tOjQ0Mw..&hl=en&v=Ya-Cd6PbRI5ktAHEhm9JuKEu&size=normal&cb=sa2502jzdt91"></iframe> | ||
<textarea id="g-recaptcha-response-3" name="g-recaptcha-response" | ||
class="g-recaptcha-response" | ||
style="width: 250px; height: 40px; border: 1px solid rgb(193, 193, 193); margin: 10px 25px; padding: 0px; resize: none; display: none;"></textarea> | ||
</div> | ||
<iframe style="display: none;"></iframe> | ||
</div> | ||
<div class="cta"> | ||
<div class="button-container"> | ||
<a href="" class="button primary submit">Send</a> | ||
<a href="" class="button cancel">Cancel</a> | ||
</div> | ||
</div> | ||
</form> | ||
</div> |
Oops, something went wrong.