добавлено: если используется [mod_comment:X] - X число желаемых последних комментариев на странице, вывод происходит в шаблоне last_comments.tpl

This commit is contained in:
2026-01-12 00:10:49 +05:00
parent d82c7d21b2
commit 0d8eecd145
5 changed files with 259 additions and 29 deletions

View File

@@ -1629,6 +1629,98 @@ function commentAdminSettingsEdit($tpl_dir)
$AVE_Template->assign('content', $AVE_Template->fetch($tpl_dir . $this->_admin_settings_tpl));
}
/**
* Метод для получения последних X комментариев
*/
function getLatestComments($limit = 10)
{
global $AVE_DB;
// 1. Принудительно подключаем CSS
$GLOBALS['user_header']['comment_css'] = '<link rel="stylesheet" href="' . ABS_PATH . 'modules/comment/css/mod_comment_styles.css" type="text/css" />';
$sql = $AVE_DB->Query("
SELECT
comm.*,
doc.document_title,
doc.document_alias
FROM " . PREFIX . "_module_comment_info AS comm
LEFT JOIN " . PREFIX . "_documents AS doc ON doc.Id = comm.document_id
WHERE comm.comment_status = '1'
ORDER BY comm.comment_published DESC
LIMIT " . (int)$limit
);
$items = array();
if ($sql && $sql->NumRows() > 0) {
while ($res = $sql->FetchAssocArray()) {
$row = array_change_key_case($res, CASE_LOWER);
// Обработка текста комментария
$row['comment_text'] = mb_strimwidth(strip_tags($row['comment_text'] ?? ''), 0, 150, "...");
$row['date'] = ave_date_format(get_settings('date_format'), $row['comment_published']);
// Логика аватара (системный или буквенный)
if (isset($row['comment_author_id']) && $row['comment_author_id'] > 0) {
$row['avatar'] = function_exists('getAvatar') ? getAvatar($row['comment_author_id'], 48) : '';
} else {
$row['avatar'] = '';
}
if (empty($row['avatar']) || strpos($row['avatar'], 'user.png') !== false) {
$row['avatar'] = '';
$name = !empty($row['comment_author_name']) ? stripslashes($row['comment_author_name']) : 'Guest';
$row['first_letter'] = mb_strtoupper(mb_substr(trim($name), 0, 1, 'UTF-8'));
$row['avatar_color_index'] = (abs(crc32($name)) % 12) + 1;
}
// Авторские звезды
$user_rating = (int)($row['user_rating'] ?? 0);
$stars_html = '';
if ($user_rating > 0) {
for ($i = 1; $i <= 5; $i++) {
if ($i <= $user_rating) {
$stars_html .= '<i class="bi bi-star-fill text-warning me-1" style="font-size: 0.8rem;"></i>';
} else {
$stars_html .= '<i class="bi bi-star text-muted me-1" style="font-size: 0.8rem; opacity: 0.5;"></i>';
}
}
}
$row['stars'] = $stars_html;
// Формирование ссылки
$doc_id = (int)$row['document_id'];
$alias = (!empty($row['document_alias']) && $row['document_alias'] != '/') ? $row['document_alias'] : '';
$raw_url = "index.php?id=" . $doc_id . "&doc=" . $alias . "/";
$final_url = function_exists('rewrite_link') ? rewrite_link($raw_url) : $alias;
// Чистим слеши
$final_url = preg_replace('/(?<!:)\/\//', '/', str_ireplace(['"//"', '///'], ['/', '/'], $final_url));
$final_url = rtrim($final_url, '/');
// ФИКС ГЛАВНОЙ: если ссылка пустая после rtrim, значит это корень сайта
if (empty($final_url)) {
$final_url = '/';
}
// Собираем финальный URL с якорем
$row['link'] = $final_url . '#comment_wrapper_' . ($row['id'] ?? 0);
// Дополнительная проверка корректности начала ссылки
if (isset($row['link'][0]) && $row['link'][0] == '#') {
$row['link'] = '/' . $row['link'];
}
$row['document_title'] = !empty($row['document_title']) ? $row['document_title'] : 'Документ #' . $doc_id;
$items[] = $row;
}
}
return $items;
}
}
?>

View File

@@ -231,4 +231,62 @@
.comment-image-item .card-link-wrapper:hover .file-box {
box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
border-color: #0d6efd !important; /* Цвет границы при наведении (синий) */
}
}
/*стили при переходе с блока последние коммента*/
/* Плавная прокрутка */
html {
scroll-behavior: smooth !important;
}
/* Отступ от фиксированного меню */
[id^="comment_wrapper_"] {
scroll-margin-top: 100px !important;
}
/* Эффект подсветки */
[id^="comment_wrapper_"]:target {
animation: highlight-fade 3s ease-in-out !important;
outline: 2px solid #ffc107 !important;
border-radius: 0.375rem;
}
@keyframes highlight-fade {
0% { background-color: #fff9c4 !important; }
100% { background-color: transparent; }
}
/* Геометрия аватаров для виджета */
.lc-avatar-wrapper {
width: 42px;
height: 42px;
margin-right: 12px;
flex-shrink: 0;
}
.lc-avatar-wrapper img {
width: 42px;
height: 42px;
border-radius: 50%;
object-fit: cover;
}
.lc-letter-circle {
width: 42px;
height: 42px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-weight: bold;
font-size: 1.1rem;
text-transform: uppercase;
}
.lc-reply-label {
font-size: 0.8rem;
color: #6c757d;
font-weight: normal;
margin-left: 5px;
}

View File

@@ -1,20 +1,19 @@
<?php
if (! defined('BASE_DIR'))
exit;
if (!defined('BASE_DIR')) exit;
$module = array(
'ModuleSysName' => 'comment',
'ModuleVersion' => '3.30',
'ModuleAutor' => 'Repellent',
'ModuleCopyright' => '&copy; 2007-' . date('Y') . ' AVE.cms',
'ModuleStatus' => 1,
'ModuleIsFunction' => 1,
'ModuleTemplate' => 0,
'ModuleAdminEdit' => 1,
'ModuleFunction' => 'mod_comment',
'ModuleTag' => '[mod_comment]',
'ModuleTagLink' => null,
'ModuleAveTag' => '#\\\[mod_comment]#',
'ModulePHPTag' => '<?php mod_comment(); ?>'
);
$module = array(
'ModuleSysName' => 'comment',
'ModuleVersion' => '3.33',
'ModuleAutor' => 'Repellent',
'ModuleCopyright' => '&copy; 2007-' . date('Y') . ' AVE.cms',
'ModuleStatus' => 1,
'ModuleIsFunction' => 1,
'ModuleTemplate' => 0,
'ModuleAdminEdit' => 1,
'ModuleFunction' => 'mod_comment',
'ModuleTag' => '[mod_comment]',
'ModuleTagLink' => null,
'ModuleAveTag' => '#\\\[mod_comment(:[\\\d]+)?]#',
'ModulePHPTag' => '<?php mod_comment("$1"); ?>'
);
?>

View File

@@ -14,21 +14,42 @@ if(!defined('BASE_DIR')) exit;
* Функция, предназначенная для вывода списка комментариев к данному документу.
* Она будет выполнена при парсинге шаблона вместо системного тега [mod_comment].
*/
function mod_comment()
function mod_comment($param = '')
{
global $AVE_Template;
global $AVE_Template;
// Подключаем класс и создаем объект дял работы
require_once(BASE_DIR . '/modules/comment/class/comment.php');
$comment = new Comment;
// 1. Подключаем класс
require_once(BASE_DIR . '/modules/comment/class/comment.php');
$comment = new Comment;
// Подключаем языковые файлы
$tpl_dir = BASE_DIR . '/modules/comment/templates/';
$lang_file = BASE_DIR . '/modules/comment/lang/' . $_SESSION['user_language'] . '.txt';
$AVE_Template->config_load($lang_file, 'module');
// 2. Проверяем: если в теге передана цифра [mod_comment:5]
// $param может прийти в виде ":5" или просто "5" в зависимости от парсера
$limit = (int)str_replace(':', '', $param);
// Обращаемся к методу commentListShow() и отображаем список комментариев
$comment->commentListShow($tpl_dir);
if ($limit > 0) {
// --- РЕЖИМ "ПОСЛЕДНИЕ ОТЗЫВЫ" ---
$tpl_dir = BASE_DIR . '/modules/comment/templates/';
// Загружаем переводы (даты, заголовки)
$lang_file = BASE_DIR . '/modules/comment/lang/' . ($_SESSION['user_language'] ?? 'ru') . '.txt';
if (file_exists($lang_file)) $AVE_Template->config_load($lang_file, 'module');
// Берем данные из метода
$items = $comment->getLatestComments($limit);
$AVE_Template->assign('last_comments_items', $items);
// Выводим специальный шаблон для виджета
echo $AVE_Template->fetch($tpl_dir . 'last_comments.tpl');
return; // Выходим, чтобы под виджетом не вылез список комментов статьи
}
// --- СТАНДАРТНЫЙ РЕЖИМ (список под статьей) ---
// Если параметров нет или это обычный [mod_comment]
$tpl_dir = BASE_DIR . '/modules/comment/templates/';
$lang_file = BASE_DIR . '/modules/comment/lang/' . ($_SESSION['user_language'] ?? 'ru') . '.txt';
if (file_exists($lang_file)) $AVE_Template->config_load($lang_file, 'module');
$comment->commentListShow($tpl_dir);
}
/**

View File

@@ -0,0 +1,60 @@
<div class="last-comments-widget" style="max-width: 400px;">
<h4 class="widget-title mb-4" style="font-weight: 700; border-left: 4px solid #0d6efd; padding-left: 15px; line-height: 1.2;">Свежие отзывы</h4>
<div class="list-group list-group-flush">
{foreach from=$last_comments_items item=c}
<div class="list-group-item bg-transparent px-0 py-3 border-bottom" style="border-color: #f0f0f0 !important;">
<div class="d-flex align-items-start mb-2">
<div class="lc-avatar-wrapper">
{if $c.avatar}
<img src="{$c.avatar}" alt="{$c.comment_author_name|escape}">
{else}
<div class="lc-letter-circle av-c{$c.avatar_color_index|default:1}">
{$c.first_letter|default:'?'|upper}
</div>
{/if}
</div>
<div class="flex-grow-1 min-w-0">
<div class="d-flex justify-content-between align-items-start">
<div>
<strong style="color: #333; font-size: 0.95rem; display: block; line-height: 1.2;">
{$c.comment_author_name}
{if $c.parent_id > 0}
<span class="lc-reply-label">
<i class="bi bi-reply-all-fill text-primary"></i> ответил(а)
</span>
{/if}
</strong>
{if $c.stars}
<div class="d-flex align-items-center" style="margin-top: 3px; line-height: 1;">
{$c.stars}
</div>
{/if}
</div>
<span class="text-muted" style="font-size: 0.7rem; white-space: nowrap;">
<i class="bi bi-clock me-1"></i>{$c.date}
</span>
</div>
</div>
</div>
<div style="margin-left: 54px;">
<div class="mb-2">
<a href="{$c.link}" class="text-decoration-none d-flex align-items-center fw-medium" style="color: #0d6efd; font-size: 0.85rem;">
<i class="bi bi-file-earmark-text me-1 text-secondary"></i>
<span class="text-truncate">{$c.document_title}</span>
</a>
</div>
<div style="color: #444; font-size: 0.9rem; line-height: 1.4; background: #f9f9f9; padding: 10px 12px; border-radius: 0 8px 8px 8px; border-left: 2px solid #0d6efd;">
«{$c.comment_text}»
</div>
</div>
</div>
{/foreach}
</div>
</div>