breznflow/assets/admin.js
Michael fd83e4810b BreznFlow 1.0.0 — WordPress.org submission
Initial public release of BreznFlow, an n8n workflow renderer for WordPress.
Fully PHPCS-compliant (WordPress Coding Standards), security-hardened,
and ready for WordPress.org plugin review.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 11:27:36 +00:00

199 lines
7.6 KiB
JavaScript

/* BreznFlow — Admin JS (vanilla ES2020, no dependencies) */
/* global breznflowAdmin */
(function () {
'use strict';
// ── AJAX helpers ──────────────────────────────────────────────────────────
function post(action, data, callback) {
const params = new URLSearchParams();
params.append('action', action);
params.append('nonce', breznflowAdmin.nonce);
for (const [k, v] of Object.entries(data)) {
params.append(k, v);
}
fetch(breznflowAdmin.ajaxUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params.toString(),
})
.then(function(r) { return r.json(); })
.then(callback)
.catch(function(err) {
callback({ success: false, data: { message: String(err) } });
});
}
// ── Step 1: Validation ────────────────────────────────────────────────────
const jsonTextarea = document.getElementById('breznflow-json');
const validateBtn = document.getElementById('breznflow-validate-btn');
const submitBtn = document.getElementById('breznflow-step1-submit');
const resultDiv = document.getElementById('breznflow-validation-result');
function showResult(success, message) {
if (!resultDiv) return;
resultDiv.removeAttribute('hidden');
resultDiv.className = success ? 'success' : 'error';
resultDiv.textContent = message;
}
if (validateBtn && jsonTextarea) {
validateBtn.addEventListener('click', function () {
const json = jsonTextarea.value.trim();
if (!json) {
showResult(false, breznflowAdmin.i18n.pasteFirst || 'Please paste a workflow JSON first.');
return;
}
validateBtn.disabled = true;
validateBtn.textContent = breznflowAdmin.i18n.validating || 'Validating...';
post('breznflow_validate_json', { json: json }, function(resp) {
validateBtn.disabled = false;
validateBtn.textContent = breznflowAdmin.i18n.validateJson || 'Validate JSON';
if (resp.success) {
const msg = (breznflowAdmin.i18n.valid || 'Valid n8n workflow') +
': ' + resp.data.name + ' \u2014 ' + resp.data.nodes + ' ' + (breznflowAdmin.i18n.nodes || 'nodes');
showResult(true, msg);
if (submitBtn) submitBtn.disabled = false;
} else {
showResult(false, (breznflowAdmin.i18n.invalid || 'Invalid') + ': ' + (resp.data && resp.data.message ? resp.data.message : 'Unknown error'));
if (submitBtn) submitBtn.disabled = true;
}
});
});
}
// ── Step 1: File upload → textarea ────────────────────────────────────────
const fileInput = document.getElementById('breznflow-file');
if (fileInput && jsonTextarea) {
fileInput.addEventListener('change', function () {
const file = this.files && this.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
jsonTextarea.value = e.target.result;
if (resultDiv) {
resultDiv.setAttribute('hidden', '');
resultDiv.className = '';
resultDiv.textContent = '';
}
if (submitBtn) submitBtn.disabled = true;
};
reader.readAsText(file);
});
}
// ── Step 1: URL fetch ─────────────────────────────────────────────────────
const urlInput = document.getElementById('breznflow-url');
const fetchBtn = document.getElementById('breznflow-fetch-url');
if (fetchBtn && urlInput && jsonTextarea) {
fetchBtn.addEventListener('click', function () {
const url = urlInput.value.trim();
if (!url) return;
fetchBtn.disabled = true;
fetchBtn.textContent = breznflowAdmin.i18n.fetching || 'Fetching...';
post('breznflow_fetch_url', { url: url }, function(resp) {
fetchBtn.disabled = false;
fetchBtn.textContent = breznflowAdmin.i18n.fetch || 'Fetch';
if (resp.success && resp.data && resp.data.json) {
jsonTextarea.value = resp.data.json;
if (submitBtn) submitBtn.disabled = true;
if (resultDiv) {
resultDiv.setAttribute('hidden', '');
resultDiv.textContent = '';
}
} else {
showResult(false, resp.data && resp.data.message ? resp.data.message : (breznflowAdmin.i18n.fetchFailed || 'Fetch failed'));
}
});
});
}
// ── Copy Shortcode buttons ────────────────────────────────────────────────
function attachCopyButtons() {
document.querySelectorAll('.breznflow-copy-sc').forEach(function(btn) {
btn.addEventListener('click', function () {
const sc = btn.getAttribute('data-sc') || '';
const label = btn.textContent;
if (!sc) return;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(sc).then(function() {
btn.textContent = breznflowAdmin.i18n.copied || 'Copied!';
setTimeout(function() { btn.textContent = label; }, 2000);
}).catch(function() {
fallbackCopy(sc, btn, label);
});
} else {
fallbackCopy(sc, btn, label);
}
});
});
}
function fallbackCopy(text, btn, label) {
const ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.focus();
ta.select();
try {
document.execCommand('copy');
btn.textContent = breznflowAdmin.i18n.copied || 'Copied!';
setTimeout(function() { btn.textContent = label; }, 2000);
} catch (e) {
// silently ignore
}
document.body.removeChild(ta);
}
attachCopyButtons();
// ── Step 2: Live shortcode preview ────────────────────────────────────────
const scLive = document.getElementById('breznflow-shortcode-live');
if (scLive) {
const postIdInput = document.querySelector('input[name="breznflow_post_id"]');
const postId = postIdInput ? postIdInput.value : '';
const modeRadios = document.querySelectorAll('input[name="default_mode"]');
const showTitleCb = document.querySelector('input[name="show_title"]');
const showInfoCb = document.querySelector('input[name="show_infobox"]');
const showDlCb = document.querySelector('input[name="show_download"]');
const zoomInput = document.querySelector('input[name="default_zoom"]');
function updatePreview() {
let sc = '[breznflow id="' + postId + '"';
const modeVal = document.querySelector('input[name="default_mode"]:checked');
if (modeVal && modeVal.value !== 'visual') sc += ' mode="' + modeVal.value + '"';
if (zoomInput && zoomInput.value !== '100') sc += ' zoom="' + zoomInput.value + '"';
if (showTitleCb && !showTitleCb.checked) sc += ' show_title="0"';
if (showInfoCb && !showInfoCb.checked) sc += ' show_infobox="0"';
if (showDlCb && showDlCb.checked) sc += ' show_download="1"';
sc += ']';
scLive.textContent = sc;
// Update copy button data attribute
const copyBtn = scLive.nextElementSibling;
if (copyBtn && copyBtn.classList.contains('breznflow-copy-sc')) {
copyBtn.setAttribute('data-sc', sc);
}
}
modeRadios.forEach(function(r) { r.addEventListener('change', updatePreview); });
if (showTitleCb) showTitleCb.addEventListener('change', updatePreview);
if (showInfoCb) showInfoCb.addEventListener('change', updatePreview);
if (showDlCb) showDlCb.addEventListener('change', updatePreview);
if (zoomInput) zoomInput.addEventListener('input', updatePreview);
}
}());