pub(super) const SOURCE: &str = r#"
// ── Key-value editor ──────────────────────────────────────────────────
function setupKeyValueEditor() {
var editors = document.querySelectorAll('[data-kv-editor]');
for (var i = 0; i < editors.length; i++) {
initKeyValueEditor(editors[i]);
}
}
function initKeyValueEditor(editor) {
var rowsContainer = editor.querySelector('[data-kv-rows]');
var addBtn = editor.querySelector('[data-kv-add]');
var tmpl = editor.querySelector('[data-kv-row-template]');
if (!rowsContainer || !addBtn || !tmpl) {
return;
}
addBtn.addEventListener('click', function() {
var clone = tmpl.content.cloneNode(true);
rowsContainer.appendChild(clone);
syncHiddenField(editor);
});
rowsContainer.addEventListener('click', function(e) {
var target = e.target;
// Walk up from target to nearest [data-kv-delete] (if any).
var delBtn = target.closest ? target.closest('[data-kv-delete]') : null;
if (!delBtn) {
return;
}
var row = delBtn.closest('[data-kv-row]');
if (row && row.parentNode) {
row.parentNode.removeChild(row);
syncHiddenField(editor);
}
});
rowsContainer.addEventListener('input', function(e) {
var target = e.target;
if (!target || !target.hasAttribute) {
return;
}
if (target.hasAttribute('data-kv-key') || target.hasAttribute('data-kv-value')) {
syncHiddenField(editor);
}
});
}
function syncHiddenField(editor) {
var fieldName = editor.getAttribute('data-kv-field');
if (!fieldName) {
return;
}
var hiddenInput = editor.querySelector(
'input[name="' + fieldName + '"][type="hidden"]'
);
if (!hiddenInput) {
return;
}
var rows = editor.querySelectorAll('[data-kv-row]');
var obj = {};
for (var i = 0; i < rows.length; i++) {
var keyEl = rows[i].querySelector('[data-kv-key]');
var valEl = rows[i].querySelector('[data-kv-value]');
var k = keyEl ? String(keyEl.value).replace(/^\s+|\s+$/g, '') : '';
var v = valEl ? valEl.value : '';
if (k !== '') {
// Last-write-wins on duplicate keys (D-10).
obj[k] = v;
}
}
hiddenInput.value = JSON.stringify(obj);
}
"#;