/** * Blog Admin JavaScript * Handles blog post management with Editor.js integration */ let editor = null; let categories = []; let posts = []; let currentEditingPost = null; // Initialize async function init() { await loadCategories(); await loadPosts(); setupEventListeners(); setupTabs(); } // Setup tab switching function setupTabs() { const tabButtons = document.querySelectorAll('.tab-button'); tabButtons.forEach(btn => { btn.addEventListener('click', () => { const tabName = btn.dataset.tab; // Update buttons tabButtons.forEach(b => b.classList.remove('active')); btn.classList.add('active'); // Update content document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); document.getElementById(`${tabName}-tab`).classList.add('active'); }); }); } // Setup event listeners function setupEventListeners() { // Refresh button document.getElementById('refresh-blogs')?.addEventListener('click', async () => { await loadPosts(); showStatus('Posts refreshed', 'success'); }); // New post button document.getElementById('new-post')?.addEventListener('click', () => { openModal(); }); // Modal close document.getElementById('modal-close')?.addEventListener('click', closeModal); document.getElementById('cancel-post')?.addEventListener('click', closeModal); // Click outside modal to close document.getElementById('post-modal')?.addEventListener('click', (e) => { if (e.target.id === 'post-modal') closeModal(); }); // Post form submit document.getElementById('post-form')?.addEventListener('submit', handlePostSubmit); // Category form submit document.getElementById('category-form')?.addEventListener('submit', handleCategorySubmit); // Generate slug from title document.getElementById('post-title')?.addEventListener('blur', () => { const title = document.getElementById('post-title').value; const slugInput = document.getElementById('post-slug'); if (title && !slugInput.value) { slugInput.value = generateSlug(title); } }); // Filters ['filter-type', 'filter-status', 'filter-source'].forEach(id => { document.getElementById(id)?.addEventListener('change', () => { renderPostsList(); }); }); document.getElementById('filter-search')?.addEventListener('input', () => { renderPostsList(); }); // Generate category slug document.getElementById('category-name')?.addEventListener('blur', () => { const name = document.getElementById('category-name').value; const slugInput = document.getElementById('category-slug'); if (name && !slugInput.value) { slugInput.value = generateSlug(name); } }); } // Generate slug function generateSlug(text) { return text .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, '') .substring(0, 100); } // Load categories from API async function loadCategories() { try { const response = await fetch('/api/blogs/categories'); const data = await response.json(); categories = data.categories || []; populateCategorySelect(); renderCategoriesList(); } catch (error) { console.error('Failed to load categories:', error); } } // Load posts from API async function loadPosts() { try { const response = await fetch('/api/admin/blogs'); const data = await response.json(); posts = data.posts || []; renderPostsList(); } catch (error) { console.error('Failed to load posts:', error); document.getElementById('blog-list').innerHTML = '
Failed to load posts
'; } } // Populate category select dropdown function populateCategorySelect() { const select = document.getElementById('post-category'); select.innerHTML = ''; categories.forEach(cat => { const option = document.createElement('option'); option.value = cat.slug; option.textContent = cat.name; select.appendChild(option); }); } // Render posts list function renderPostsList() { const container = document.getElementById('blog-list'); const typeFilter = document.getElementById('filter-type')?.value; const statusFilter = document.getElementById('filter-status')?.value; const sourceFilter = document.getElementById('filter-source')?.value; const searchFilter = document.getElementById('filter-search')?.value.toLowerCase(); let filtered = posts; if (typeFilter) filtered = filtered.filter(p => p.type === typeFilter); if (statusFilter) filtered = filtered.filter(p => p.status === statusFilter); if (sourceFilter) filtered = filtered.filter(p => p.source === sourceFilter); if (searchFilter) { filtered = filtered.filter(p => p.title?.toLowerCase().includes(searchFilter) || p.excerpt?.toLowerCase().includes(searchFilter) || p.author?.toLowerCase().includes(searchFilter) ); } if (filtered.length === 0) { container.innerHTML = 'No posts found
'; return; } container.innerHTML = filtered.map(post => `No categories found
'; return; } container.innerHTML = categories.map(cat => `${escapeHtml(cat.description)}
` : ''}