174 lines
6.2 KiB
JavaScript
174 lines
6.2 KiB
JavaScript
/**
|
||
* 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 <img> */
|
||
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();
|
||
});
|
||
});
|
||
|
||
});
|
||
|
||
})();
|