forked from UKSOURCE/cms.lams
feat(cms): enhance content editors with dynamic UI configs and validation
Implement a more flexible, configuration-driven approach for CMS editors across accreditation, admissions, and partnerships modules. - Move UI labels, help texts, and field limits from hardcoded views to `editorUi` configurations in config files. - Add server-side and client-side validation to prevent duplicate category tabs in accreditation and partnerships editors. - Refactor partnership and admission views to dynamically render tabs and fields based on the provided configuration. - Update field length constraints and default values across multiple content editors to better align with frontend requirements. - Improve the admissions calculator editor with dynamic field configurations and default value fallbacks.
This commit is contained in:
@@ -36,7 +36,22 @@
|
||||
});
|
||||
});
|
||||
|
||||
form.addEventListener("submit", function () {
|
||||
form.addEventListener("submit", function (event) {
|
||||
const duplicateTabs = getDuplicateTabs(state?.grid?.tabs);
|
||||
|
||||
clearCategoryTabsValidation();
|
||||
|
||||
if (duplicateTabs.length > 0) {
|
||||
event.preventDefault();
|
||||
highlightDuplicateCategoryTabs(duplicateTabs);
|
||||
showToast(
|
||||
"Duplicate category tab",
|
||||
`Category tab "${duplicateTabs[0]}" already exists. Please use unique tab names before saving.`,
|
||||
"danger",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
pageJsonInput.value = JSON.stringify(state);
|
||||
});
|
||||
|
||||
@@ -52,6 +67,62 @@
|
||||
config.tabs.forEach((tab) => renderSection(tab.key));
|
||||
}
|
||||
|
||||
function getDuplicateTabs(tabs) {
|
||||
if (!Array.isArray(tabs)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const seen = new Set();
|
||||
const duplicates = [];
|
||||
|
||||
tabs.forEach((tab) => {
|
||||
const trimmedTab = String(tab || "").trim();
|
||||
const normalizedTab = trimmedTab.toLowerCase();
|
||||
|
||||
if (!normalizedTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seen.has(normalizedTab)) {
|
||||
duplicates.push(trimmedTab);
|
||||
return;
|
||||
}
|
||||
|
||||
seen.add(normalizedTab);
|
||||
});
|
||||
|
||||
return duplicates;
|
||||
}
|
||||
|
||||
function clearCategoryTabsValidation() {
|
||||
const tabsList = document.querySelector(
|
||||
'[data-section-key="grid"] .page-editor-array-list',
|
||||
);
|
||||
|
||||
tabsList
|
||||
?.querySelectorAll(".is-invalid")
|
||||
.forEach((element) => element.classList.remove("is-invalid"));
|
||||
}
|
||||
|
||||
function highlightDuplicateCategoryTabs(duplicateTabs) {
|
||||
const tabsList = document.querySelector(
|
||||
'[data-section-key="grid"] .page-editor-array-list',
|
||||
);
|
||||
const normalizedDuplicates = new Set(
|
||||
duplicateTabs.map((tab) => String(tab || "").trim().toLowerCase()),
|
||||
);
|
||||
|
||||
const duplicateInputs = Array.from(
|
||||
tabsList?.querySelectorAll(".form-control") || [],
|
||||
).filter((input) => {
|
||||
const inputValue = String(input.value || "").trim().toLowerCase();
|
||||
return inputValue && normalizedDuplicates.has(inputValue);
|
||||
});
|
||||
|
||||
duplicateInputs.forEach((input) => input.classList.add("is-invalid"));
|
||||
duplicateInputs[0]?.focus();
|
||||
}
|
||||
|
||||
function updateTabUrl(tabKey) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set("tab", tabKey);
|
||||
|
||||
Reference in New Issue
Block a user