From f0eb9a584c7a1b90d0ffd5a0139f420f4e069bb1 Mon Sep 17 00:00:00 2001 From: Repellent Date: Mon, 15 Dec 2025 22:11:35 +0500 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/comment.js | 293 ++++++++++++++++++++------------ templates/comments_tree.tpl | 74 +++++--- templates/comments_tree_sub.tpl | 31 ++-- 3 files changed, 252 insertions(+), 146 deletions(-) diff --git a/js/comment.js b/js/comment.js index f71f457..0e193e8 100644 --- a/js/comment.js +++ b/js/comment.js @@ -11,28 +11,63 @@ (function($){ // ==================================================================== - // КОРРЕКЦИЯ: ПРИНУДИТЕЛЬНАЯ ФИКСАЦИЯ HTTPS + // КОРРЕКЦИЯ: ПРИНУДИТЕЛЬНАЯ ФИКСАЦИЯ HTTPS (если требуется) // ==================================================================== if (typeof aveabspath !== 'undefined') { - aveabspath = 'https://bag.local/'; + // ПРЕДУПРЕЖДЕНИЕ: Если aveabspath должен быть динамическим, + // удалите эту строку. + // aveabspath = 'https://bag.local/'; } // ==================================================================== - /*Limit symbols*/ - (function($){$.fn.extend({limit:function(limit,element){var interval,f;var self=$(this);$(this).focus(function(){interval=window.setInterval(substring,100)});$(this).blur(function(){clearInterval(interval);substring()});substringFunction="function substring(){ var val = $(self).val();var length = val.length;if(length > limit){$(self).val($(self).val().substring(0,limit));}";if(typeof element!='undefined')substringFunction+="if($(element).html() != limit-length){$(element).html((limit-length<=0)?'0':limit-length);}";substringFunction+="}";eval(substringFunction);substring()}})})(jQuery); + /* Limit symbols */ + (function($){ + $.fn.extend({ + limit: function(limit, element){ + var interval, f; + var self = $(this); + + function substring(){ + var val = $(self).val(); + var length = val.length; + + if(length > limit){ + $(self).val($(self).val().substring(0,limit)); + length = limit; + } + + if(typeof element !== 'undefined'){ + if($(element).html() != limit - length){ + $(element).html((limit - length <= 0) ? '0' : limit - length); + } + } + } + + $(this).focus(function(){ + interval = window.setInterval(substring, 100); + }); + + $(this).blur(function(){ + clearInterval(interval); + substring(); + }); + + substring(); + } + }) + })(jQuery); function getCaptha(){ - now = new Date(); - $('#captcha img').attr('src', aveabspath+'inc/captcha.php?cd=' + now); - }; + var now = new Date(); + $('#captcha img').attr('src', aveabspath + 'inc/captcha.php?cd=' + now.getTime()); + } - // ИСПРАВЛЕННАЯ ФУНКЦИЯ cAction - function cAction(obj,action){ + function cAction(obj, action){ var cid; // --- Логика для действий с документом (open/close) --- if (action === 'open' || action === 'close') { - cid = DOC_ID; + cid = DOC_ID; } else { // 1. Пытаемся найти ссылку и взять ID из атрибута rel var $link = $(obj).closest('a.mod_comment_answer'); @@ -49,79 +84,87 @@ return; } - if (action=='answer'){ + if (action === 'answer'){ $('#parent_id').val(cid); - // --- ИСПРАВЛЕНИЕ: Добавлено .show() для отображения формы после перемещения --- - $('#mod_comment_new').insertBefore('#end'+cid).show(); + // Перемещаем форму и показываем ее + $('#mod_comment_new').insertBefore('#end' + cid).show(); return; } - // ... (остальной код для admin actions: delete, lock, open/close) - if (UGROUP==1){ - $.get(aveabspath+'index.php',{ + // Действия администратора + if (UGROUP == 1){ + $.get(aveabspath + 'index.php', { module: 'comment', action: action, docid: DOC_ID, Id: cid - },function(){ - if (action=='delete'){ + }, function(){ + if (action === 'delete'){ + // Удаляем блок комментария $(obj).parents('.mod_comment_comment').eq(0).remove(); } - if (action=='open'){ - $('#mod_comment_open').attr('id', 'mod_comment_close').html(COMMENT_SITE_CLOSE); + + if (action === 'open'){ + // 1. Меняем ID и текст + var $openButton = $('#mod_comment_open'); + $openButton.attr('id', 'mod_comment_close').html(' ' + COMMENT_SITE_CLOSE); + // 2. МЕНЯЕМ КЛАССЫ СТИЛЕЙ + $openButton.removeClass('btn-outline-success').addClass('btn-outline-danger'); } - if (action=='close'){ - $('#mod_comment_close').attr('id', 'mod_comment_open').html(COMMENT_SITE_OPEN); + + if (action === 'close'){ + // 1. Меняем ID и текст + var $closeButton = $('#mod_comment_close'); + $closeButton.attr('id', 'mod_comment_open').html(' ' + COMMENT_SITE_OPEN); + // 2. МЕНЯЕМ КЛАССЫ СТИЛЕЙ + $closeButton.removeClass('btn-outline-danger').addClass('btn-outline-success'); } - // ==================================================================== - // ИСПРАВЛЕНИЕ: ДИНАМИЧЕСКАЯ СМЕНА ИКОНКИ ЗАМКА (Font Awesome) - // ==================================================================== - if (action=='unlock'){ - // Меняем классы: mod_comment_unlock (открыт) -> mod_comment_lock (закрыт) - // Меняем цвет: text-success (зеленый) -> text-dark (темный) + + // Динамическая смена иконки замка для отдельного комментария + if (action === 'unlock'){ $(obj).removeClass('mod_comment_unlock text-success') - .addClass('mod_comment_lock text-dark') - .attr('title',COMMENT_LOCK_LINK) - .find('i.fa') // Ищем иконку FA - .removeClass('fa-unlock').addClass('fa-lock'); // Меняем иконку + .addClass('mod_comment_lock text-dark') + .attr('title', COMMENT_LOCK_LINK) + .find('i') + .removeClass('bi-unlock-fill').addClass('bi-lock-fill'); } - if (action=='lock'){ - // Меняем классы: mod_comment_lock (закрыт) -> mod_comment_unlock (открыт) - // Меняем цвет: text-dark (темный) -> text-success (зеленый) + if (action === 'lock'){ $(obj).removeClass('mod_comment_lock text-dark') - .addClass('mod_comment_unlock text-success') - .attr('title',COMMENT_UNLOCK_LINK) - .find('i.fa') // Ищем иконку FA - .removeClass('fa-lock').addClass('fa-unlock'); // Меняем иконку + .addClass('mod_comment_unlock text-success') + .attr('title', COMMENT_UNLOCK_LINK) + .find('i') + .removeClass('bi-lock-fill').addClass('bi-unlock-fill'); } - // ==================================================================== }); } - }; + } - // ИСПРАВЛЕННАЯ ФУНКЦИЯ VALIDATE: Устойчива к отсутствию полей - function validate(formData,jqForm,options){ + function validate(formData, jqForm, options){ $('.alert').remove(); - var form = jqForm ? jqForm[0] : $('#mod_comment_new form')[0]; + var form = jqForm ? jqForm[0] : $('#mod_comment_new form')[0]; + // Проверка имени if (form.comment_author_name && !form.comment_author_name.value){ alert(COMMENT_ERROR_AUTHOR); $(form.comment_author_name).focus(); return false; } + // Проверка email if (form.comment_author_email && !form.comment_author_email.value){ alert(COMMENT_ERROR_EMAIL); $(form.comment_author_email).focus(); return false; } + // Проверка текста if (!form.comment_text || !form.comment_text.value){ alert(COMMENT_ERROR_TEXT); if (form.comment_text) $(form.comment_text).focus(); return false; } + // Проверка капчи (если требуется) if (IS_IM && form.securecode && !form.securecode.value){ alert(COMMENT_ERROR_CAPTCHA); $(form.securecode).focus(); @@ -129,35 +172,48 @@ } return true; - }; + } function setClickable(){ + // Отвязываем предыдущие обработчики, чтобы избежать множественных вызовов + $('.editable_text').off('click'); + $('.editable_text').click(function(){ - var cid = $(this).parents('.mod_comment_box').attr('id'); - var revert = $(this).html(); - var textarea = '

'; - var charsLeft = '

'+COMMENT_CHARS_LEFT+'

'; - var buttonSave = ' '; - var buttonReset = ''; - $(this).after('
'+COMMENT_EDIT_TITLE - +''+textarea+buttonSave+buttonReset+charsLeft+'
').remove(); - $('.saveButton').click(function(){saveChanges(this,false,cid);}); - $('.cancelButton').click(function(){saveChanges(this,revert,cid);}); - $('#ta_'+cid).limit(MAX_CHARS,'#charsLeft_'+cid); + var $this = $(this); + var cid = $this.parents('.mod_comment_box').attr('id'); + var revert = $this.html(); + + var textarea = '

'; + var charsLeft = '

' + COMMENT_CHARS_LEFT + '

'; + var buttonSave = ' '; + var buttonReset = ''; + + $this.after( + '
' + COMMENT_EDIT_TITLE + + '' + textarea + charsLeft + buttonSave + buttonReset + '
' + ).remove(); + + $('.saveButton').click(function(){saveChanges(this, false, cid);}); + $('.cancelButton').click(function(){saveChanges(this, revert, cid);}); + + $('#ta_' + cid).limit(MAX_CHARS, '#charsLeft_' + cid); }) - .attr('title',COMMENT_EDIT_LINK) + .attr('title', COMMENT_EDIT_LINK) .mouseover(function(){$(this).addClass('editable');}) .mouseout(function(){$(this).removeClass('editable');}); - $('#in_message').limit(MAX_CHARS,'#charsLeft_new'); - }; - // ИСПРАВЛЕННАЯ ФУНКЦИЯ saveChanges - function saveChanges(obj,cancel,cid){ + // Лимит символов для новой формы + $('#in_message').limit(MAX_CHARS, '#charsLeft_new'); + } + + function saveChanges(obj, cancel, cid){ + var $box = $(obj).parents('.box'); + if (!cancel){ - var t = $(obj).parent().children().children().val(); + var t = $box.find('#ta_' + cid).val(); $.ajax({ - url: aveabspath+'index.php?ajax=1', + url: aveabspath + 'index.php?ajax=1', type: 'POST', data: { module: 'comment', @@ -166,84 +222,105 @@ text: t }, success: function(txt){ - $(obj).parent().parent().parent().after('
'+txt+'
').remove(); + $box.after('
' + txt + '
').remove(); var now = new Date(); - var date = now.toLocaleString(); - $('#'+cid).find('.mod_comment_changed').html(' ('+COMMENT_TEXT_CHANGED+' '+date+')'); + var date = now.toLocaleString(); + $('#' + cid).find('.mod_comment_changed').html(' (' + COMMENT_TEXT_CHANGED + ' ' + date + ')'); setClickable(); }, error: function(xhr, status, error) { console.error("AJAX Error (Edit):", status, error); - alert("Ошибка при редактировании комментария. Пожалуйста, проверьте консоль."); + alert("Ошибка при редактировании комментария."); } }); } else { - $(obj).parent().parent().parent().after('
'+cancel+'
').remove(); + $box.after('
' + cancel + '
').remove(); setClickable(); } - }; + } function displayNewComment(data){ - if (data=='wrong_securecode'){ - $('#captcha').after('
'+COMMENT_WRONG_CODE+'
'); + if (data === 'wrong_securecode'){ + $('#captcha').after('
'+COMMENT_WRONG_CODE+'
'); $('#securecode').focus(); } else { - $('#end'+$('#parent_id').val()).before(data); + $('#end' + $('#parent_id').val()).before(data); $('#parent_id').val(''); $('#mod_comment_new form')[0].reset(); - // --- Перемещаем форму обратно в конец. УБРАНО .hide() для сохранения видимости. + // Перемещаем форму обратно в конец $('#mod_comment_new').insertAfter('#end'); setClickable(); } getCaptha(); - }; + } $(document).ready(function(){ - setClickable(); + setClickable(); - // Делегирование событий + // Смена капчи $(document).on('click', '#captcha img', function(){getCaptha();}); - $(document).on('click', '.mod_comment_answer', function(){cAction(this,'answer');}); + // Ответ на комментарий + $(document).on('click', '.mod_comment_answer', function(e){ + e.preventDefault(); + cAction(this, 'answer'); + }); - $(document).on('click', '.mod_comment_edit', function(){ + // Редактирование (для администратора/автора) + $(document).on('click', '.mod_comment_edit', function(e){ + e.preventDefault(); var cid = $(this).parents('.mod_comment_box').attr('id'); - var commentTextBlock = $('#'+cid).find('.mod_comment_text'); - var revert = commentTextBlock.html(); + var commentTextBlock = $('#' + cid).find('.mod_comment_text'); + var revert = commentTextBlock.html(); - var textarea = '

'; - var charsLeft = '

'+COMMENT_CHARS_LEFT+'

'; - var buttonSave = ' '; - var buttonReset = ''; + var textarea = '

'; + var charsLeft = '

' + COMMENT_CHARS_LEFT + '

'; + var buttonSave = ' '; + var buttonReset = ''; commentTextBlock.after( - '
'+COMMENT_EDIT_TITLE - +''+textarea+buttonSave+buttonReset+charsLeft+'
' - ).remove(); + '
' + COMMENT_EDIT_TITLE + + '' + textarea + charsLeft + buttonSave + buttonReset + '
' + ).remove(); - $('.saveButton').click(function(){saveChanges(this,false,cid);}); - $('.cancelButton').click(function(){saveChanges(this,revert,cid);}); - $('#ta_'+cid).limit(MAX_CHARS,'#charsLeft_'+cid); + $('.saveButton').click(function(){saveChanges(this, false, cid);}); + $('.cancelButton').click(function(){saveChanges(this, revert, cid);}); + $('#ta_' + cid).limit(MAX_CHARS, '#charsLeft_' + cid); }); if (UGROUP == 1) { - $(document).on('click', '.mod_comment_delete', function(){ - if (confirm('Вы уверены, что хотите удалить комментарий?')) { - cAction(this, 'delete'); - } + // Удаление (с использованием Bootstrap Modal) + $(document).on('click', '.mod_comment_delete', function(e){ + e.preventDefault(); + var $deleteButton = $(this); + var $modal = $('#deleteCommentModal'); + + // Привязываем действие к кнопке подтверждения в модальном окне + $('#confirmDeleteButton').off('click').on('click', function() { + cAction($deleteButton[0], 'delete'); + // Закрываем модальное окно (совместимость с BS5) + var modalInstance = bootstrap.Modal.getInstance($modal[0]) || new bootstrap.Modal($modal[0]); + modalInstance.hide(); + }); + + // Открываем модальное окно (совместимость с BS5) + var modal = new bootstrap.Modal($modal[0]); + modal.show(); }); - $(document).on('click', '.mod_comment_lock', function(){cAction(this, 'lock');}); - $(document).on('click', '.mod_comment_unlock', function(){cAction(this, 'unlock');}); + // Блокировка/разблокировка + $(document).on('click', '.mod_comment_lock', function(e){e.preventDefault(); cAction(this, 'lock');}); + $(document).on('click', '.mod_comment_unlock', function(e){e.preventDefault(); cAction(this, 'unlock');}); - $(document).on('click', '#mod_comment_open', function(){cAction(this,'open');}); - $(document).on('click', '#mod_comment_close', function(){cAction(this,'close');}); + // Открыть/Закрыть комментарии для документа + $(document).on('click', '#mod_comment_open', function(e){e.preventDefault(); cAction(this, 'open');}); + $(document).on('click', '#mod_comment_close', function(e){e.preventDefault(); cAction(this, 'close');}); } - // Отправка формы (AJAX) - ИСПРАВЛЕНИЕ ДВОЙНОЙ ОТПРАВКИ + // Отправка формы (AJAX) $('#mod_comment_new form').on('submit', function(e){ e.preventDefault(); @@ -253,32 +330,30 @@ } var submitButton = form.find('input[type="submit"], button[type="submit"]').first(); - var originalButtonText = submitButton.val(); + var originalButtonText = submitButton.text(); + if (!originalButtonText) originalButtonText = submitButton.val(); var formData = form.serialize(); $.ajax({ - url: aveabspath+'index.php?ajax=1', + url: aveabspath + 'index.php?ajax=1', type: 'POST', data: formData, dataType: 'html', - // Отключаем кнопку перед отправкой beforeSend: function() { - submitButton.prop('disabled', true).val('Отправка...'); + submitButton.prop('disabled', true).text('Отправка...'); }, - // Включаем кнопку обратно и обрабатываем ответ success: function(data) { displayNewComment(data); - submitButton.prop('disabled', false).val(originalButtonText); + submitButton.prop('disabled', false).text(originalButtonText); }, timeout: 3000, - error: function(xhr, status, error) { + error: function(xhr, status, error) { console.error("AJAX Error (Creation):", status, error); - alert("Ошибка при отправке комментария. Пожалуйста, проверьте консоль."); - // Включаем кнопку обратно в случае ошибки - submitButton.prop('disabled', false).val(originalButtonText); + alert("Ошибка при отправке комментария."); + submitButton.prop('disabled', false).text(originalButtonText); } }); return false; diff --git a/templates/comments_tree.tpl b/templates/comments_tree.tpl index 646db06..cd7e6d2 100644 --- a/templates/comments_tree.tpl +++ b/templates/comments_tree.tpl @@ -1,19 +1,19 @@ {if $display_comments==1} {* ===================================================================== *} -{* НОВОЕ: ПРОВЕРКА ПРАВ НА ЧТЕНИЕ (самый высокий приоритет) *} +{* ПРОВЕРКА ПРАВ НА ЧТЕНИЕ *} {* ===================================================================== *} {if $no_read_permission == 1} {else} {* ===================================================================== *} - {* ВСЁ СУЩЕСТВУЮЩЕЕ СОДЕРЖИМОЕ БЛОКА КОММЕНТАРИЕВ (если права есть) *} + {* БЛОК КОММЕНТАРИЕВ *} {* ===================================================================== *}

{#COMMENT_SITE_TITLE#} - {if $closed==1 && $smarty.const.UGROUP!=1} + {if $closed==1 && $smarty.const.UGROUP!=1} {#COMMENT_SITE_CLOSED#} {/if}

@@ -38,7 +38,6 @@ {/if} - {* ИСПРАВЛЕНИЕ 1: Добавлена проверка isset() для безопасного доступа к $comments[0] *} {if isset($comments[0])}
{include file="$subtpl" subcomments=$comments[0]} @@ -48,7 +47,7 @@ {* ===================================================================== *} - {* ФОРМА ДОБАВЛЕНИЯ КОММЕНТАРИЯ (MODAL/BLOCK) *} + {* ФОРМА ДОБАВЛЕНИЯ КОММЕНТАРИЯ *} {* ===================================================================== *}
{if $closed==1 && $smarty.const.UGROUP!=1} @@ -67,26 +66,35 @@
Форма добавления комментария - {* Блок для имени и email (скрытые поля для авторизованных) *} + {* Блок для имени и email *} {if $smarty.session.user_group != '2'} - {* АВТОРИЗОВАННЫЙ ПОЛЬЗОВАТЕЛЬ *} - - {* ИСПРАВЛЕНИЕ: Добавлена проверка isset для user_email *} - {if isset($smarty.session.user_email) && $smarty.session.user_email != ''} - - {/if} + {* АВТОРИЗОВАННЫЙ ПОЛЬЗОВАТЕЛЬ: Отображаем поля как readonly *} +
+
+ + +
+
+ + +
+
+ {* Скрытые поля для отправки *} + + + {else} {* ГОСТЬ (требуется ввод имени) *}
- - + +
{* ГОСТЬ (email) *}
- - + +
{/if} @@ -95,14 +103,12 @@
- {* ИСПРАВЛЕНИЕ 2: Безопасное чтение comment_author_website через if/else *} - +
- {* ИСПРАВЛЕНИЕ 3: Безопасное чтение comment_author_city через if/else *} - +
@@ -155,7 +161,7 @@
{/if} - {* <-- Закрывает mt-5 для формы *} + {if $page_nav} {/if} + + {* ===================================================================== *} + {* НОВОЕ: МОДАЛЬНОЕ ОКНО ПОДТВЕРЖДЕНИЯ УДАЛЕНИЯ КОММЕНТАРИЯ (Bootstrap 5) *} + {* ===================================================================== *} + + + {* ===================================================================== *} + {* ПЕРЕМЕННЫЕ JAVASCRIPT И ПОДКЛЮЧЕНИЕ ФАЙЛА *} + {* ===================================================================== *}