190 lines
6.8 KiB
JavaScript
190 lines
6.8 KiB
JavaScript
import { deleteJson, getJson, sendJson } from './api.js';
|
|
import { renderCmsCategoryList, renderCmsContentEmpty, renderCmsContentRow } from './cmsRenderer.js';
|
|
import { esc } from './sanitize.js';
|
|
|
|
export function createCmsController(deps) {
|
|
var contentData = [];
|
|
|
|
function loadStats() {
|
|
getJson('/api/admin/learning/stats')
|
|
.then(function(data) {
|
|
if (!data.success) return;
|
|
var s = data.stats;
|
|
setText('cms-stat-published', s.publishedContent);
|
|
setText('cms-stat-drafts', s.totalContent - s.publishedContent);
|
|
setText('cms-stat-categories', s.totalCategories);
|
|
setText('cms-stat-quizzes', s.totalQuizzes);
|
|
setText('cms-stat-attempts', s.totalAttempts);
|
|
});
|
|
}
|
|
|
|
function loadCategories(editorCategoryId, filterCategoryId) {
|
|
getJson('/api/admin/learning/categories')
|
|
.then(function(data) {
|
|
if (!data.success) return;
|
|
var container = document.getElementById('lh-cms-categories');
|
|
if (!container) return;
|
|
|
|
container.innerHTML = renderCmsCategoryList(data.categories);
|
|
updateCategorySelects(data.categories, editorCategoryId, filterCategoryId);
|
|
setActiveCategory((document.getElementById('cms-filter-category') || {}).value || 'all');
|
|
});
|
|
}
|
|
|
|
function addCategory() {
|
|
var input = document.getElementById('lh-cms-cat-name');
|
|
if (!input || !input.value.trim()) { deps.showToast('Enter category name', 'error'); return; }
|
|
|
|
sendJson('/api/admin/learning/categories', 'POST', { name: input.value.trim() })
|
|
.then(function(data) {
|
|
if (data.success) {
|
|
input.value = '';
|
|
loadCategories();
|
|
deps.refreshUserCategories();
|
|
deps.showToast('Category created', 'success');
|
|
} else deps.showToast(data.error || 'Failed', 'error');
|
|
})
|
|
.catch(function() { deps.showToast('Request failed', 'error'); });
|
|
}
|
|
|
|
function deleteCategory(id) {
|
|
if (!window.__confirmDeleteCat) {
|
|
window.__confirmDeleteCat = id;
|
|
deps.showToast('Click delete again to confirm removing this category', 'info');
|
|
setTimeout(function() { window.__confirmDeleteCat = null; }, 4000);
|
|
return;
|
|
}
|
|
window.__confirmDeleteCat = null;
|
|
deleteJson('/api/admin/learning/categories/' + id)
|
|
.then(function(data) {
|
|
if (data.success) {
|
|
loadCategories();
|
|
deps.refreshUserCategories();
|
|
deps.showToast('Category deleted', 'info');
|
|
} else deps.showToast(data.error || 'Failed', 'error');
|
|
});
|
|
}
|
|
|
|
function loadContent() {
|
|
var container = document.getElementById('lh-cms-content-list');
|
|
if (!container) return;
|
|
container.innerHTML = '<p style="text-align:center;color:var(--g400);padding:12px;">Loading...</p>';
|
|
|
|
getJson('/api/admin/learning/content')
|
|
.then(function(data) {
|
|
if (!data.success) return;
|
|
contentData = data.content || [];
|
|
if (contentData.length === 0) {
|
|
container.innerHTML = '<p style="text-align:center;color:var(--g400);padding:12px;">No content yet. Click "New Content" to create.</p>';
|
|
return;
|
|
}
|
|
renderContentList(contentData);
|
|
});
|
|
}
|
|
|
|
function handleFilterInput(e) {
|
|
if (e.target.id === 'cms-search') filterContent();
|
|
}
|
|
|
|
function handleFilterChange(e) {
|
|
if (e.target.id !== 'cms-filter-status' && e.target.id !== 'cms-filter-category') return;
|
|
if (e.target.id === 'cms-filter-category') setActiveCategory(e.target.value || 'all');
|
|
filterContent();
|
|
}
|
|
|
|
function filterByCategory(categoryId) {
|
|
var filterSel = document.getElementById('cms-filter-category');
|
|
if (filterSel) filterSel.value = String(categoryId);
|
|
setActiveCategory(categoryId);
|
|
filterContent();
|
|
}
|
|
|
|
function refreshAll() {
|
|
loadContent();
|
|
loadCategories();
|
|
loadStats();
|
|
}
|
|
|
|
function renderContentList(items) {
|
|
var container = document.getElementById('lh-cms-content-list');
|
|
if (!container) return;
|
|
if (!items || items.length === 0) {
|
|
container.innerHTML = renderCmsContentEmpty();
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = items.map(renderCmsContentRow).join('');
|
|
}
|
|
|
|
function filterContent() {
|
|
var search = (document.getElementById('cms-search') || {}).value || '';
|
|
var statusFilter = (document.getElementById('cms-filter-status') || {}).value || 'all';
|
|
var catFilter = (document.getElementById('cms-filter-category') || {}).value || 'all';
|
|
|
|
search = search.toLowerCase().trim();
|
|
var filtered = contentData.filter(function(item) {
|
|
var title = (item.title || '').toLowerCase();
|
|
var subject = (item.subject || '').toLowerCase();
|
|
if (search && title.indexOf(search) === -1 && subject.indexOf(search) === -1) return false;
|
|
if (statusFilter === 'published' && !item.published) return false;
|
|
if (statusFilter === 'draft' && item.published) return false;
|
|
if (catFilter !== 'all' && String(item.category_id) !== catFilter) return false;
|
|
return true;
|
|
});
|
|
renderContentList(filtered);
|
|
}
|
|
|
|
return {
|
|
addCategory: addCategory,
|
|
deleteCategory: deleteCategory,
|
|
filterByCategory: filterByCategory,
|
|
handleFilterChange: handleFilterChange,
|
|
handleFilterInput: handleFilterInput,
|
|
loadCategories: loadCategories,
|
|
loadContent: loadContent,
|
|
loadStats: loadStats,
|
|
refreshAll: refreshAll
|
|
};
|
|
}
|
|
|
|
function updateCategorySelects(categories, editorCategoryId, filterCategoryId) {
|
|
var sel = document.getElementById('lh-cms-edit-category');
|
|
if (sel) {
|
|
var selectedEditorId = editorCategoryId !== undefined ? editorCategoryId : sel.value;
|
|
sel.innerHTML = '<option value="">Uncategorized</option>';
|
|
categories.forEach(function(c) {
|
|
sel.innerHTML += '<option value="' + c.id + '">' + esc(c.name) + '</option>';
|
|
});
|
|
if (selectedEditorId && hasSelectValue(sel, selectedEditorId)) sel.value = selectedEditorId;
|
|
}
|
|
|
|
var filterSel = document.getElementById('cms-filter-category');
|
|
if (filterSel) {
|
|
var selectedFilterId = filterCategoryId !== undefined ? filterCategoryId : filterSel.value;
|
|
filterSel.innerHTML = '<option value="all">All Categories</option>';
|
|
categories.forEach(function(c) {
|
|
filterSel.innerHTML += '<option value="' + c.id + '">' + esc(c.name) + '</option>';
|
|
});
|
|
if (selectedFilterId && hasSelectValue(filterSel, selectedFilterId)) filterSel.value = selectedFilterId;
|
|
}
|
|
}
|
|
|
|
function setText(id, val) {
|
|
var el = document.getElementById(id);
|
|
if (el) el.textContent = val;
|
|
}
|
|
|
|
function setActiveCategory(categoryId) {
|
|
categoryId = String(categoryId || 'all');
|
|
document.querySelectorAll('.lh-cms-cat-filter').forEach(function(item) {
|
|
item.classList.toggle('active', categoryId !== 'all' && item.dataset.id === categoryId);
|
|
});
|
|
}
|
|
|
|
function hasSelectValue(sel, value) {
|
|
value = String(value);
|
|
for (var i = 0; i < sel.options.length; i++) {
|
|
if (sel.options[i].value === value) return true;
|
|
}
|
|
return false;
|
|
}
|