document.addEventListener('DOMContentLoaded', () => {
const loginSection = document.getElementById('login-section');
const editorSection = document.getElementById('editor-section');
const loginForm = document.getElementById('moder-login-form');
const loginError = document.getElementById('login-error');
const tabBtns = document.querySelectorAll('.tab-btn');
const addBlockBtn = document.getElementById('add-block-btn');
const blocksList = document.getElementById('blocks-list');
const logoutBtn = document.getElementById('logout-btn');
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
loginError.textContent = '';
const username = loginForm.username.value.trim();
const password = loginForm.password.value;
try {
const res = await fetch('/moders/moder-login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
if (res.ok) {
loginSection.style.display = 'none';
editorSection.style.display = '';
loadBlocks(currentTab);
} else {
const data = await res.json();
loginError.textContent = data.message || 'Ошибка входа';
}
} catch (err) {
loginError.textContent = 'Ошибка сервера';
}
});
if (logoutBtn) {
logoutBtn.onclick = async () => {
await fetch('/moders/moder-logout');
editorSection.style.display = 'none';
loginSection.style.display = '';
showNotify('Вы вышли из системы', 'success');
};
}
tabBtns.forEach(btn => {
btn.addEventListener('click', () => {
tabBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentTab = btn.dataset.tab;
loadBlocks(currentTab);
});
});
function loadBlocks(tab) {
fetch(`/moders/content/${tab}`)
.then(res => res.json())
.then(data => {
blocksList.innerHTML = '';
if (!Array.isArray(data) || !data.length) {
blocksList.innerHTML = '
Нет блоков
';
return;
}
data.forEach(block => {
const div = document.createElement('div');
div.className = 'content-block';
div.innerHTML = `${DOMPurify.sanitize(block.content)}
`;
const editBtn = document.createElement('button');
editBtn.textContent = 'Редактировать';
editBtn.onclick = () => openEditModal(block);
const delBtn = document.createElement('button');
delBtn.textContent = 'Удалить';
delBtn.onclick = async () => {
if (confirm('Удалить блок?')) {
await fetch(`/moders/content/${tab}/${block.id}`, { method: 'DELETE' });
showNotify('Блок удалён', 'success');
loadBlocks(tab);
}
};
div.appendChild(editBtn);
div.appendChild(delBtn);
blocksList.appendChild(div);
});
});
}
const editModal = document.getElementById('edit-modal');
const editModalClose = document.getElementById('edit-modal-close');
const editBlockForm = document.getElementById('edit-block-form');
const editBlockId = document.getElementById('edit-block-id');
const editModalTitle = document.getElementById('edit-modal-title');
let editQuill;
let currentTab = 'info';
let editingBlockId = null;
let originalContent = '';
function showNotify(msg, type = 'success') {
const notify = document.getElementById('notify');
notify.textContent = msg;
notify.className = 'show ' + type;
setTimeout(() => { notify.className = ''; }, 2200);
}
if (typeof Quill === 'undefined' || typeof DOMPurify === 'undefined') {
console.error('Required libraries not loaded');
return;
}
// Инициализируйте Quill
if (!initQuill()) {
return;
}
function initQuill() {
if (typeof Quill === 'undefined') {
console.error('Quill not loaded');
return false;
}
editQuill = new Quill('#edit-quill-editor', {
theme: 'snow',
modules: {
toolbar: [
[{ header: [1, 2, 3, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ 'align': [] }],
[{ 'color': [] }, { 'background': [] }],
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
['blockquote', 'code-block'],
['link', 'image', 'video'],
['clean']
]
}
});
return true;
}
function openEditModal(block) {
editingBlockId = block ? block.id : null;
editBlockId.value = block ? block.id : '';
editModalTitle.textContent = block ? 'Редактировать блок' : 'Добавить блок';
editQuill.root.innerHTML = block ? block.content : '';
document.getElementById('edit-block-preview').innerHTML = block ? DOMPurify.sanitize(block.content) : '';
originalContent = block ? block.content : '';
editModal.style.display = 'block';
}
editQuill.on('text-change', () => {
document.getElementById('edit-block-preview').innerHTML = DOMPurify.sanitize(editQuill.root.innerHTML);
});
function tryCloseEditModal() {
const currentContent = editQuill.root.innerHTML;
if (currentContent !== originalContent) {
document.getElementById('confirm-modal').style.display = 'flex';
const yesBtn = document.getElementById('confirm-close-yes');
const noBtn = document.getElementById('confirm-close-no');
yesBtn.onclick = function() {
document.getElementById('confirm-modal').style.display = 'none';
editModal.style.display = 'none';
};
noBtn.onclick = function() {
document.getElementById('confirm-modal').style.display = 'none';
};
return;
}
editModal.style.display = 'none';
}
editModalClose.onclick = tryCloseEditModal;
window.onclick = (event) => {
if (event.target === editModal) tryCloseEditModal();
};
addBlockBtn.onclick = () => openEditModal(null);
editBlockForm.addEventListener('submit', async (e) => {
e.preventDefault();
const content = DOMPurify.sanitize(editQuill.root.innerHTML.trim());
if (!content || content === '
') return;
if (editingBlockId) {
await fetch(`/moders/content/${currentTab}/${editingBlockId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'text', content })
});
showNotify('Блок обновлён', 'success');
} else {
await fetch(`/moders/content/${currentTab}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'text', content })
});
showNotify('Блок добавлен', 'success');
}
editModal.style.display = 'none';
loadBlocks(currentTab);
});
fetch('/moders/check-session', { credentials: 'include' }).then(res => {
if (res.ok) {
loginSection.style.display = 'none';
editorSection.style.display = '';
loadBlocks(currentTab);
} else {
loginSection.style.display = '';
editorSection.style.display = 'none';
}
});
let csrfToken = '';
fetch('/moders/csrf-token').then(res => res.json()).then(data => {
csrfToken = data.csrfToken;
});
const originalFetch = window.fetch;
window.fetch = function(url, options = {}) {
if (options && options.method && ['POST','PUT','DELETE'].includes(options.method.toUpperCase())) {
options.headers = options.headers || {};
options.headers['x-csrf-token'] = csrfToken;
}
return originalFetch(url, options);
};
});