/** * OG Image Backend Module – live preview via AJAX * EXT:vitec/Resources/Public/Javascript/og-image-preview.js */ (function () { 'use strict'; /** Debounce helper */ function debounce(fn, ms) { let t; return function (...args) { clearTimeout(t); t = setTimeout(() => fn.apply(this, args), ms); }; } /** Collect all form values into a FormData-compatible plain object */ function collectFormData() { const form = document.getElementById('vitecOgForm'); if (!form) return {}; const fd = new FormData(form); const out = {}; for (const [key, val] of fd.entries()) { // key looks like "ogimage[something]" const match = key.match(/^ogimage\[(.+)]$/); if (match) { out[key] = val; } } return out; } /** POST to the preview endpoint, update the */ async function requestPreview() { const form = document.getElementById('vitecOgForm'); const spinner = document.getElementById('previewSpinner'); const img = document.getElementById('ogPreviewImg'); const placeholder = document.getElementById('ogPreviewPlaceholder'); const dl = document.getElementById('previewDownload'); if (!form) return; if (spinner) spinner.classList.remove('d-none'); try { const body = new URLSearchParams(collectFormData()); const previewUrl = form.dataset.previewUrl || window.location.href; const resp = await fetch(previewUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString(), }); if (!resp.ok) throw new Error('Server error ' + resp.status); const json = await resp.json(); if (json.success && json.dataUri) { img.src = json.dataUri; img.style.display = 'block'; if (placeholder) placeholder.style.display = 'none'; if (dl) { dl.href = json.dataUri; dl.classList.remove('d-none'); } } else { console.warn('[OG Preview]', json.message); } } catch (e) { console.error('[OG Preview] fetch failed:', e); } finally { if (spinner) spinner.classList.add('d-none'); } } const debouncedPreview = debounce(requestPreview, 600); // ── Wire up events once DOM is ready ────────────────────────────── document.addEventListener('DOMContentLoaded', function () { // Manual preview button const btn = document.getElementById('btnPreview'); if (btn) { btn.addEventListener('click', requestPreview); } // Auto-preview on any .js-live input change document.querySelectorAll('.js-live').forEach(function (el) { el.addEventListener('input', debouncedPreview); el.addEventListener('change', debouncedPreview); }); // Background type toggle (show colour vs image picker) function syncBgType() { const colorWrap = document.getElementById('bg-color-wrap'); const imageWrap = document.getElementById('bg-image-wrap'); const selected = document.querySelector('input.js-bg-type:checked'); if (!selected) return; if (selected.value === 'image') { colorWrap && (colorWrap.style.display = 'none'); imageWrap && (imageWrap.style.display = 'block'); } else { colorWrap && (colorWrap.style.display = 'block'); imageWrap && (imageWrap.style.display = 'none'); } } document.querySelectorAll('input.js-bg-type').forEach(function (el) { el.addEventListener('change', function () { syncBgType(); debouncedPreview(); }); }); const bgImageSelect = document.querySelector('select[name="ogimage[bg_image]"]'); if (bgImageSelect) { bgImageSelect.addEventListener('change', function () { const imageTypeRadio = document.querySelector('input.js-bg-type[value="image"]'); if (imageTypeRadio) { imageTypeRadio.checked = true; } syncBgType(); requestPreview(); }); } syncBgType(); // initialise on load // Hex text ↔ colour picker sync document.querySelectorAll('.js-hex-sync').forEach(function (hexInput) { const targetId = hexInput.dataset.target; const picker = document.getElementById(targetId); if (!picker) return; picker.addEventListener('input', function () { hexInput.value = picker.value; }); hexInput.addEventListener('input', function () { const val = hexInput.value.trim(); if (/^#[0-9a-fA-F]{6}$/.test(val)) { picker.value = val; picker.dispatchEvent(new Event('input', { bubbles: true })); } }); }); // Preset buttons document.querySelectorAll('.js-preset').forEach(function (btn) { btn.addEventListener('click', function () { const bg = btn.dataset.bg; const tc = btn.dataset.titleColor; const sc = btn.dataset.subtitleColor; const bgInput = document.getElementById('bgColor'); if (bgInput && bg) { bgInput.value = bg; bgInput.dispatchEvent(new Event('input', {bubbles:true})); } const tInput = document.getElementById('titleColor'); if (tInput && tc) { tInput.value = tc; tInput.dispatchEvent(new Event('input', {bubbles:true})); } const sInput = document.getElementById('subtitleColor'); if (sInput && sc) { sInput.value = sc; sInput.dispatchEvent(new Event('input', {bubbles:true})); } debouncedPreview(); }); }); }); })();