добавлено превью загружаемого/загруженного фото

This commit is contained in:
2025-12-24 12:19:09 +05:00
parent e11b24ffe4
commit e9bd93daa0
2 changed files with 129 additions and 60 deletions

View File

@@ -119,7 +119,26 @@
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() {
@@ -143,40 +162,30 @@
});
});
// Универсальный обработчик клика по звездам (и в новой форме, и в ред.)
$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');
$('#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');
@@ -198,9 +207,7 @@
$doc.on('mouseleave', '.star-item', function() {
var $parent = $(this).parent();
if ($parent.hasClass('comment-like')) {
$(this).css('transform', 'scale(1)');
}
if ($parent.hasClass('comment-like')) { $(this).css('transform', 'scale(1)'); }
});
$doc.on('click', '.star-item', function() {
@@ -211,11 +218,7 @@
$.ajax({
url: 'index.php?module=comment&action=vote&ajax=1',
type: 'POST',
data: {
comment_id: commentId,
vote: voteValue,
ajax: 1
},
data: { comment_id: commentId, vote: voteValue, ajax: 1 },
success: function(response) {
var res = response.toString().trim();
if (res.indexOf('success') !== -1) {
@@ -225,28 +228,18 @@
alert('Вы уже голосовали за этот комментарий.');
} else if (res.indexOf('own_comment') !== -1) {
alert('Нельзя голосовать за свой собственный комментарий.');
}
/* НОВОЕ: Обработка запрета голосования для незарегистрированных пользователей */
else if (res.indexOf('forbidden_anon') !== -1) {
} else if (res.indexOf('forbidden_anon') !== -1) {
alert('Голосование доступно только зарегистрированным пользователям.');
}
else {
} else {
alert('Ошибка при обработке голоса сервером.');
}
},
error: function(xhr) {
alert('Ошибка связи с сервером. Статус: ' + xhr.status);
}
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.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) {
@@ -271,7 +264,7 @@
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');
@@ -280,7 +273,6 @@
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;
@@ -290,19 +282,14 @@
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>
@@ -317,21 +304,46 @@
}
}
// ВНЕДРЕНИЕ: Проверка прав на загрузку изображения при редактировании
// Обертка для ТЕКУЩЕГО изображения с крестиком (как при загрузке)
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 = `<input type="file" id="new_file_${cid}" class="form-control form-control-sm mb-3" accept="image/*">`;
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}
${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>` : ''}
${currentImgPreview}
${fileInputHtml}
<div class="d-flex gap-2">
<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>
@@ -342,6 +354,37 @@
$('#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();
@@ -356,13 +399,10 @@
fd.append('text', $('#ta_' + cid).val());
var rInput = $('#rating_input_' + cid);
if (rInput.length) {
fd.append('user_rating', rInput.val());
}
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];
@@ -372,6 +412,17 @@
$.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(); }
});
@@ -392,28 +443,36 @@
data: new FormData(this),
processData: false,
contentType: false,
beforeSend: function() {
$btn.prop('disabled', true).text('Отправка...');
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);
} else {
location.reload();
}
$('#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();
});
$doc.on('click', '#captcha img, #reload_captcha', function(e) { e.preventDefault(); getCaptha(); });
});
})(jQuery);

View File

@@ -172,6 +172,16 @@
<i class="bi bi-x-lg"></i>
</button>
</div>
{* --- НОВОЕ: ИНДИКАТОР ЗАГРУЗКИ (PROGRESS BAR) --- *}
<div id="upload_progress_container" class="mt-2 d-none">
<div class="progress" style="height: 8px;">
<div id="upload_progress_bar" class="progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" style="width: 0%"></div>
</div>
<div id="upload_status_text" class="small text-muted mt-1">Загрузка: 0%</div>
</div>
{* --- КОНЕЦ ИНДИКАТОРА --- *}
<div id="file_error" class="text-danger small mt-1 d-none"></div>
</div>
{/if}