Photographe de Mariage, ISTANY
/
VIVEZ L'INSTANT, NOUS CRÉONS VOS IMAGES
L'OFFRE ISTANY

ISTANY Forms JS Module

/**
* ISTANY Forms Module v1.0
* Vanilla JS | fetch() | WP REST API
* Formulaires : contact, guide, multistep devis
* Multi-location : chaque formulaire utilise data-location
*/
(function () {
‘use strict’;

// ─── Config (injectée par PHP via window.ISTANY_FORM) ───────────────────────
var CFG = window.ISTANY_FORM || {};
var ENDPOINT = CFG.endpoint || ‘/wp-json/istany/v1/contact’;
var NONCE = CFG.nonce ||  »;

// ─── Validation ─────────────────────────────────────────────────────────────
function clearErrors(scope) {
scope.querySelectorAll(‘.istany-error’).forEach(function (el) { el.remove(); });
scope.querySelectorAll(‘.istany-field-error’).forEach(function (el) {
el.classList.remove(‘istany-field-error’);
});
}

function showFieldError(field, message) {
field.classList.add(‘istany-field-error’);
var err = document.createElement(‘span’);
err.className = ‘istany-error’;
err.setAttribute(‘role’, ‘alert’);
err.textContent = message;
field.parentNode.insertBefore(err, field.nextSibling);
}

function showGlobalError(container, message) {
var existing = container.querySelector(‘.istany-error-global’);
if (existing) existing.remove();
var err = document.createElement(‘p’);
err.className = ‘istany-error istany-error-global’;
err.setAttribute(‘role’, ‘alert’);
err.textContent = message;
container.insertBefore(err, container.firstChild);
}

function isValidEmail(value) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}

function validateFields(fields) {
var valid = true;
Array.prototype.forEach.call(fields, function (field) {
if (!field.required) return;
if (!field.value.trim()) {
showFieldError(field, ‘Ce champ est obligatoire.’);
valid = false;
} else if (field.type === ’email’ && !isValidEmail(field.value.trim())) {
showFieldError(field, ‘Adresse e-mail invalide.’);
valid = false;
}
});
return valid;
}

// ─── Multistep : stepper ────────────────────────────────────────────────────
function updateStepper(form, step) {
for (var i = 1; i <= 3; i++) { var el = form.querySelector('[data-stepper-step="' + i + '"]'); if (!el) continue; el.classList.remove('active', 'done'); if (i < step) el.classList.add('done'); else if (i === step) el.classList.add('active'); } } function getCurrentStep(form) { var active = form.querySelector('[data-step].active'); return active ? parseInt(active.dataset.step, 10) : 1; } function goToStep(form, step) { var current = getCurrentStep(form); var from = form.querySelector('[data-step="' + current + '"]'); var to = form.querySelector('[data-step="' + step + '"]'); if (from) from.classList.remove('active'); if (to) to.classList.add('active'); updateStepper(form, step); } // ─── Multistep : cartes cliquables ────────────────────────────────────────── function bindCards(form) { form.querySelectorAll('.ms-choice:not(.ms-multi)').forEach(function (card) { card.addEventListener('click', function () { var group = card.dataset.group; form.querySelectorAll('.ms-choice[data-group="' + group + '"]').forEach(function (c) { c.classList.remove('selected'); }); card.classList.add('selected'); }); }); form.querySelectorAll('.ms-choice.ms-multi').forEach(function (card) { card.addEventListener('click', function () { card.classList.toggle('selected'); }); }); } // ─── Collecte des données ─────────────────────────────────────────────────── function collectData(form) { var data = { location: form.dataset.location || '', form_id: form.id || '', form_type: form.dataset.formType || 'contact', nonce: NONCE, website: '', prenom: '', nom: '', email: '', tel: '', date: '', lieu: '', message: '', style: '', prestation: '' }; // Honeypot var hp = form.querySelector('[name="website"]'); if (hp) data.website = hp.value; // Champs nommés standards ['prenom', 'nom', 'email', 'tel', 'date', 'lieu', 'message'].forEach(function (name) { var el = form.querySelector('[name="' + name + '"]'); if (!el) { // Fallback pour les IDs du multistep (msPrenom, msEmail…) var camel = name.charAt(0).toUpperCase() + name.slice(1); el = form.querySelector('#ms' + camel); } if (el) data[name] = el.value.trim(); }); // Cartes sélectionnées var prests = []; form.querySelectorAll('.ms-choice.selected:not(.ms-multi)').forEach(function (c) { if (c.dataset.group === 'style') data.style = c.dataset.value; }); form.querySelectorAll('.ms-choice.ms-multi.selected').forEach(function (c) { prests.push(c.dataset.value); }); data.prestation = prests.join(', '); return data; } // ─── Soumission AJAX ──────────────────────────────────────────────────────── function submitForm(form, submitBtn, onSuccess) { var origLabel = submitBtn.textContent; submitBtn.disabled = true; submitBtn.textContent = 'Envoi en cours…'; fetch(ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(collectData(form)) }) .then(function (res) { return res.json().then(function (json) { return { ok: res.ok, json: json }; }); }) .then(function (result) { if (result.ok && result.json.success) { onSuccess(result.json.message || ''); } else { submitBtn.disabled = false; submitBtn.textContent = origLabel; var nav = submitBtn.closest('.ms-nav') || submitBtn.parentNode; showGlobalError(nav, result.json.message || 'Une erreur est survenue. Veuillez réessayer.'); } }) .catch(function () { submitBtn.disabled = false; submitBtn.textContent = origLabel; var nav = submitBtn.closest('.ms-nav') || submitBtn.parentNode; showGlobalError(nav, 'Erreur réseau. Veuillez réessayer.'); }); } // ─── Init : formulaire multistep ──────────────────────────────────────────── function initMultistepForm(form) { bindCards(form); // Navigation (délégation d'événements) form.addEventListener('click', function (e) { var btn = e.target.closest('[data-action]'); if (!btn || btn.type === 'submit') return; var action = btn.dataset.action; var step = parseInt(btn.dataset.step, 10); if (action === 'next') goToStep(form, step + 1); if (action === 'prev') goToStep(form, step - 1); }); // Soumission form.addEventListener('submit', function (e) { e.preventDefault(); clearErrors(form); if (!validateFields(form.querySelectorAll('[required]'))) return; var submitBtn = form.querySelector('[type="submit"]'); submitForm(form, submitBtn, function () { var ms3 = form.querySelector('[data-step="3"]'); var success = form.querySelector('#msSuccess'); if (ms3) ms3.classList.remove('active'); if (success) success.classList.add('active'); }); }); } // ─── Init : formulaire simple ──────────────────────────────────────────────── function initSimpleForm(form) { form.addEventListener('submit', function (e) { e.preventDefault(); clearErrors(form); if (!validateFields(form.querySelectorAll('[required]'))) return; var submitBtn = form.querySelector('[type="submit"]'); submitForm(form, submitBtn, function (message) { form.style.display = 'none'; var box = document.createElement('div'); box.className = 'istany-success'; box.textContent = message || 'Merci ! Nous vous répondrons sous 48 heures.'; form.parentNode.insertBefore(box, form.nextSibling); }); }); } // ─── Auto-initialisation ──────────────────────────────────────────────────── function init() { document.querySelectorAll('form[data-location]').forEach(function (form) { if (form.dataset.formType === 'multistep-devis') { initMultistepForm(form); } else { initSimpleForm(form); } }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } }());


Warning: Undefined variable $data in /home/clients/218c9a7b522e0cc297e853281773c317/web/wp-content/viewcache/946ac7c0879f4e4965e0d3452b491de1 on line 12

Warning: Undefined variable $data in /home/clients/218c9a7b522e0cc297e853281773c317/web/wp-content/viewcache/946ac7c0879f4e4965e0d3452b491de1 on line 13

Warning: Undefined variable $data in /home/clients/218c9a7b522e0cc297e853281773c317/web/wp-content/viewcache/946ac7c0879f4e4965e0d3452b491de1 on line 14
FERMER LE MENU
L'OFFRE ISTANY