// Gen4 Formulier Embedder Script met verbeterde positionering (function() { // Wacht tot het document volledig is geladen if (document.readyState === 'complete' || document.readyState === 'interactive') { initGen4Form(); } else { document.addEventListener('DOMContentLoaded', initGen4Form); } function initGen4Form() { // Zoek alle div elementen op de pagina const formContainers = document.querySelectorAll('[id="plaats-form-hier"]'); // Bepaal de client ID (indien opgegeven in data-client attribuut) // Anders gebruik origin als client-id formContainers.forEach(container => { const clientId = container.getAttribute('data-client') || encodeURIComponent(window.location.hostname); // Lees de positie-attributen (x en y) const xPosition = container.getAttribute('x') || 'right'; const yPosition = container.getAttribute('y') || 'bottom'; console.log('Detected position attributes:', { x: xPosition, y: yPosition }); // Verberg de container container.style.display = 'none'; // Maak het formulier createForm(container, clientId, xPosition, yPosition); }); } async function createForm(container, clientId, xPosition, yPosition) { try { // Haal de configuratie op voor deze specifieke client const formConfig = await fetchFormConfig(clientId); // Voeg stijlen toe const style = document.createElement('style'); style.textContent = formConfig.css; document.head.appendChild(style); // Check of dit een floating form is const isFloating = formConfig.floating && formConfig.floating.enabled; if (isFloating) { // Genereer custom HTML met de posities const customHTML = createPositionedHTML(xPosition, yPosition, formConfig); // Voeg het floating form toe aan de body (niet aan de container) document.body.insertAdjacentHTML('beforeend', customHTML); // Setup de click events voor de floating button en close button setupFloatingFormEvents(); } else { // Normale form mode - voeg toe aan de container container.style.display = ''; container.innerHTML = formConfig.html; } // Selecteer het formulier element (werkt voor zowel normale als floating forms) const form = document.querySelector('#gen4-contact-form'); // Dynamisch velden toevoegen op basis van formConfig.fields if (formConfig.fields && Array.isArray(formConfig.fields)) { formConfig.fields.forEach(field => { const fieldGroup = document.createElement('div'); fieldGroup.className = 'gen4-form-group'; // Label maken const label = document.createElement('label'); label.setAttribute('for', field.name); label.textContent = field.label; fieldGroup.appendChild(label); // Veld maken op basis van type let inputElement; switch(field.type) { case 'textarea': inputElement = document.createElement('textarea'); inputElement.setAttribute('rows', field.rows || 4); break; case 'select': inputElement = document.createElement('select'); if (field.options && Array.isArray(field.options)) { field.options.forEach(option => { const optionElement = document.createElement('option'); optionElement.value = option.value; optionElement.textContent = option.label; inputElement.appendChild(optionElement); }); } break; case 'checkbox': inputElement = document.createElement('input'); inputElement.type = 'checkbox'; // Speciale behandeling voor checkbox label label.removeAttribute('for'); const checkboxContainer = document.createElement('div'); checkboxContainer.className = 'gen4-checkbox-container'; checkboxContainer.appendChild(inputElement); checkboxContainer.appendChild(document.createTextNode(' ' + field.label)); fieldGroup.innerHTML = ''; fieldGroup.appendChild(checkboxContainer); break; case 'radio': if (field.options && Array.isArray(field.options)) { const radioGroup = document.createElement('div'); radioGroup.className = 'gen4-radio-group'; field.options.forEach(option => { const radioContainer = document.createElement('div'); radioContainer.className = 'gen4-radio-option'; const radioInput = document.createElement('input'); radioInput.type = 'radio'; radioInput.name = field.name; radioInput.id = `${field.name}_${option.value}`; radioInput.value = option.value; const radioLabel = document.createElement('label'); radioLabel.setAttribute('for', `${field.name}_${option.value}`); radioLabel.textContent = option.label; radioContainer.appendChild(radioInput); radioContainer.appendChild(radioLabel); radioGroup.appendChild(radioContainer); }); fieldGroup.appendChild(radioGroup); inputElement = null; // Al toegevoegd } break; default: inputElement = document.createElement('input'); inputElement.type = field.type; } // Attributen toevoegen aan het input element if (inputElement) { inputElement.id = field.name; inputElement.name = field.name; if (field.required) { inputElement.required = true; } if (field.placeholder) { inputElement.placeholder = field.placeholder; } // Eventuele extra attributen toevoegen if (field.attributes) { Object.keys(field.attributes).forEach(attr => { inputElement.setAttribute(attr, field.attributes[attr]); }); } fieldGroup.appendChild(inputElement); } // Voeg foutmelding element toe indien nodig if ((field.attributes && field.attributes['data-validate']) || (field.type === 'email' && field.name === 'email_confirm')) { const errorMessage = document.createElement('div'); errorMessage.className = 'gen4-error-message'; errorMessage.id = `error-${field.name}`; fieldGroup.appendChild(errorMessage); } form.appendChild(fieldGroup); }); } // Submit button toevoegen const submitButton = document.createElement('button'); submitButton.type = 'submit'; submitButton.className = 'gen4-form-submit'; submitButton.textContent = (formConfig.submitButton && formConfig.submitButton.text) || 'Verzenden'; // Positie van button instellen als dat is opgegeven if (formConfig.submitButton && formConfig.submitButton.position) { const buttonContainer = document.createElement('div'); buttonContainer.className = `gen4-button-container gen4-button-${formConfig.submitButton.position}`; buttonContainer.appendChild(submitButton); form.appendChild(buttonContainer); } else { form.appendChild(submitButton); } // Formulier validatie en submit handler instellen setupFormValidation(form, formConfig); setupFormSubmission(clientId, formConfig); } catch (error) { console.error('Fout bij het laden van het formulier:', error); container.innerHTML = '
Er is een fout opgetreden bij het laden van het formulier.
'; container.style.display = 'block'; } } // Genereer aangepaste HTML met direct ingestelde posities function createPositionedHTML(xPosition, yPosition, formConfig) { let buttonStyle = ''; let containerStyle = ''; // Bepaal button positie switch(xPosition.toLowerCase()) { case 'left': buttonStyle += 'left: 20px; right: auto;'; break; case 'center': buttonStyle += 'left: 50%; right: auto; transform: translateX(-50%);'; break; default: // right buttonStyle += 'right: 20px; left: auto;'; } switch(yPosition.toLowerCase()) { case 'top': buttonStyle += 'top: 20px; bottom: auto;'; break; case 'middle': if (xPosition.toLowerCase() === 'center') { buttonStyle = 'left: 50%; top: 50%; transform: translate(-50%, -50%);'; } else { buttonStyle += 'top: 50%; bottom: auto; transform: translateY(-50%);'; } break; default: // bottom buttonStyle += 'bottom: 20px; top: auto;'; } // Bepaal container positie relatief aan de button switch(xPosition.toLowerCase()) { case 'left': containerStyle += 'left: 20px; right: auto;'; break; case 'center': containerStyle += 'left: 50%; right: auto; transform: translateX(-50%);'; break; default: // right containerStyle += 'right: 20px; left: auto;'; } switch(yPosition.toLowerCase()) { case 'top': containerStyle += 'top: 80px; bottom: auto;'; break; case 'middle': if (xPosition.toLowerCase() === 'center') { containerStyle = 'left: 50%; top: 50%; transform: translate(-50%, -50%);'; } else { containerStyle += 'top: 50%; bottom: auto; transform: translateY(-50%);'; } break; default: // bottom containerStyle += 'bottom: 80px; top: auto;'; } const buttonIcon = ` `; const buttonText = formConfig.floating && formConfig.floating.buttonText ? formConfig.floating.buttonText : 'Contact opnemen'; // Bouw de HTML met inline styles return `

${formConfig.floating && formConfig.floating.title ? formConfig.floating.title : 'Contact opnemen'}

`; } // Setup event listeners voor de floating form function setupFloatingFormEvents() { const floatingButton = document.getElementById('gen4-floating-button'); const floatingContainer = document.getElementById('gen4-floating-container'); const closeButton = document.getElementById('gen4-close-button'); if (floatingButton && floatingContainer && closeButton) { // Open het formulier wanneer op de button wordt geklikt floatingButton.addEventListener('click', function() { floatingContainer.classList.add('visible'); }); // Sluit het formulier wanneer op de sluit-knop wordt geklikt closeButton.addEventListener('click', function() { floatingContainer.classList.remove('visible'); }); // Sluit het formulier wanneer buiten het formulier wordt geklikt document.addEventListener('click', function(event) { if (floatingContainer.classList.contains('visible') && !floatingContainer.contains(event.target) && !floatingButton.contains(event.target)) { floatingContainer.classList.remove('visible'); } }); } } // Voeg validatie toe aan het formulier function setupFormValidation(form, formConfig) { // Check of validatie enabled is if (!formConfig.validation || !formConfig.validation.enabled) { return; } // Validatie voor email matching const emailField = form.querySelector('[name="email"]'); const emailConfirmField = form.querySelector('[name="email_confirm"]'); if (emailField && emailConfirmField) { // Valideer bij input in confirm veld emailConfirmField.addEventListener('input', function() { validateEmailMatch(emailField, emailConfirmField, formConfig); }); // Valideer ook wanneer het originele e-mailveld verandert emailField.addEventListener('input', function() { if (emailConfirmField.value) { validateEmailMatch(emailField, emailConfirmField, formConfig); } }); } } // Valideer of e-mailadressen overeenkomen function validateEmailMatch(emailField, emailConfirmField, formConfig) { const errorElement = document.getElementById(`error-${emailConfirmField.name}`); if (emailField.value !== emailConfirmField.value) { emailConfirmField.classList.add('error'); if (errorElement) { errorElement.textContent = formConfig.validation.messages.email_mismatch || 'De e-mailadressen komen niet overeen.'; errorElement.classList.add('visible'); } return false; } else { emailConfirmField.classList.remove('error'); if (errorElement) { errorElement.classList.remove('visible'); } return true; } } async function fetchFormConfig(clientId) { // Haal de HTML en CSS configuratie op van de server const response = await fetch(`https://hzg.gen4.nl/webhook/form-config?client=${clientId}`); if (!response.ok) { throw new Error('Kon de formulier configuratie niet laden'); } return response.json(); } function setupFormSubmission(clientId, formConfig) { const form = document.querySelector('#gen4-contact-form'); const messageDiv = document.querySelector('#gen4-form-message'); if (!form || !messageDiv) { console.error('Formulier elementen niet gevonden'); return; } form.addEventListener('submit', function(e) { e.preventDefault(); // Valideer het formulier eerst als validatie ingeschakeld is if (formConfig.validation && formConfig.validation.enabled) { // Check e-mail matching als beide velden bestaan const emailField = form.querySelector('[name="email"]'); const emailConfirmField = form.querySelector('[name="email_confirm"]'); if (emailField && emailConfirmField) { if (!validateEmailMatch(emailField, emailConfirmField, formConfig)) { return; // Stop versturen als e-mailadressen niet matchen } } } // Verzamel alle formuliervelden (werkt met dynamische velden) const formData = { clientId: clientId, timestamp: new Date().toISOString(), origin: encodeURIComponent(window.location.origin) }; // Voeg alle form velden toe aan formData Array.from(form.elements).forEach(element => { if (element.name && element.name !== 'submit' && element.name !== 'email_confirm') { // Bevestigingsvelden (zoals email_confirm) uitsluiten van verzending // Speciale behandeling voor checkboxes if (element.type === 'checkbox') { formData[element.name] = element.checked; } // Speciale behandeling voor radio buttons else if (element.type === 'radio') { if (element.checked) { formData[element.name] = element.value; } } // Normale velden else { formData[element.name] = element.value; } } }); // Verzend data naar n8n webhook fetch('https://hzg.gen4.nl/webhook/form-submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }) .then(response => { if (!response.ok) { throw new Error('Netwerkrespons was niet OK'); } return response.json(); }) .then(data => { // Toon succesbericht messageDiv.textContent = data.message || 'Bedankt! Je bericht is succesvol verzonden.'; messageDiv.className = 'gen4-form-message success'; form.reset(); // Als het een floating form is, sluit het automatisch na enkele seconden if (formConfig.floating && formConfig.floating.enabled) { setTimeout(function() { const floatingContainer = document.getElementById('gen4-floating-container'); if (floatingContainer && floatingContainer.classList.contains('visible')) { floatingContainer.classList.remove('visible'); } }, 3000); // Sluit na 3 seconden } }) .catch(error => { // Toon foutmelding messageDiv.textContent = 'Er is een fout opgetreden bij het verzenden van je bericht. Probeer het later nog eens.'; messageDiv.className = 'gen4-form-message error'; console.error('Fout:', error); }); }); } })();