- Заменен лишний div.container на стандартный container для единообразия - Заменен класс .card на .ios-card в секции активности для устранения конфликтов стилей - Добавлен card-list.css в base.html для корректного отображения карточек новостей - Добавлены CSS правила для правильного поведения .row и колонок в grid-layout - Исправлена проблема с выходом календаря за границы страницы - Убраны видимые скроллбары у modal-body и modal-content для чистого UI
340 lines
11 KiB
JavaScript
340 lines
11 KiB
JavaScript
/**
|
||
* @module feedCrudHandler
|
||
* @description Обработчик CRUD операций для постов и комментариев через API
|
||
*/
|
||
|
||
/**
|
||
* Инициализирует обработчики CRUD операций для постов и комментариев
|
||
* @param {Object} options - Опции инициализации
|
||
* @param {string} options.postsApiUrl - URL API для списка постов
|
||
* @param {string} options.commentsApiUrl - URL API для списка комментариев
|
||
* @param {Object} [options.headers={}] - HTTP заголовки для запросов
|
||
* @returns {Object} API с методом destroy
|
||
*/
|
||
export function initFeedCrudHandler(options) {
|
||
const {
|
||
postsApiUrl,
|
||
commentsApiUrl,
|
||
headers = {}
|
||
} = options;
|
||
|
||
// Для multipart/form-data убираем Content-Type, оставляем только Authorization
|
||
const authHeaders = {};
|
||
if (headers['Authorization']) {
|
||
authHeaders['Authorization'] = headers['Authorization'];
|
||
}
|
||
|
||
// Формы постов
|
||
const postCreateForm = document.getElementById('postCreateForm');
|
||
const postEditForm = document.getElementById('postEditForm');
|
||
const postDeleteForm = document.getElementById('postDeleteForm');
|
||
|
||
// Формы комментариев
|
||
const commentCreateForm = document.getElementById('commentCreateForm');
|
||
const commentEditForm = document.getElementById('commentEditForm');
|
||
const commentDeleteForm = document.getElementById('commentDeleteForm');
|
||
|
||
// Массив для хранения обработчиков
|
||
const handlers = [];
|
||
|
||
/**
|
||
* Обработчик создания поста
|
||
*/
|
||
async function handlePostCreate(e) {
|
||
e.preventDefault();
|
||
|
||
const formData = new FormData(postCreateForm);
|
||
|
||
try {
|
||
const response = await fetch(postsApiUrl, {
|
||
method: 'POST',
|
||
headers: authHeaders, // Только Authorization, без Content-Type
|
||
body: formData
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Публикация создана!');
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
let errorMsg = 'Ошибка создания публикации:\n';
|
||
for (const [field, errors] of Object.entries(error)) {
|
||
errorMsg += `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}\n`;
|
||
}
|
||
alert(errorMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error creating post:', error);
|
||
alert('Ошибка сети при создании публикации');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обработчик редактирования поста
|
||
*/
|
||
async function handlePostEdit(e) {
|
||
e.preventDefault();
|
||
|
||
const postId = postEditForm.dataset.postId;
|
||
if (!postId) {
|
||
alert('ID поста не найден');
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData(postEditForm);
|
||
|
||
try {
|
||
const response = await fetch(`${postsApiUrl}${postId}/`, {
|
||
method: 'PATCH',
|
||
headers: authHeaders, // Только Authorization
|
||
body: formData
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Публикация обновлена!');
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
let errorMsg = 'Ошибка обновления публикации:\n';
|
||
for (const [field, errors] of Object.entries(error)) {
|
||
errorMsg += `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}\n`;
|
||
}
|
||
alert(errorMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error updating post:', error);
|
||
alert('Ошибка сети при обновлении публикации');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обработчик удаления поста
|
||
*/
|
||
async function handlePostDelete(e) {
|
||
e.preventDefault();
|
||
|
||
const postId = postDeleteForm.dataset.postId;
|
||
if (!postId) {
|
||
alert('ID поста не найден');
|
||
return;
|
||
}
|
||
|
||
if (!confirm('Вы уверены, что хотите удалить эту публикацию?')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`${postsApiUrl}${postId}/`, {
|
||
method: 'DELETE',
|
||
headers: headers
|
||
});
|
||
|
||
if (response.ok || response.status === 204) {
|
||
alert('Публикация удалена');
|
||
// Перенаправляем на главную ленту
|
||
window.location.href = postDeleteForm.dataset.redirectUrl || '/feed/';
|
||
} else {
|
||
alert(`Ошибка удаления: ${response.status}`);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error deleting post:', error);
|
||
alert('Ошибка сети при удалении публикации');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обработчик закрепления/открепления поста
|
||
*/
|
||
async function handlePinPost(e) {
|
||
e.preventDefault();
|
||
|
||
const button = e.currentTarget;
|
||
const postId = button.dataset.postId;
|
||
const action = button.dataset.action; // 'pin' or 'unpin'
|
||
|
||
if (!postId) {
|
||
alert('ID поста не найден');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`${postsApiUrl}${postId}/${action}/`, {
|
||
method: 'POST',
|
||
headers: headers
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert(action === 'pin' ? 'Новость закреплена!' : 'Новость откреплена!');
|
||
window.location.reload();
|
||
} else {
|
||
alert(`Ошибка: ${response.status}`);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error pinning/unpinning post:', error);
|
||
alert('Ошибка сети');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обработчик создания комментария
|
||
*/
|
||
async function handleCommentCreate(e) {
|
||
e.preventDefault();
|
||
|
||
const formData = new FormData(commentCreateForm);
|
||
|
||
try {
|
||
const response = await fetch(commentsApiUrl, {
|
||
method: 'POST',
|
||
headers: authHeaders, // Только Authorization
|
||
body: formData
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Комментарий добавлен!');
|
||
window.location.reload();
|
||
} else {
|
||
const error = await response.json();
|
||
let errorMsg = 'Ошибка добавления комментария:\n';
|
||
for (const [field, errors] of Object.entries(error)) {
|
||
errorMsg += `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}\n`;
|
||
}
|
||
alert(errorMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error creating comment:', error);
|
||
alert('Ошибка сети при добавлении комментария');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обработчик редактирования комментария
|
||
*/
|
||
async function handleCommentEdit(e) {
|
||
e.preventDefault();
|
||
|
||
const commentId = commentEditForm.dataset.commentId;
|
||
if (!commentId) {
|
||
alert('ID комментария не найден');
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData(commentEditForm);
|
||
|
||
try {
|
||
const response = await fetch(`${commentsApiUrl}${commentId}/`, {
|
||
method: 'PATCH',
|
||
headers: authHeaders, // Только Authorization
|
||
body: formData
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert('Комментарий обновлён!');
|
||
const postId = commentEditForm.dataset.postId;
|
||
if (postId) {
|
||
window.location.href = `/feed/post/${postId}/#c${commentId}`;
|
||
} else {
|
||
window.location.reload();
|
||
}
|
||
} else {
|
||
const error = await response.json();
|
||
let errorMsg = 'Ошибка обновления комментария:\n';
|
||
for (const [field, errors] of Object.entries(error)) {
|
||
errorMsg += `${field}: ${Array.isArray(errors) ? errors.join(', ') : errors}\n`;
|
||
}
|
||
alert(errorMsg);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error updating comment:', error);
|
||
alert('Ошибка сети при обновлении комментария');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Обработчик удаления комментария
|
||
*/
|
||
async function handleCommentDelete(e) {
|
||
e.preventDefault();
|
||
|
||
const commentId = commentDeleteForm.dataset.commentId;
|
||
if (!commentId) {
|
||
alert('ID комментария не найден');
|
||
return;
|
||
}
|
||
|
||
if (!confirm('Вы уверены, что хотите удалить этот комментарий?')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const response = await fetch(`${commentsApiUrl}${commentId}/`, {
|
||
method: 'DELETE',
|
||
headers: headers
|
||
});
|
||
|
||
if (response.ok || response.status === 204) {
|
||
alert('Комментарий удалён');
|
||
const postId = commentDeleteForm.dataset.postId;
|
||
if (postId) {
|
||
window.location.href = `/feed/post/${postId}/`;
|
||
} else {
|
||
window.location.reload();
|
||
}
|
||
} else {
|
||
alert(`Ошибка удаления: ${response.status}`);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error deleting comment:', error);
|
||
alert('Ошибка сети при удалении комментария');
|
||
}
|
||
}
|
||
|
||
// Привязываем обработчики к формам
|
||
if (postCreateForm) {
|
||
postCreateForm.addEventListener('submit', handlePostCreate);
|
||
handlers.push({ element: postCreateForm, event: 'submit', handler: handlePostCreate });
|
||
}
|
||
|
||
if (postEditForm) {
|
||
postEditForm.addEventListener('submit', handlePostEdit);
|
||
handlers.push({ element: postEditForm, event: 'submit', handler: handlePostEdit });
|
||
}
|
||
|
||
if (postDeleteForm) {
|
||
postDeleteForm.addEventListener('submit', handlePostDelete);
|
||
handlers.push({ element: postDeleteForm, event: 'submit', handler: handlePostDelete });
|
||
}
|
||
|
||
if (commentCreateForm) {
|
||
commentCreateForm.addEventListener('submit', handleCommentCreate);
|
||
handlers.push({ element: commentCreateForm, event: 'submit', handler: handleCommentCreate });
|
||
}
|
||
|
||
if (commentEditForm) {
|
||
commentEditForm.addEventListener('submit', handleCommentEdit);
|
||
handlers.push({ element: commentEditForm, event: 'submit', handler: handleCommentEdit });
|
||
}
|
||
|
||
if (commentDeleteForm) {
|
||
commentDeleteForm.addEventListener('submit', handleCommentDelete);
|
||
handlers.push({ element: commentDeleteForm, event: 'submit', handler: handleCommentDelete });
|
||
}
|
||
|
||
// Привязываем обработчики к кнопкам закрепления
|
||
const pinButtons = document.querySelectorAll('[data-action="pin"], [data-action="unpin"]');
|
||
pinButtons.forEach(button => {
|
||
button.addEventListener('click', handlePinPost);
|
||
handlers.push({ element: button, event: 'click', handler: handlePinPost });
|
||
});
|
||
|
||
// Возвращаем API для очистки
|
||
return {
|
||
destroy() {
|
||
handlers.forEach(({ element, event, handler }) => {
|
||
element.removeEventListener(event, handler);
|
||
});
|
||
handlers.length = 0;
|
||
}
|
||
};
|
||
}
|