Files
comment/templates/comments_tree_sub.tpl
2026-02-01 19:05:11 +05:00

406 lines
21 KiB
Smarty
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{literal}
<style>
/* Стили для стандартной шапки поповера */
.popover-header {
background-color: #f0f0f0 !important; /* Тот самый серый цвет */
border-bottom: 1px solid #dee2e6 !important;
padding: 8px 12px !important;
font-size: 0.9rem !important;
font-weight: 600 !important;
}
/* Кнопка закрытия в шапке */
.pop-close {
background: none !important;
border: none !important;
font-size: 22px !important;
line-height: 1 !important;
color: #999 !important;
cursor: pointer !important;
padding: 0 !important;
margin-left: 10px !important;
}
.pop-close:hover {
color: #f00 !important;
}
.popover-body {
padding: 12px !important;
min-width: 230px !important;
}
.author-popover, .author-popover:focus, .author-popover:active {
outline: none !important;
box-shadow: none !important;
text-decoration: none !important;
}
</style>
{/literal}
{foreach from=$subcomments item=c name=sub_loop}
{* ОПРЕДЕЛЯЕМ СТАТУС УДАЛЕНИЯ *}
{assign var="is_deleted" value=false}
{if $c.comment_author_name == '__DELETED__' || $c.comment_author_name == 'Удалено'}
{assign var="is_deleted" value=true}
{/if}
{assign var="parent_hidden" value=false}
{if isset($parent_status) && $parent_status == 0}
{assign var="parent_hidden" value=true}
{/if}
<div class="card mb-3 mod_comment_comment {if $c.parent_id} ms-2 ms-md-4{/if} {if $is_deleted}opacity-75 bg-light{/if}"
id="comment_wrapper_{$c.Id}"
data-parent="{$c.parent_id|default:0}"
data-user-rating="{$c.user_rating|default:0}"
data-is-own="{if isset($c.is_my_own) && $c.is_my_own}1{else}0{/if}">
{if isset($smarty.request.subaction) && $smarty.request.subaction=='showonly' && isset($smarty.request.comment_id) && $smarty.request.comment_id==$c.Id}
<div class="border border-warning border-3 rounded p-0">
{/if}
<div id="comment_{$c.Id}" class="mod_comment_box {if $c.comment_status == 0 && !$is_deleted}opacity-75 border border-warning rounded{/if}">
<div class="card-body p-3 d-flex align-items-start">
{* БЛОК АВАТАРА *}
<div class="mod_comment_avatar">
{if !$is_deleted}
{if isset($c.avatar) && $c.avatar != ''}
<img src="{$c.avatar}" alt="{$c.comment_author_name|escape}" class="rounded-circle">
{else}
<div class="mod_comment_avatar_letter av-c{$c.avatar_color_index|default:1}">
{$c.first_letter|default:'?'|upper}
</div>
{/if}
{else}
<div class="mod_comment_avatar_letter bg-secondary text-white" style="opacity: 0.5;">
{if $c.comment_text == '__DEL_BY_ADM__'}
<i class="bi bi-shield-lock"></i>
{else}
<i class="bi bi-person-x"></i>
{/if}
</div>
{/if}
</div>
<div class="flex-grow-1 min-w-0">
{* ПРОВЕРКА НА МОДЕРАЦИЮ ДЛЯ АВТОРА *}
{if $c.comment_status == 0 && !$is_deleted}
<div class="alert alert-warning py-1 px-2 mb-2 small d-flex align-items-center border-0 shadow-sm" style="border-left: 4px solid #ffc107 !important;">
<i class="bi bi-clock-history me-2 text-dark"></i>
<span class="text-dark">
{#COMMENT_WAITING_MODERATION#}
</span>
</div>
{/if}
{* Информация об авторе и дате *}
<div class="mod_comment_meta text-muted small d-flex flex-wrap align-items-center">
{if !$is_deleted}
<span class="d-flex align-items-center">
<i class="bi bi-person me-1"></i>
<span title="{#COMMENT_PUB_AUTOR_A#}">
<a href="javascript:void(0);"
class="author-popover fw-bold link-dark text-decoration-none"
data-id="{$c.Id}"
role="button"
tabindex="0">
{$c.comment_author_name|stripslashes|escape}
</a>
</span>
{* ПРОВЕРКА ИСТОРИИ ИМЕН АНОНИМА *}
{if !empty($c.past_names)}
<span class="badge rounded-pill bg-light text-danger border border-danger ms-1"
style="font-size: 0.65rem; cursor: help;"
data-bs-toggle="tooltip"
data-bs-html="true"
title="{#COMMENT_CHECK_NAME#}<br/>{foreach $c.past_names as $pname}{$pname|escape}<br/>{/foreach}">
<i class="bi bi-exclamation-triangle-fill"></i> {#COMMENT_CHECK_NAME_TRUE#}
</span>
{/if}
</span>
<span class="d-flex align-items-center ms-2"><i class="bi bi-clock me-1"></i> {$c.comment_published}</span>
{if $smarty.const.UGROUP==1}
<span class="text-secondary d-none d-sm-inline ms-2">• IP:{$c.comment_author_ip}</span>
{/if}
{if isset($c.comment_changed) && $c.comment_changed && $c.comment_changed != '0'}
<span class="badge bg-light text-secondary border fw-normal ms-2" id="changed_{$c.Id}">{#COMMENT_CHECK_NAME_EDIT#} {$c.comment_changed}</span>
{/if}
{else}
<span class="fw-bold text-secondary text-uppercase" style="font-size: 0.75rem;">
<i class="bi bi-info-circle me-1"></i> {#COMMENT_STATUS_DELETED#}
</span>
<span class="ms-2 d-flex align-items-center"><i class="bi bi-clock me-1"></i> {$c.comment_published}</span>
{/if}
</div>
{* Текст комментария *}
<div class="mod_comment_text comment-text-content mb-2 {if $is_deleted}text-secondary fst-italic{/if}">
{if $c.comment_text == '__DEL_BY_ADM__'}
<i class="bi bi-shield-exclamation me-1"></i> {#COMMENT_TEXT_DEL_BY_ADMIN#}
{elseif $c.comment_text == '__DEL_BY_AUT__'}
<i class="bi bi-trash3 me-1"></i> {#COMMENT_TEXT_DEL_BY_AUTHOR#}
{elseif $is_deleted}
<i class="bi bi-trash3 me-1"></i> {#COMMENT_STATUS_DELETED#}
{else}
{$c.comment_text|stripslashes|nl2br}
{/if}
</div>
{* Доп. поля и Файлы (Выводим только если НЕ удален) *}
{if !$is_deleted}
{if $c.comment_author_website || $c.comment_author_city}
<div class="small text-muted mb-2 border-start ps-2">
{if $c.comment_author_website}<div><i class="bi bi-link-45deg"></i> {$c.comment_author_website}</div>{/if}
{if $c.comment_author_city}<div><i class="bi bi-geo-alt"></i> {$c.comment_author_city}</div>{/if}
</div>
{/if}
{if !empty($c.comment_file)}
<div class="mod_comment_attached_images mt-2 d-flex flex-wrap gap-2" id="image_container_{$c.Id}">
{assign var="all_files" value=","|explode:$c.comment_file}
{assign var="img_exts" value=['jpg', 'jpeg', 'png', 'gif', 'webp']}
{* 1. ИЗОБРАЖЕНИЯ *}
{foreach from=$all_files item=file}
{assign var="f_name" value=$file|trim}
{if $f_name}
{assign var="ext_parts" value="."|explode:$f_name}
{assign var="f_ext" value=$ext_parts[$ext_parts|@count-1]|lower}
{if in_array($f_ext, $img_exts)}
<div class="comment-image-item d-flex flex-column align-items-center justify-content-between h-100">
<a href="{$ABS_PATH}uploads/comments/{$f_name}" target="_blank" class="card-link-wrapper d-flex align-items-center justify-content-center mb-1" style="height: 100px;">
<img src="{$ABS_PATH}uploads/comments/{$f_name}" class="img-fluid rounded border shadow-sm" style="width: 100px; height: 100px; object-fit: cover;" alt="{#COMMENT_FILE_IMAGE#}" />
</a>
<div class="d-flex align-items-center">
<span class="badge bg-light text-secondary border fw-normal text-truncate d-inline-block" style="max-width: 100px; font-size: 0.7rem; padding: 1px 4px; line-height: 1.2;" title="{$f_name|regex_replace:'/_[0-9]+(?=\.[a-z0-9]+$)/i':''}">
{$f_name|regex_replace:"/_[0-9]+(?=\.[a-z0-9]+$)/i":""}
</span>
</div>
</div>
{/if}
{/if}
{/foreach}
{* 2. ОСТАЛЬНЫЕ файлы *}
{foreach from=$all_files item=file}
{assign var="f_name" value=$file|trim}
{if $f_name}
{assign var="ext_parts" value="."|explode:$f_name}
{assign var="f_ext" value=$ext_parts[$ext_parts|@count-1]|lower}
{if !in_array($f_ext, $img_exts)}
<div class="comment-image-item d-flex flex-column align-items-center justify-content-between h-100">
<a href="{$ABS_PATH}uploads/comments/{$f_name}" target="_blank" class="card-link-wrapper text-decoration-none d-block text-center mb-1">
<div class="file-box d-flex align-items-center justify-content-center bg-light text-dark rounded border shadow-sm" style="width: 100px; height: 100px; font-weight: bold; text-transform: uppercase; font-size: 14px; transition: all 0.2s;">
<i class="bi bi-file-earmark-arrow-down me-1"></i>{$f_ext}
</div>
</a>
<div class="d-flex align-items-center">
<span class="badge bg-light text-secondary border fw-normal text-truncate d-inline-block" style="max-width: 100px; font-size: 0.7rem; padding: 1px 4px; line-height: 1.2;" title="{$f_name|regex_replace:'/_[0-9]+(?=\.[a-z0-9]+$)/i':''}">
{$f_name|regex_replace:"/_[0-9]+(?=\.[a-z0-9]+$)/i":""}
</span>
</div>
</div>
{/if}
{/if}
{/foreach}
</div>
{/if}
{/if}
</div>
</div>
{* ФУТЕР *}
<div class="card-footer bg-white border-top p-2 d-flex flex-wrap justify-content-between align-items-center gap-2">
<div class="d-flex align-items-center flex-wrap gap-2">
{if !$is_deleted}
{* 1. Оценка автора *}
{if isset($c.user_rating) && $c.user_rating > 0}
<div class="rating-author-badge" title="{#COMMENT_AUTOR_RATING_A#} {$c.user_rating} {#COMMENT_AUTOR_RATING_IZ#} 5">
<span class="d-none d-sm-inline">{#COMMENT_AUTOR_RATING_B#}</span>
<div class="rating-author-stars">
{section name=r_star start=1 loop=6}
<i class="bi {if $smarty.section.r_star.index <= $c.user_rating}bi-star-fill{else}bi-star{/if}"></i>
{/section}
</div>
<span class="rating-value">{$c.user_rating}</span>
</div>
{/if}
{* 2. Рейтинг комментария *}
{if $comment_rating_type != 2}
<div class="comment-rating-container d-flex align-items-center py-1 px-2 bg-light rounded border" data-id="{$c.Id}">
{if $comment_rating_type == 1}
<div class="comment-like text-danger" style="cursor: pointer;">
<i class="star-item bi bi-heart-fill me-1" data-value="5"></i>
<span class="fw-bold small">{$c.rating_count|default:0}</span>
</div>
{else}
<div class="comment-stars text-warning" style="cursor: pointer;">
{assign var="avg_rating" value=0}
{if isset($c.rating_count) && $c.rating_count > 0}
{math equation="round(x / y)" x=$c.rating_sum y=$c.rating_count assign="avg_rating"}
{/if}
<div class="d-flex align-items-center me-1">
{section name=star start=1 loop=6}
<i class="star-item bi {if $smarty.section.star.index <= $avg_rating}bi-star-fill{else}bi-star{/if} me-1" data-value="{$smarty.section.star.index}"></i>
{/section}
</div>
{if isset($c.rating_count)}<span class="text-muted small">({$c.rating_count})</span>{/if}
</div>
{/if}
</div>
{/if}
{* 3. Таймер редактирования *}
{if $c.can_edit && isset($c.edit_time_left) && $c.edit_time_left > 0}
<div class="text-muted small d-flex align-items-center" id="timer_container_{$c.Id}">
<i class="bi bi-hourglass-split text-primary me-1"></i> {#COMMENT_PUB_TIMER_TXT_A#}
<span id="timer_{$c.Id}" data-left="{$c.edit_time_left}" class="timer-count fw-bold">
{math equation="floor(x/3600)" x=$c.edit_time_left assign="h"}
{math equation="floor((x%3600)/60)" x=$c.edit_time_left assign="m"}
{math equation="x%60" x=$c.edit_time_left assign="s"}
{if $h > 0}{$h} {#COMMENT_PUB_TIMER_HOUR#} {/if}
{* Теперь минуты тоже с ведущим нулем *}
{if $m < 10}0{/if}{$m} {#COMMENT_PUB_TIMER_MIN#}
{if $s < 10}0{/if}{$s} {#COMMENT_PUB_TIMER_SEC#}
</span>{#COMMENT_PUB_TIMER_TXT_B#}
</div>
{/if}
{/if}
</div>
{* КНОПКИ ДЕЙСТВИЙ *}
<div class="actions-buttons d-flex align-items-center gap-1">
{if !$is_deleted}
{if ($cancomment==1 && $closed!=1) || $smarty.const.UGROUP==1}
{if $comment_allow_self_answer == 1 || !(isset($c.is_my_own) && $c.is_my_own)}
<a class="btn btn-sm btn-link text-primary text-decoration-none mod_comment_answer px-2" href="javascript:void(0);" data-id="{$c.Id}">
<i class="bi bi-reply-fill me-1"></i> <span class="d-none d-sm-inline">{#COMMENT_ANSWER_LINK#}</span>
</a>
{/if}
{/if}
<span id="controls_{$c.Id}" class="d-flex align-items-center gap-1">
{if $c.can_edit}
<a class="btn btn-sm btn-link text-warning mod_comment_edit px-2" title="{#COMMENT_EDIT_LINK#}" href="javascript:void(0);" data-id="{$c.Id}"><i class="bi bi-pencil-square"></i></a>
<a class="btn btn-sm btn-link text-danger mod_comment_delete px-2" title="{#COMMENT_DELETE_LINK#}" href="javascript:void(0);" data-id="{$c.Id}"><i class="bi bi-trash"></i></a>
{/if}
</span>
{if $smarty.const.UGROUP==1}
{* Если родитель НЕ скрыт — показываем кнопку управления потомком *}
<a class="btn btn-sm btn-link {if $c.comment_status==1}text-success{else}text-danger{/if} mod_comment_toggle px-2"
href="javascript:void(0);"
data-id="{$c.Id}"
{if $parent_hidden}style="display: none;"{/if}
title="{if $c.comment_status==1}{#COMMENT_ICON_HIDE#}{else}{#COMMENT_ICON_SHOW#}{/if}">
<i class="bi bi-{if $c.comment_status==1}eye{else}eye-slash{/if}"></i>
</a>
{/if}
{/if}
</div>
</div>
</div>
{if isset($smarty.request.subaction) && $smarty.request.subaction=='showonly' && isset($smarty.request.comment_id) && $smarty.request.comment_id==$c.Id}
</div>
{/if}
<span id="end{$c.Id}"></span>
{if isset($comments) && isset($comments[$c.Id])}
<div class="mt-2">
{include file="$subtpl" subcomments=$comments[$c.Id] sub=1 parentId=$c.Id parent_status=$c.comment_status}
</div>
{/if}
</div>
{* --- ВСТАВЛЯЕМ КНОПКУ AJAX ОТВЕТОВ --- *}
{if $smarty.foreach.sub_loop.last && isset($more_counts[$parentId])}
<div id="ajax_loader_{$parentId}" class="ms-4 mb-3">
<button class="btn btn-sm btn-outline-primary" onclick="loadMoreReplies('{$parentId}')">
<i class="bi bi-chevron-double-down"></i> {#COMMENT_ANSWER_AJAX_BUTTON#} {$more_counts[$parentId]} {#COMMENT_ANSWER_AJAX_TEXT#}
</button>
</div>
{/if}
{/foreach}
{literal}
<script type="text/javascript">
(function() {
// Глобальный обработчик для крестика
document.addEventListener('click', function(e) {
if (e.target.closest('.pop-close')) {
const pid = e.target.closest('.pop-close').getAttribute('data-id');
const trigger = document.querySelector(`.author-popover[data-id="${pid}"]`);
if (trigger) {
const ins = bootstrap.Popover.getInstance(trigger);
if (ins) ins.hide();
trigger.blur();
}
}
});
const startInitialization = () => {
if (typeof bootstrap === 'undefined') return false;
document.querySelectorAll('.author-popover').forEach(el => {
if (el.getAttribute('data-popover-initialized')) return;
new bootstrap.Popover(el, {
html: true,
sanitize: false,
trigger: 'focus',
placement: 'top',
// ВОТ ЗДЕСЬ ВОЗВРАЩАЕМ ШАПКУ
title: function() {
const cid = el.getAttribute('data-id');
return `
<span>${COMMENT_PUB_AUTOR_A}</span>
<button type="button" class="pop-close" data-id="${cid}">&times;</button>
`;
},
content: function() {
const commentId = el.getAttribute('data-id');
const popoverId = 'popover-content-' + commentId;
setTimeout(() => {
const popContent = document.getElementById(popoverId);
if (popContent && popContent.innerHTML === '...') {
if (el.getAttribute('data-loading') === 'true') return;
el.setAttribute('data-loading', 'true');
fetch('index.php?module=comment&action=postinfo&pop=1&Id=' + commentId)
.then(res => res.text())
.then(html => {
popContent.innerHTML = html;
el.setAttribute('data-loading', 'false');
})
.catch(() => { popContent.innerHTML = 'Ошибка'; el.setAttribute('data-loading', 'false'); });
}
}, 30);
return `<div id="${popoverId}">...</div>`;
},
template: `
<div class="popover" role="tooltip">
<div class="popover-arrow"></div>
<h3 class="popover-header d-flex justify-content-between align-items-center"></h3>
<div class="popover-body"></div>
</div>`
});
el.setAttribute('data-popover-initialized', 'true');
});
return true;
};
let timer = setInterval(() => { if (startInitialization()) clearInterval(timer); }, 300);
})();
</script>
{/literal}