Files
comment/js/comment.js

480 lines
26 KiB
JavaScript
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.
/* ====================================================================
ОБЕРТКА ДЛЯ ОЖИДАНИЯ 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('change', '#comment_image', function() {
var input = this;
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#image_preview_img').attr('src', e.target.result);
$('#image_preview_wrapper').removeClass('d-none');
}
reader.readAsDataURL(input.files[0]);
}
});
$doc.on('click', '#remove_image_btn', function() {
$('#comment_image').val('');
$('#image_preview_wrapper').addClass('d-none');
$('#image_preview_img').attr('src', '#');
});
// --- ЛОГИКА ВЫБОРА РЕЙТИНГА В ФОРМЕ ---
$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 ratingInput = $(this).closest('.rating-edit-block').find('input[type="hidden"]');
if (ratingInput.length) {
ratingInput.val(val);
} else {
$('#comment_user_rating').val(val);
}
$(this).prevAll().addBack().removeClass('bi-star').addClass('bi-star-fill');
$(this).nextAll().removeClass('bi-star-fill').addClass('bi-star');
});
$doc.on('click', '#buttonReset', function() {
$('#comment_user_rating').val(0);
$('#user_rating_stars .star-choice').removeClass('bi-star-fill').addClass('bi-star');
$('#image_preview_wrapper').addClass('d-none');
});
$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');
});
// --- РЕДАКТИРОВАНИЕ (С ПРЕДПРОСМОТРОМ ТЕКУЩЕГО ФОТО) ---
$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;
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');
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 currentImgPreview = '';
if (currentImg) {
currentImgPreview = `
<div id="existing_preview_wrapper_${cid}" class="mt-2 mb-2 position-relative" style="width: fit-content;">
<img src="${currentImg}" class="img-thumbnail" style="max-height: 100px;">
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-existing-img"
data-id="${cid}" style="padding: 0 5px; margin: 2px;" title="Удалить текущее фото">
<i class="bi bi-x-lg"></i>
</button>
<input class="form-check-input d-none" type="checkbox" id="del_img_${cid}">
</div>`;
}
var fileInputHtml = '';
if (typeof UGROUP !== 'undefined' && (UGROUP != '2' || (typeof ALLOW_FILES_ANON !== 'undefined' && ALLOW_FILES_ANON == '1'))) {
fileInputHtml = `
<div class="mb-2">
<label class="small text-muted mb-1">Заменить/Добавить фото:</label>
<input type="file" id="new_file_${cid}" class="form-control form-control-sm" accept="image/*">
</div>
<div id="edit_preview_wrapper_${cid}" class="mt-2 mb-2 d-none position-relative" style="width: fit-content;">
<img id="edit_preview_img_${cid}" src="#" alt="Превью" class="img-thumbnail" style="max-height: 100px;">
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-edit-new-img"
data-id="${cid}" style="padding: 0 5px; margin: 2px;">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div id="edit_progress_container_${cid}" class="mt-2 d-none">
<div class="progress" style="height: 5px;"><div id="edit_progress_bar_${cid}" class="progress-bar bg-success" style="width: 0%"></div></div>
</div>`;
}
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}
${currentImgPreview}
${fileInputHtml}
<div class="d-flex gap-2 align-items-center mt-3">
<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', '.remove-existing-img', function() {
var cid = $(this).data('id');
$('#existing_preview_wrapper_' + cid).addClass('d-none');
$('#del_img_' + cid).prop('checked', true); // Помечаем скрытый чекбокс на удаление
});
// Обработка выбора НОВОГО файла при редактировании
$doc.on('change', 'input[id^="new_file_"]', function() {
var cid = $(this).attr('id').replace('new_file_', '');
var input = this;
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#edit_preview_img_' + cid).attr('src', e.target.result);
$('#edit_preview_wrapper_' + cid).removeClass('d-none');
// Если выбрали новый файл, старое превью логично скрыть
$('#existing_preview_wrapper_' + cid).addClass('d-none');
$('#del_img_' + cid).prop('checked', true);
}
reader.readAsDataURL(input.files[0]);
}
});
// Удаление НОВОГО выбранного файла в режиме редактирования
$doc.on('click', '.remove-edit-new-img', function() {
var cid = $(this).data('id');
$('#new_file_' + cid).val('');
$('#edit_preview_wrapper_' + cid).addClass('d-none');
});
$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,
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var pct = Math.round((evt.loaded / evt.total) * 100);
$('#edit_progress_container_' + cid).removeClass('d-none');
$('#edit_progress_bar_' + cid).css('width', pct + '%');
}
}, false);
return xhr;
},
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,
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var pct = Math.round((evt.loaded / evt.total) * 100);
$('#upload_progress_container').removeClass('d-none');
$('#upload_progress_bar').css('width', pct + '%');
$('#upload_status_text').text('Загрузка: ' + pct + '%');
}
}, false);
return xhr;
},
beforeSend: function() { $btn.prop('disabled', true).text('Отправка...'); },
success: function(data) {
if (data.includes('wrong_securecode')) {
alert("Код капчи введен неверно!");
getCaptha();
$btn.prop('disabled', false).text(originalBtnText);
$('#upload_progress_container').addClass('d-none');
} else { location.reload(); }
},
error: function() {
alert("Ошибка связи с сервером");
$btn.prop('disabled', false).text(originalBtnText);
$('#upload_progress_container').addClass('d-none');
}
});
});
$doc.on('click', '#captcha img, #reload_captcha', function(e) { e.preventDefault(); getCaptha(); });
});
})(jQuery);
}
})();