';
$('#editorMain').innerHTML = html;
setupSearchFields();
}
function renderCurrent() {
ced_syncDOMToData(moduleData);
if (!moduleData || !moduleID) return;
renderModuleEditor(moduleID, moduleData);
}
function renderCard(sec, data) {
var collapsed = expandedCards[sec.id] === false;
var isFull = cardWidths[sec.id] !== undefined ? cardWidths[sec.id] : (sec.fullWidth || false);
var fullClass = isFull ? ' obj-card-full' : '';
var h = '
';
h += '
';
h += '' + (collapsed ? '▶' : '▼') + '';
h += '' + sec.label + '';
h += '';
if (!sec.always) {
h += '';
}
h += '
';
if (!collapsed) {
h += '
';
if (sec.isArray) {
h += renderArraySection(sec, data);
} else {
h += '
';
sec.fields.forEach(function(f) {
h += renderField(sec, f, data, -1);
});
h += '
';
if (sec.inline) {
sec.inline.forEach(function(il) {
if (il.type === 'kv') {
h += ced_renderKV(sec, il, data);
}
});
}
}
h += '
';
}
h += '
';
return h;
}
function renderArraySection(sec, data) {
var arr = moduleData[cardPath(sec)] || [];
var h = '';
arr.forEach(function(item, idx) {
h += '
';
h += '
';
sec.fields.forEach(function(f) {
h += renderField(sec, f, data, idx);
});
h += '
';
h += '';
h += '
';
});
h += '';
return h;
}
function renderField(sec, f, data, idx) {
return ced_renderField(sec, f, data, idx, null, null, cardPath, fieldID, getVal);
}
function toggleCard(id) {
expandedCards[id] = expandedCards[id] === false ? true : false;
renderCurrent();
}
function toggleCardWidth(id) {
cardWidths[id] = !cardWidths[id];
renderCurrent();
}
function removeSection(id) {
var sec = MODULE_SECTIONS.find(function(s) { return s.id === id; });
if (!sec) return;
if (sec.path) {
delete moduleData[sec.path];
}
delete addedSections[id];
renderCurrent();
}
function addSection() {
var sel = $('#addSectionSelect');
var id = sel.value;
if (!id) return;
var sec = MODULE_SECTIONS.find(function(s) { return s.id === id; });
if (!sec) return;
if (sec.path && sec.isArray) {
moduleData[sec.path] = [];
} else if (sec.path) {
moduleData[sec.path] = {};
}
addedSections[id] = true;
expandedCards[id] = true;
renderCurrent();
}
function addArrayItem(cardID) {
var sec = MODULE_SECTIONS.find(function(s) { return s.id === cardID; });
if (!sec || !sec.isArray) return;
var arr = moduleData[sec.path] || [];
var empty = {};
sec.fields.forEach(function(f) {
empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
});
arr.push(empty);
moduleData[sec.path] = arr;
renderCurrent();
}
function removeArrayItem(cardID, idx) {
var sec = MODULE_SECTIONS.find(function(s) { return s.id === cardID; });
if (!sec || !sec.isArray) return;
var arr = moduleData[sec.path] || [];
arr.splice(idx, 1);
renderCurrent();
}
function saveModule() {
if (!ced_validateFields(MODULE_SECTIONS, fieldID, null)) return;
var out = {};
MODULE_SECTIONS.forEach(function(sec) {
if (sec.isArray) {
var arr = [];
var card = document.querySelector('.obj-card[data-card="' + sec.id + '"]');
if (!card) return;
var rows = card.querySelectorAll('.obj-sub-row');
rows.forEach(function(row, idx) {
var item = {};
sec.fields.forEach(function(f) {
var fid = fieldID(sec, f[0], idx);
var el = document.getElementById(fid);
if (el) item[f[0]] = collectFieldValue(el, f[2]);
});
if (Object.keys(item).length > 0) arr.push(item);
});
if (arr.length > 0) { out[sec.path] = arr; }
return;
}
var sectionObj = {};
var hasValues = sec.always;
if (sec.fields) {
sec.fields.forEach(function(f) {
var fid = fieldID(sec, f[0]);
var el = document.getElementById(fid);
if (!el) return;
var val = collectFieldValue(el, f[2]);
if (val !== '' && val !== false && val !== 0 && val !== null) hasValues = true;
sectionObj[f[0]] = val;
});
}
if (sec.inline) {
sec.inline.forEach(function(il) {
if (il.type === 'kv') {
var kvEl = document.querySelector('.obj-kv-list[data-sec="' + sec.id + '"][data-key="' + il.key + '"]');
if (kvEl) {
var map = {};
kvEl.querySelectorAll('.obj-kv-row').forEach(function(row) {
var keyEl = row.querySelector('.obj-kv-key');
var valEl = row.querySelector('.obj-kv-val');
if (keyEl && keyEl.value.trim() && valEl) {
map[keyEl.value.trim()] = parseFloat(valEl.value) || 0;
}
});
if (Object.keys(map).length > 0) { sectionObj[il.key] = map; hasValues = true; }
}
}
});
}
if (sec.always) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
} else if (hasValues && sec.path) {
out[sec.path] = sectionObj;
} else if (hasValues) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
}
});
ced_cleanOutput(out);
out.id = moduleID;
API.put('/api/modules/' + encodeURIComponent(moduleID), out).then(function(resp) {
notify('Module ' + moduleID + ' saved', 'success');
updateUndoBar();
if (resp && resp._raw) moduleData._raw = resp._raw;
}).catch(function(e) { notify('Save failed: ' + e.message, 'error'); });
}
function deleteModule() {
if (!confirm('Delete module "' + moduleID + '"?')) return;
API.del('/api/modules/' + encodeURIComponent(moduleID)).then(function() {
notify('Module ' + moduleID + ' deleted', 'success');
updateUndoBar();
moduleID = null;
currentID = null;
moduleData = null;
$('#editorMain').innerHTML = '