421 lines
22 KiB
JavaScript
421 lines
22 KiB
JavaScript
/* ====================================================================
|
||
ОБЕРТКА ДЛЯ ОЖИДАНИЯ JQUERY
|
||
==================================================================== */
|
||
(function waitForJQuery() {
|
||
if (typeof jQuery === 'undefined') {
|
||
setTimeout(waitForJQuery, 10);
|
||
} else {
|
||
(function($) {
|
||
|
||
if (typeof aveabspath === 'undefined') {
|
||
window.aveabspath = '/';
|
||
}
|
||
|
||
/* --- ТАЙМЕРЫ --- */
|
||
function initCommentTimers() {
|
||
$('.timer-count:not(.timer-running)').each(function() {
|
||
var $timer = $(this);
|
||
$timer.addClass('timer-running');
|
||
var timeLeft = parseInt($timer.attr('data-left'));
|
||
var cid = $timer.attr('id').replace('timer_', '');
|
||
|
||
var countdown = setInterval(function() {
|
||
timeLeft--;
|
||
if (timeLeft <= 0) {
|
||
clearInterval(countdown);
|
||
$('#controls_' + cid).fadeOut(300);
|
||
$('#timer_container_' + cid).html('<span class="text-danger small">Время на правку истекло</span>');
|
||
return;
|
||
}
|
||
var minutes = Math.floor(timeLeft / 60);
|
||
var seconds = timeLeft % 60;
|
||
$timer.text(minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
|
||
$timer.attr('data-left', timeLeft);
|
||
}, 1000);
|
||
$timer.data('interval-id', countdown);
|
||
});
|
||
}
|
||
|
||
/* Limit Plugin */
|
||
$.fn.extend({
|
||
limit: function(limit, element) {
|
||
return this.each(function() {
|
||
var self = $(this);
|
||
function substring() {
|
||
var val = self.val();
|
||
if (val.length > limit) self.val(val.substring(0, limit));
|
||
if (typeof element !== 'undefined') {
|
||
var remaining = limit - self.val().length;
|
||
$(element).html(remaining < 0 ? '0' : remaining);
|
||
}
|
||
}
|
||
self.on('focus keyup paste', substring);
|
||
substring();
|
||
});
|
||
}
|
||
});
|
||
|
||
function getCaptha() {
|
||
var now = new Date();
|
||
$('#captcha img').attr('src', aveabspath + 'inc/captcha.php?cd=' + now.getTime());
|
||
}
|
||
|
||
function validate(form) {
|
||
var checks = [
|
||
{ field: form.comment_author_name, msg: "Введите имя" },
|
||
{ field: form.comment_author_email, msg: "Введите Email" },
|
||
{ field: form.comment_text, msg: "Введите текст" }
|
||
];
|
||
for (var i = 0; i < checks.length; i++) {
|
||
if (checks[i].field && !checks[i].field.value.trim()) {
|
||
alert(checks[i].msg);
|
||
$(checks[i].field).focus();
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/* --- ДЕЙСТВИЯ (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('<i class="bi bi-lock-fill me-1"></i> ' + 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('<i class="bi bi-unlock-fill me-1"></i> ' + 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 isLock = (action === 'lock');
|
||
$btn.toggleClass('mod_comment_lock mod_comment_unlock text-dark text-success')
|
||
.attr('title', isLock ? 'Разблокировать' : 'Заблокировать')
|
||
.find('i').toggleClass('bi-lock-fill bi-unlock-fill');
|
||
}
|
||
});
|
||
}
|
||
|
||
/* --- ИНИЦИАЛИЗАЦИЯ --- */
|
||
$(document).ready(function() {
|
||
initCommentTimers();
|
||
var $doc = $(document);
|
||
|
||
// --- ЛОГИКА ВЫБОРА РЕЙТИНГА В ФОРМЕ (НОВОЕ) ---
|
||
$doc.on('mouseenter', '.star-choice', function() {
|
||
var val = $(this).data('value');
|
||
$(this).parent().find('.star-choice').each(function() {
|
||
if ($(this).data('value') <= val) {
|
||
$(this).removeClass('bi-star').addClass('bi-star-fill');
|
||
} else {
|
||
$(this).removeClass('bi-star-fill').addClass('bi-star');
|
||
}
|
||
});
|
||
});
|
||
|
||
$doc.on('mouseleave', '.rating-edit-block', function() {
|
||
var cid = $(this).find('input[type="hidden"]').attr('id').replace('rating_input_', '');
|
||
var currentRating = parseInt($('#rating_input_' + cid).val()) || 0;
|
||
$(this).find('.star-choice').each(function() {
|
||
if ($(this).data('value') <= currentRating) {
|
||
$(this).removeClass('bi-star').addClass('bi-star-fill');
|
||
} else {
|
||
$(this).removeClass('bi-star-fill').addClass('bi-star');
|
||
}
|
||
});
|
||
});
|
||
|
||
// Универсальный обработчик клика по звездам (и в новой форме, и в ред.)
|
||
$doc.on('click', '.star-choice', function() {
|
||
var val = $(this).data('value');
|
||
var $parent = $(this).parent();
|
||
|
||
// 1. Ищем инпут для формы редактирования (он находится внутри .rating-edit-block)
|
||
var ratingInput = $(this).closest('.rating-edit-block').find('input[type="hidden"]');
|
||
|
||
if (ratingInput.length) {
|
||
ratingInput.val(val);
|
||
} else {
|
||
// 2. Ищем инпут для основной формы (по ID)
|
||
$('#comment_user_rating').val(val);
|
||
}
|
||
|
||
// Визуально фиксируем звезды сразу после клика
|
||
$(this).prevAll().addBack().removeClass('bi-star').addClass('bi-star-fill');
|
||
$(this).nextAll().removeClass('bi-star-fill').addClass('bi-star');
|
||
});
|
||
|
||
// Сброс звезд при очистке всей формы (кнопка Reset)
|
||
$doc.on('click', '#buttonReset', function() {
|
||
$('#comment_user_rating').val(0);
|
||
$('#user_rating_stars .star-choice').removeClass('bi-star-fill').addClass('bi-star');
|
||
});
|
||
|
||
// Сброс только звезд по кнопке "Сбросить" в основной форме
|
||
$doc.on('click', '#reset_stars', function(e) {
|
||
e.preventDefault();
|
||
$('#comment_user_rating').val(0);
|
||
$('#user_rating_stars .star-choice').removeClass('bi-star-fill').addClass('bi-star');
|
||
});
|
||
|
||
// Сброс звезд в форме редактирования
|
||
$doc.on('click', '.reset-edit-stars', function(e) {
|
||
e.preventDefault();
|
||
var cid = $(this).data('id');
|
||
$('#rating_input_' + cid).val(0);
|
||
$('#user_rating_stars_' + cid + ' .star-choice').removeClass('bi-star-fill').addClass('bi-star');
|
||
});
|
||
|
||
// --- ЛОГИКА ГОЛОСОВАНИЯ (РЕЙТИНГ УЖЕ ОПУБЛИКОВАННЫХ) ---
|
||
$doc.on('mouseenter', '.star-item', function() {
|
||
var $parent = $(this).parent();
|
||
if ($parent.hasClass('comment-like')) {
|
||
$(this).css('transform', 'scale(1.2)');
|
||
}
|
||
else {
|
||
$(this).prevAll().addBack().removeClass('bi-star').addClass('bi-star-fill');
|
||
$(this).nextAll().removeClass('bi-star-fill').addClass('bi-star');
|
||
}
|
||
});
|
||
|
||
$doc.on('mouseleave', '.star-item', function() {
|
||
var $parent = $(this).parent();
|
||
if ($parent.hasClass('comment-like')) {
|
||
$(this).css('transform', 'scale(1)');
|
||
}
|
||
});
|
||
|
||
$doc.on('click', '.star-item', function() {
|
||
var $container = $(this).closest('.comment-rating-container');
|
||
var commentId = $container.data('id');
|
||
var voteValue = $(this).data('value');
|
||
|
||
$.ajax({
|
||
url: 'index.php?module=comment&action=vote&ajax=1',
|
||
type: 'POST',
|
||
data: {
|
||
comment_id: commentId,
|
||
vote: voteValue,
|
||
ajax: 1
|
||
},
|
||
success: function(response) {
|
||
var res = response.toString().trim();
|
||
if (res.indexOf('success') !== -1) {
|
||
$container.html('<span class="text-success small fw-bold">Спасибо!</span>');
|
||
setTimeout(function(){ location.reload(); }, 1000);
|
||
} else if (res.indexOf('already_voted') !== -1) {
|
||
alert('Вы уже голосовали за этот комментарий.');
|
||
} else if (res.indexOf('own_comment') !== -1) {
|
||
alert('Нельзя голосовать за свой собственный комментарий.');
|
||
}
|
||
/* НОВОЕ: Обработка запрета голосования для незарегистрированных пользователей */
|
||
else if (res.indexOf('forbidden_anon') !== -1) {
|
||
alert('Голосование доступно только зарегистрированным пользователям.');
|
||
}
|
||
else {
|
||
alert('Ошибка при обработке голоса сервером.');
|
||
}
|
||
},
|
||
error: function(xhr) {
|
||
alert('Ошибка связи с сервером. Статус: ' + xhr.status);
|
||
}
|
||
});
|
||
});
|
||
|
||
// Глобальные кнопки управления
|
||
$doc.on('click', '#mod_comment_close', function(e) {
|
||
e.preventDefault(); cAction(this, 'close');
|
||
});
|
||
$doc.on('click', '#mod_comment_open', function(e) {
|
||
e.preventDefault(); cAction(this, 'open');
|
||
});
|
||
|
||
// КНОПКА ОТВЕТА
|
||
$doc.off('click', '.mod_comment_answer').on('click', '.mod_comment_answer', function(e) {
|
||
e.preventDefault();
|
||
var cid = $(this).data('id');
|
||
var $form = $('#mod_comment_new');
|
||
$form.insertAfter('#comment_' + cid).show();
|
||
$('#parent_id').val(cid);
|
||
$('html, body').animate({ scrollTop: $form.offset().top - 150 }, 500);
|
||
$('#in_message').focus();
|
||
});
|
||
|
||
// Удаление
|
||
$doc.off('click', '.mod_comment_delete').on('click', '.mod_comment_delete', function(e) {
|
||
e.preventDefault();
|
||
if (confirm('Удалить этот комментарий?')) cAction(this, 'delete');
|
||
});
|
||
|
||
// Блокировка
|
||
$doc.off('click', '.mod_comment_lock, .mod_comment_unlock').on('click', '.mod_comment_lock, .mod_comment_unlock', function(e) {
|
||
e.preventDefault();
|
||
cAction(this, $(this).hasClass('mod_comment_lock') ? 'lock' : 'unlock');
|
||
});
|
||
|
||
// --- РЕДАКТИРОВАНИЕ (ОБНОВЛЕННОЕ С ПРОВЕРКОЙ is_my_own) ---
|
||
$doc.off('click', '.mod_comment_edit').on('click', '.mod_comment_edit', function(e) {
|
||
e.preventDefault();
|
||
var cid = $(this).data('id');
|
||
var $wrapper = $('#comment_wrapper_' + cid);
|
||
var $textBlock = $wrapper.find('.mod_comment_text').first();
|
||
|
||
if ($wrapper.find('.edit-form-container').length > 0) return;
|
||
|
||
// ПРОВЕРКА АВТОРСТВА: используем флаг is_my_own из атрибута шаблона
|
||
var isMyOwn = $wrapper.attr('data-is-own') == '1';
|
||
var currentRating = parseInt($wrapper.attr('data-user-rating')) || 0;
|
||
|
||
$('.edit-form-container').remove();
|
||
$('.mod_comment_text').show();
|
||
|
||
var cleanText = $textBlock.html().replace(/<br\s*\/?>/mg, "\n").trim();
|
||
var currentImg = $wrapper.find('.mod_comment_attached_image img').first().attr('src');
|
||
|
||
// Рисуем звезды ТОЛЬКО если настройка включена И это собственный комментарий (is_my_own)
|
||
var starsEditBlock = '';
|
||
if (typeof SHOW_USER_RATING !== 'undefined' && SHOW_USER_RATING == '1' && isMyOwn) {
|
||
|
||
// ВНЕДРЕНИЕ: Проверка прав группы (Авторизован или разрешено анонимам)
|
||
if (typeof UGROUP !== 'undefined' && (UGROUP != '2' || RATING_ANON_SET == '1')) {
|
||
|
||
var starsHtml = '';
|
||
for(var i=1; i<=5; i++) {
|
||
var starClass = (i <= currentRating) ? 'bi-star-fill' : 'bi-star';
|
||
starsHtml += `<i class="star-choice ${starClass}" data-value="${i}" style="cursor: pointer; color: #ffc107; font-size: 1.2rem; margin-right: 2px;"></i>`;
|
||
}
|
||
|
||
starsEditBlock = `
|
||
<div class="mb-2 rating-edit-block">
|
||
<label class="small text-muted d-block mb-1">Ваша оценка:</label>
|
||
<div class="d-flex align-items-center">
|
||
<div id="user_rating_stars_${cid}">${starsHtml}</div>
|
||
<a href="javascript:void(0);" class="reset-edit-stars ms-3 text-decoration-none small text-muted" data-id="${cid}">
|
||
<i class="bi bi-x-circle"></i> Сбросить
|
||
</a>
|
||
</div>
|
||
<input type="hidden" name="comment_user_rating" id="rating_input_${cid}" value="${currentRating}" />
|
||
</div>`;
|
||
}
|
||
}
|
||
|
||
// ВНЕДРЕНИЕ: Проверка прав на загрузку изображения при редактировании
|
||
var fileInputHtml = '';
|
||
if (typeof UGROUP !== 'undefined' && (UGROUP != '2' || (typeof ALLOW_FILES_ANON !== 'undefined' && ALLOW_FILES_ANON == '1'))) {
|
||
fileInputHtml = `<input type="file" id="new_file_${cid}" class="form-control form-control-sm mb-3" accept="image/*">`;
|
||
}
|
||
|
||
var editHtml = `
|
||
<div class="edit-form-container border rounded p-3 bg-light mt-2 mb-2">
|
||
<textarea rows="5" id="ta_${cid}" class="form-control mb-2">${cleanText}</textarea>
|
||
|
||
${starsEditBlock}
|
||
|
||
${currentImg ? `<div class="form-check mb-2"><input class="form-check-input" type="checkbox" id="del_img_${cid}"><label class="form-check-label small text-danger" for="del_img_${cid}">Удалить фото</label></div>` : ''}
|
||
${fileInputHtml}
|
||
<div class="d-flex gap-2">
|
||
<button type="button" class="btn btn-sm btn-primary saveButton" data-id="${cid}">Сохранить</button>
|
||
<button type="button" class="btn btn-sm btn-secondary cancelButton">Отмена</button>
|
||
<small class="ms-auto text-muted">Осталось: <span id="charsLeft_${cid}"></span></small>
|
||
</div>
|
||
</div>`;
|
||
|
||
$textBlock.hide().after(editHtml);
|
||
$('#ta_' + cid).limit(1000, '#charsLeft_' + cid).focus();
|
||
});
|
||
|
||
$doc.on('click', '.cancelButton', function() {
|
||
var $container = $(this).closest('.edit-form-container');
|
||
$container.prev('.mod_comment_text').show();
|
||
$container.remove();
|
||
});
|
||
|
||
$doc.on('click', '.saveButton', function() {
|
||
var $btn = $(this);
|
||
var cid = $btn.data('id');
|
||
var fd = new FormData();
|
||
fd.append('module', 'comment'); fd.append('action', 'edit'); fd.append('Id', cid);
|
||
fd.append('text', $('#ta_' + cid).val());
|
||
|
||
var rInput = $('#rating_input_' + cid);
|
||
if (rInput.length) {
|
||
fd.append('user_rating', rInput.val());
|
||
}
|
||
|
||
fd.append('delete_image', $('#del_img_' + cid).is(':checked') ? 1 : 0);
|
||
|
||
// Проверяем наличие инпута перед попыткой чтения файла
|
||
var fileInput = $('#new_file_' + cid);
|
||
if (fileInput.length) {
|
||
var file = fileInput[0].files[0];
|
||
if (file) fd.append('comment_image', file);
|
||
}
|
||
|
||
$.ajax({
|
||
url: aveabspath + 'index.php?ajax=1',
|
||
type: 'POST', data: fd, processData: false, contentType: false,
|
||
beforeSend: function() { $btn.prop('disabled', true).text('...'); },
|
||
success: function() { location.reload(); }
|
||
});
|
||
});
|
||
|
||
// Отправка новой формы (или ответа)
|
||
$doc.on('submit', '#mod_comment_new form', function(e) {
|
||
e.preventDefault();
|
||
if (!validate(this)) return false;
|
||
|
||
var $form = $(this);
|
||
var $btn = $form.find('[type="submit"]');
|
||
var originalBtnText = $btn.text();
|
||
|
||
$.ajax({
|
||
url: aveabspath + 'index.php?ajax=1',
|
||
type: 'POST',
|
||
data: new FormData(this),
|
||
processData: false,
|
||
contentType: false,
|
||
beforeSend: function() {
|
||
$btn.prop('disabled', true).text('Отправка...');
|
||
},
|
||
success: function(data) {
|
||
if (data.includes('wrong_securecode')) {
|
||
alert("Код капчи введен неверно!");
|
||
getCaptha();
|
||
$btn.prop('disabled', false).text(originalBtnText);
|
||
} else {
|
||
location.reload();
|
||
}
|
||
},
|
||
error: function() {
|
||
alert("Ошибка связи с сервером");
|
||
$btn.prop('disabled', false).text(originalBtnText);
|
||
}
|
||
});
|
||
});
|
||
|
||
$doc.on('click', '#captcha img, #reload_captcha', function(e) {
|
||
e.preventDefault(); getCaptha();
|
||
});
|
||
});
|
||
|
||
})(jQuery);
|
||
}
|
||
})(); |