diff --git a/class/comment.php b/class/comment.php index 5645791..9d7aba8 100644 --- a/class/comment.php +++ b/class/comment.php @@ -969,7 +969,9 @@ function commentPostDelete($comment_id) $comment_id = (int)$comment_id; if ($comment_id <= 0) die('Ошибка: Неверный ID'); - // --- ПОЛУЧЕНИЕ ДАННЫХ И ПРОВЕРКА ПРАВ --- + // Читаем тип удаления из запроса (для админки) + $delete_type = $_REQUEST['admin_action_type'] ?? 'auto'; + $this->_commentSettingsGet(); $comment_data = $AVE_DB->Query(" @@ -985,7 +987,6 @@ function commentPostDelete($comment_id) $anon_key = $this->_getAnonKey(); $can_delete = false; - if ($user_group === 1) { $can_delete = true; } else { @@ -993,10 +994,7 @@ function commentPostDelete($comment_id) ($comment_data['comment_author_id'] == 0 && !empty($comment_data['anon_key']) && $comment_data['anon_key'] == $anon_key); $is_time_ok = (time() - (int)$comment_data['comment_published'] < (int)$this->conf_edit_time); - - if ($is_author && $is_time_ok) { - $can_delete = true; - } + if ($is_author && $is_time_ok) $can_delete = true; } if (!$can_delete) { @@ -1006,10 +1004,13 @@ function commentPostDelete($comment_id) $has_children = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_module_comment_info WHERE parent_id = '" . $comment_id . "'")->GetCell(); $upload_dir = BASE_DIR . '/uploads/comments/'; + + // Проверка на Ajax + $is_ajax = (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); - // --- МЯГКОЕ УДАЛЕНИЕ (если есть ответы и удаляет не админ) --- - if ($has_children > 0 && $user_group != 1) { - // Удаляем файлы физически, если они есть + // --- ЛОГИКА МЯГКОГО УДАЛЕНИЯ --- + if ($has_children > 0 && $delete_type !== 'full') { + // 1. Физически удаляем файлы, если они были if (!empty($comment_data['comment_file'])) { $files_to_del = explode(',', $comment_data['comment_file']); foreach ($files_to_del as $f_name) { @@ -1018,22 +1019,31 @@ function commentPostDelete($comment_id) } } - $del_text = "Комментарий удален автором."; + $status_marker = ($user_group === 1) ? '__DEL_BY_ADM__' : '__DEL_BY_AUT__'; + $AVE_DB->Query(" UPDATE " . PREFIX . "_module_comment_info - SET comment_text = '" . addslashes($del_text) . "', + SET comment_text = '" . $status_marker . "', + comment_author_name = '__DELETED__', + comment_author_id = '0', + comment_author_email = '', + comment_author_ip = '0.0.0.0', comment_file = '', anon_key = '', + user_rating = '0', + rating_sum = '0', + rating_count = '0', + comment_status = '1', comment_changed = '" . time() . "' WHERE Id = '" . $comment_id . "' "); - echo "OK_SOFT"; + + echo $is_ajax ? "OK_SOFT" : "OK"; } else { - // --- ПОЛНОЕ УДАЛЕНИЕ (Админ или нет вложенных ответов) --- + // --- ПОЛНОЕ УДАЛЕНИЕ --- $ids_to_delete = [$comment_id]; - // Если админ — собираем всю ветку детей для удаления if ($user_group == 1) { $all_child_ids = []; $parent_ids = [$comment_id]; @@ -1053,7 +1063,6 @@ function commentPostDelete($comment_id) $final_ids_str = implode(',', $ids_to_delete); - // Массовое удаление всех файлов во всех удаляемых комментариях $files_res = $AVE_DB->Query("SELECT comment_file FROM " . PREFIX . "_module_comment_info WHERE Id IN ($final_ids_str)"); while ($f = $files_res->FetchAssocArray()) { if (!empty($f['comment_file'])) { @@ -1065,7 +1074,6 @@ function commentPostDelete($comment_id) } } - // Удаляем записи из БД $AVE_DB->Query("DELETE FROM " . PREFIX . "_module_comment_info WHERE Id IN ($final_ids_str)"); echo "OK"; @@ -1460,13 +1468,47 @@ function commentAdminListShow($tpl_dir) $all_items[$row['Id']] = $row; } - // --- ПОСТРОЕНИЕ ДЕРЕВА --- + +// --- ПОСТРОЕНИЕ ДЕРЕВА --- $child_map = []; foreach ($all_items as $id => $item) { $p_id = (int)$item['parent_id']; if ($p_id > 0) $child_map[$p_id][] = $id; } + // Проходим по всем элементам и помечаем тех, у кого есть дети в child_map + foreach ($all_items as $id => &$item_for_check) { + $item_for_check['has_children'] = isset($child_map[$id]) ? 1 : 0; + } + unset($item_for_check); // очистка ссылки + + $docs = []; + $processed = []; + + $buildTree = function($parent_id, $level) use (&$buildTree, &$docs, &$processed, &$all_items, &$child_map) { + if (isset($child_map[$parent_id])) { + foreach ($child_map[$parent_id] as $child_id) { + if (!in_array($child_id, $processed)) { + $item = $all_items[$child_id]; + $item['depth_level'] = $level; + // has_children уже записан в $all_items выше + $docs[] = $item; + $processed[] = $child_id; + $buildTree($child_id, $level + 1); + } + } + } + }; + + foreach ($all_items as $id => $item) { + if ($item['parent_id'] == 0 && !in_array($id, $processed)) { + $item['depth_level'] = 0; + $docs[] = $item; + $processed[] = $id; + $buildTree($id, 1); + } + } + $docs = []; $processed = []; diff --git a/css/mod_comment_styles.css b/css/mod_comment_styles.css index de17c47..ed371b3 100644 --- a/css/mod_comment_styles.css +++ b/css/mod_comment_styles.css @@ -290,3 +290,11 @@ html { font-weight: normal; margin-left: 5px; } + +/* Стиль для кнопки удаления всей ветки */ +.ico_delete_all { + background-position: -48px -48px; /* Используем стандартную иконку крестика, но... */ + filter: hue-rotate(140deg) saturate(3); /* ...меняем её цвет на фиолетово-бордовый */ + opacity: 0.8; +} +.ico_delete_all:hover { opacity: 1; transform: scale(1.1); } diff --git a/js/comment.js b/js/comment.js index b69699f..7a417c9 100644 --- a/js/comment.js +++ b/js/comment.js @@ -178,84 +178,82 @@ if ($fileInput.length && $fileInput[0].files.length > 0) { } /* --- ДЕЙСТВИЯ (DELETE, LOCK, OPEN/CLOSE, VOTE) --- */ - function cAction(obj, action) { - var $btn = $(obj); - var cid = $btn.data('id'); - - if (!cid && action !== 'open' && action !== 'close') return; - - $.get(aveabspath + 'index.php', { - module: 'comment', - action: action, - docid: typeof DOC_ID !== 'undefined' ? DOC_ID : '', - Id: cid ? cid : '' - }, function() { - if (action === 'close') { - $btn.attr('id', 'mod_comment_open') - .removeClass('btn-outline-danger').addClass('btn-outline-success') - .html(' ' + COMMENT_SITE_OPEN); - $('#mod_comment_new').fadeOut(300); - } - else if (action === 'open') { - $btn.attr('id', 'mod_comment_close') - .removeClass('btn-outline-success').addClass('btn-outline-danger') - .html(' ' + COMMENT_SITE_CLOSE); - $('#mod_comment_new').fadeIn(300); - } - if (action === 'delete') { - var $commentBlock = $btn.closest('.mod_comment_comment'); - $commentBlock.fadeOut(300, function() { $(this).remove(); }); - } - -// показать / скрыть комментарий -if (action === 'unlock' || action === 'lock') { - var $icon = $btn.find('i'); +function cAction(obj, action) { + var $btn = $(obj); + var cid = $btn.data('id'); - // ищем внутренний бокс, чтобы не красить детей - var $commentBox = $btn.closest('.mod_comment_box'); - // поиск всей карточки для очистки старых стилей - var $card = $btn.closest('.mod_comment_comment'); - - if (action === 'lock') { - // --- Статус 0: СКРЫТО --- - $icon.attr('class', 'bi bi-eye-slash'); - $btn.removeClass('text-success text-muted').addClass('text-danger').attr('title', COMMENT_ICON_SHOW); + if (!cid && action !== 'open' && action !== 'close') return; + + $.get(aveabspath + 'index.php', { + module: 'comment', + action: action, + docid: typeof DOC_ID !== 'undefined' ? DOC_ID : '', + Id: cid ? cid : '' + }, function(data) { // Добавляем аргумент data для получения ответа от PHP - // красим внутренний блок сообщения - $commentBox.addClass('opacity-75 border border-warning rounded'); - - // текст - var $alert = $commentBox.find('.alert-warning'); - if ($alert.length === 0) { - var alertHtml = '
'; - // Вставляем в именно этого сообщения - $commentBox.find('.flex-grow-1').first().prepend(alertHtml); - $alert = $commentBox.find('.alert-warning'); + if (action === 'close') { + $btn.attr('id', 'mod_comment_open') + .removeClass('btn-outline-danger').addClass('btn-outline-success') + .html(' ' + COMMENT_SITE_OPEN); + $('#mod_comment_new').fadeOut(300); + } + else if (action === 'open') { + $btn.attr('id', 'mod_comment_close') + .removeClass('btn-outline-success').addClass('btn-outline-danger') + .html(' ' + COMMENT_SITE_CLOSE); + $('#mod_comment_new').fadeIn(300); } - $alert.stop(true, true).fadeIn(300); - - } else { - // --- Статус 1: ВИДИМО --- - $icon.attr('class', 'bi bi-eye'); - $btn.removeClass('text-danger text-muted').addClass('text-success').attr('title', COMMENT_ICON_HIDE); - - // чистим бокс и карточку - var classesToRemove = 'opacity-75 border border-warning rounded'; - $commentBox.removeClass(classesToRemove); - $card.removeClass(classesToRemove + ' border-warning'); // Чистим старый класс из твоего кода - - // удаляем плашку: - $commentBox.find('.alert-warning').first().stop(true, true).fadeOut(300, function() { - $(this).remove(); - }); - } -} +// --- ОБНОВЛЕННЫЙ БЛОК УДАЛЕНИЯ --- + if (action === 'delete') { + var response = data ? data.trim() : ''; + var $commentBlock = $btn.closest('.mod_comment_comment'); // Вся ветка (включая детей) + var $commentBox = $btn.closest('.mod_comment_box'); // Только текущая карточка + + if (response === 'OK_SOFT') { + // обновляем страницу + location.reload(); + } else { + // удаляем совсем комментарий + $commentBlock.fadeOut(300, function() { $(this).remove(); }); + } + } + + // показать / скрыть комментарий + if (action === 'unlock' || action === 'lock') { + var $icon = $btn.find('i'); + var $commentBox = $btn.closest('.mod_comment_box'); + var $card = $btn.closest('.mod_comment_comment'); + + if (action === 'lock') { + $icon.attr('class', 'bi bi-eye-slash'); + $btn.removeClass('text-success text-muted').addClass('text-danger').attr('title', COMMENT_ICON_SHOW); + $commentBox.addClass('opacity-75 border border-warning rounded'); + + var $alert = $commentBox.find('.alert-warning'); + if ($alert.length === 0) { + var alertHtml = ''; + $commentBox.find('.flex-grow-1').first().prepend(alertHtml); + $alert = $commentBox.find('.alert-warning'); + } + $alert.stop(true, true).fadeIn(300); + } else { + $icon.attr('class', 'bi bi-eye'); + $btn.removeClass('text-danger text-muted').addClass('text-success').attr('title', COMMENT_ICON_HIDE); + var classesToRemove = 'opacity-75 border border-warning rounded'; + $commentBox.removeClass(classesToRemove); + $card.removeClass(classesToRemove + ' border-warning'); + + $commentBox.find('.alert-warning').first().stop(true, true).fadeOut(300, function() { + $(this).remove(); }); } + } + }); +} /* --- ИНИЦИАЛИЗАЦИЯ --- */ $(document).ready(function() { diff --git a/lang/ru.txt b/lang/ru.txt index 91f311c..ceeaaee 100644 --- a/lang/ru.txt +++ b/lang/ru.txt @@ -122,6 +122,10 @@ COMMENT_JS_ERR_SRV = "Ошибка связи с сервером" COMMENT_WAITING_MODERATION = "Ваш комментарий на проверке и виден пока только вам." COMMENT_LAST_TITEL = "Последние комментарии" COMMENT_HIDDEN_BY_MODERATOR = "Комментарий скрыт модератором и находится на проверке." +COMMENT_TEXT_DEL_BY_ADMIN = "Комментарий удален администратором." +COMMENT_TEXT_DEL_BY_AUTHOR = "Комментарий удален автором." +COMMENT_STATUS_DELETED = "Удалено" + [admin] diff --git a/templates/admin_comments.tpl b/templates/admin_comments.tpl index 0a74616..2f2548d 100644 --- a/templates/admin_comments.tpl +++ b/templates/admin_comments.tpl @@ -125,18 +125,29 @@ [#] Посмотреть -