добавлена загрузка файлов
This commit is contained in:
@@ -648,17 +648,19 @@ function commentPostFormShow($tpl_dir)
|
||||
$mime = finfo_file($finfo, $file['tmp_name']);
|
||||
finfo_close($finfo);
|
||||
|
||||
if (in_array($ext, $allowed_extensions)
|
||||
&& $file['size'] > 0
|
||||
&& $file['size'] <= $max_file_size_bytes
|
||||
&& strpos($mime, 'image/') === 0)
|
||||
{
|
||||
$new_name = time() . '_' . rand(100, 999) . '.' . $ext;
|
||||
if (move_uploaded_file($file['tmp_name'], $upload_path . $new_name)) {
|
||||
$uploaded_files[] = $new_name;
|
||||
$processed_hashes[] = $file_hash;
|
||||
}
|
||||
}
|
||||
// Проверки расширения и безопасности
|
||||
$is_allowed_ext = in_array($ext, $allowed_extensions);
|
||||
$is_dangerous = in_array($ext, ['php', 'php3', 'php4', 'php5', 'phtml', 'exe', 'pl', 'cgi']);
|
||||
|
||||
// Условие: расширение разрешено, файл не опасен и проходит по размеру
|
||||
if ($is_allowed_ext && !$is_dangerous && $file['size'] > 0 && $file['size'] <= $max_file_size_bytes)
|
||||
{
|
||||
$new_name = time() . '_' . rand(100, 999) . '.' . $ext;
|
||||
if (move_uploaded_file($file['tmp_name'], $upload_path . $new_name)) {
|
||||
$uploaded_files[] = $new_name;
|
||||
$processed_hashes[] = $file_hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,17 +852,18 @@ function commentPostEdit($comment_id)
|
||||
$mime = finfo_file($finfo, $tmp_name);
|
||||
finfo_close($finfo);
|
||||
|
||||
if (in_array($file_ext, $allowed_extensions)
|
||||
&& $file_size > 0
|
||||
&& $file_size <= ($max_kb * 1024)
|
||||
&& strpos($mime, 'image/') === 0)
|
||||
// Проверки расширения и опасных файлов
|
||||
$is_allowed_ext = in_array($file_ext, $allowed_extensions);
|
||||
$is_dangerous = in_array($file_ext, ['php', 'php3', 'php4', 'php5', 'phtml', 'exe', 'pl', 'cgi']);
|
||||
|
||||
if ($is_allowed_ext && !$is_dangerous && $file_size > 0 && $file_size <= ($max_kb * 1024))
|
||||
{
|
||||
if (!is_dir($upload_dir)) @mkdir($upload_dir, 0775, true);
|
||||
|
||||
$new_file_name = 'comm_' . time() . '_' . rand(1000, 9999) . '.' . $file_ext;
|
||||
|
||||
if (move_uploaded_file($tmp_name, $upload_dir . $new_file_name)) {
|
||||
$current_files[] = $new_file_name; // Добавляем новый файл к списку
|
||||
$current_files[] = $new_file_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
129
js/comment.js
129
js/comment.js
@@ -494,33 +494,39 @@ $doc.off('click', '.mod_comment_edit').on('click', '.mod_comment_edit', function
|
||||
|
||||
var cleanText = $textBlock.html().replace(/<br\s*\/?>/mg, "\n").trim();
|
||||
|
||||
// --- СБОР ТЕКУЩИХ КАРТИНОК (ТОЧНЫЙ ПОИСК ПО КОНТЕЙНЕРУ) ---
|
||||
// --- СБОР ТЕКУЩИХ ВЛОЖЕНИЙ ---
|
||||
var existingImagesHtml = '';
|
||||
|
||||
// Ищем картинки строго внутри контейнера вложений конкретного комментария
|
||||
var $imageContainer = $('#image_container_' + cid);
|
||||
var $foundImgs = $imageContainer.find('img');
|
||||
|
||||
if ($foundImgs.length > 0) {
|
||||
existingImagesHtml = '<div class="d-flex flex-wrap gap-2 mb-3" style="border: 1px dashed #ccc; padding: 10px; background: #fff; border-radius: 8px;">';
|
||||
// Ищем именно "карточки" из твоего шаблона (класс .comment-image-item)
|
||||
var $foundItems = $imageContainer.find('.comment-image-item');
|
||||
|
||||
if ($foundItems.length > 0) {
|
||||
existingImagesHtml = '<div class="d-flex flex-wrap gap-2 mb-3 p-2 bg-white border rounded border-dashed">';
|
||||
|
||||
$foundImgs.each(function(index) {
|
||||
var imgSrc = $(this).attr('src');
|
||||
if (!imgSrc) return;
|
||||
$foundItems.each(function(index) {
|
||||
var $item = $(this);
|
||||
var $link = $item.find('a');
|
||||
var fileUrl = $link.attr('href');
|
||||
if (!fileUrl) return;
|
||||
|
||||
var fileName = fileUrl.split('/').pop();
|
||||
var fileExt = fileName.split('.').pop().toLowerCase();
|
||||
var isImg = ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(fileExt);
|
||||
|
||||
// Используем твой же стиль превью
|
||||
var previewContent = isImg
|
||||
? `<img src="${fileUrl}" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover;">`
|
||||
: `<div class="d-flex align-items-center justify-content-center bg-light text-dark rounded border small fw-bold"
|
||||
style="width: 80px; height: 80px; text-transform: uppercase;">${fileExt}</div>`;
|
||||
|
||||
// Извлекаем имя файла из пути для передачи на сервер
|
||||
var fileName = imgSrc.split('/').pop();
|
||||
|
||||
existingImagesHtml += `
|
||||
<div id="existing_wrapper_${cid}_${index}" class="position-relative">
|
||||
<img src="${imgSrc}" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover;">
|
||||
${previewContent}
|
||||
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-existing-img"
|
||||
data-id="${cid}"
|
||||
data-img-path="${fileName}"
|
||||
data-target="existing_wrapper_${cid}_${index}"
|
||||
style="padding: 0 5px; margin: 2px; line-height: 1; z-index: 10;"
|
||||
title="Удалить">
|
||||
<i class="bi bi-x-lg" style="font-size: 0.8rem;"></i>
|
||||
data-id="${cid}" data-img-path="${fileName}" data-target="existing_wrapper_${cid}_${index}"
|
||||
style="padding: 0 4px; margin: 1px; line-height: 1; z-index: 10;">
|
||||
<i class="bi bi-x-lg" style="font-size: 0.7rem;"></i>
|
||||
</button>
|
||||
</div>`;
|
||||
});
|
||||
@@ -566,7 +572,7 @@ var editHtml = `
|
||||
<div class="mb-2">
|
||||
<label class="small text-muted mb-1">Добавить новые:</label>
|
||||
<div id="file_error_${cid}" class="js-file-error text-danger small fw-bold mb-1" style="display:none;"></div>
|
||||
<input type="file" name="comment_image[]" id="new_file_${cid}" class="form-control form-control-sm" accept="image/*" multiple>
|
||||
<input type="file" name="comment_image[]" id="new_file_${cid}" class="form-control form-control-sm" multiple>
|
||||
</div>
|
||||
<input type="hidden" name="delete_files" id="delete_files_${cid}" value="">
|
||||
|
||||
@@ -577,9 +583,14 @@ var editHtml = `
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
$textBlock.hide();
|
||||
$attachedImagesBlock.hide();
|
||||
$foundImgs.hide();
|
||||
// Прячем текст комментария
|
||||
$textBlock.hide();
|
||||
|
||||
// Прячем ВЕСЬ контейнер с оригиналами (и картинки, и упрямый ZIP)
|
||||
$('#image_container_' + cid).attr('style', 'display: none !important;');
|
||||
|
||||
// Для надежности скрываем всё остальное
|
||||
$wrapper.find('.mod_comment_attached_images, .comment-files').hide();
|
||||
|
||||
$textBlock.after(editHtml);
|
||||
|
||||
@@ -592,14 +603,10 @@ $('#new_file_' + cid).on('change', function() {
|
||||
var files = this.files;
|
||||
var $input = $(this);
|
||||
var $currentEditForm = $input.closest('.edit-form-container');
|
||||
|
||||
// ИЩЕМ ТОЛЬКО ПО КЛАССУ ОТНОСИТЕЛЬНО ИНПУТА
|
||||
var $errorDisplay = $input.prev('.js-file-error');
|
||||
|
||||
var $errorDisplay = $currentEditForm.find('.js-file-error');
|
||||
var maxLimit = parseInt(typeof MAX_FILES_COUNT !== 'undefined' ? MAX_FILES_COUNT : 5);
|
||||
|
||||
if (files) {
|
||||
// Очищаем при каждом новом выборе
|
||||
$errorDisplay.text('').hide();
|
||||
|
||||
$.each(files, function(i, file) {
|
||||
@@ -607,17 +614,17 @@ $('#new_file_' + cid).on('change', function() {
|
||||
var inPending = pendingFiles.filter(f => f !== null).length;
|
||||
|
||||
if ((alreadyInPost + inPending) >= maxLimit) {
|
||||
// ВЫВОДИМ ТЕКСТ
|
||||
$errorDisplay.text(' Лимит: ' + maxLimit + ' шт. Лишние файлы проигнорированы.').show();
|
||||
|
||||
$input.val('');
|
||||
$errorDisplay.text(' Лимит: ' + maxLimit + ' шт.').show();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file.type.match('image.*')) return true;
|
||||
// ПРОВЕРКА ЧЕРЕЗ ФУНКЦИЮ (она теперь берет ALLOWED_EXTENSIONS)
|
||||
if (!checkFileConsistency(file, $errorDisplay)) return true;
|
||||
|
||||
pendingFiles.push(file);
|
||||
var currentIndex = pendingFiles.length - 1;
|
||||
var fileExt = file.name.split('.').pop().toLowerCase();
|
||||
var isImage = ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(fileExt);
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
@@ -626,15 +633,23 @@ $('#new_file_' + cid).on('change', function() {
|
||||
$input.after(`<div id="new_files_preview_${cid}" class="d-flex flex-wrap gap-2 mt-2"></div>`);
|
||||
$previewContainer = $('#new_files_preview_' + cid);
|
||||
}
|
||||
|
||||
var content = isImage
|
||||
? `<img src="${e.target.result}" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover; border: 2px solid #0d6efd;">`
|
||||
: `<div class="d-flex align-items-center justify-content-center bg-light text-dark rounded border shadow-sm"
|
||||
style="width: 80px; height: 80px; font-weight: bold; text-transform: uppercase; font-size: 12px; border: 2px solid #0d6efd !important;">${fileExt}</div>`;
|
||||
|
||||
$previewContainer.append(`
|
||||
<div class="position-relative new-file-item" data-index="${currentIndex}">
|
||||
<img src="${e.target.result}" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover; border: 2px solid #0d6efd;">
|
||||
${content}
|
||||
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-new-file" style="padding: 0 5px; margin: 2px; line-height: 1;">
|
||||
<i class="bi bi-x-lg" style="font-size: 0.7rem;"></i>
|
||||
</button>
|
||||
</div>`);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
if (isImage) reader.readAsDataURL(file);
|
||||
else reader.onload({target: {result: ''}});
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -730,18 +745,23 @@ $doc.on('change', 'input[id^="new_file_"]', function() {
|
||||
// Обработка кнопки "Отмена" при редактировании
|
||||
$doc.on('click', '.cancelButton', function() {
|
||||
var $container = $(this).closest('.edit-form-container');
|
||||
// Находим главную обертку этого конкретного комментария
|
||||
var $wrapper = $container.closest('[id^="comment_wrapper_"]');
|
||||
var cid = $container.data('cid'); // Берем ID для обращения к контейнеру файлов
|
||||
|
||||
// 1. Возвращаем текст
|
||||
$wrapper.find('.mod_comment_text').show();
|
||||
|
||||
// 2. Возвращаем оригинальный блок с картинками
|
||||
// Ищем все возможные варианты названий блоков, которые мы скрывали
|
||||
$wrapper.find('.mod_comment_attached_image, .comment-files, .attached-images').show();
|
||||
// СНАЧАЛА ЧИСТИМ ИНЛАЙН СТИЛЬ (тот самый !important)
|
||||
$('#image_container_' + cid).attr('style', '');
|
||||
|
||||
// Затем стандартный показ
|
||||
$wrapper.find('.mod_comment_attached_image, .mod_comment_attached_images, .comment-files, .attached-images').show();
|
||||
|
||||
// 3. Если мы скрывали изображения напрямую через $foundImgs.hide(), показываем их
|
||||
$wrapper.find('img').show();
|
||||
// И ссылки (наш ZIP) тоже на всякий случай
|
||||
$wrapper.find('a').show();
|
||||
|
||||
// 4. Удаляем форму редактирования
|
||||
$container.remove();
|
||||
@@ -837,19 +857,28 @@ $doc.off('change', '#comment_image').on('change', '#comment_image', function() {
|
||||
var currentIndex = newCommentPendingFiles.length - 1;
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
if ($previewWrapper.find(`[data-index="${currentIndex}"]`).length > 0) return;
|
||||
reader.onload = function(e) {
|
||||
if ($previewWrapper.find(`[data-index="${currentIndex}"]`).length > 0) return;
|
||||
|
||||
$previewWrapper.removeClass('d-none');
|
||||
$previewWrapper.append(`
|
||||
<div class="position-relative new-comment-file-item" data-index="${currentIndex}">
|
||||
<img src="${e.target.result}" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover; border: 2px solid #198754;">
|
||||
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-new-comment-img"
|
||||
style="padding: 0 5px; margin: 2px; line-height: 1;">
|
||||
<i class="bi bi-x-lg" style="font-size: 0.7rem;"></i>
|
||||
</button>
|
||||
</div>`);
|
||||
};
|
||||
// Определяем, что вставить: картинку или заглушку с текстом расширения
|
||||
var fileExt = file.name.split('.').pop().toLowerCase();
|
||||
var isImage = ['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(fileExt);
|
||||
|
||||
// Формируем контент: либо твой оригинальный img, либо блок с расширением
|
||||
var content = isImage
|
||||
? `<img src="${e.target.result}" class="img-thumbnail" style="width: 80px; height: 80px; object-fit: cover; border: 2px solid #198754;">`
|
||||
: `<div class="d-flex align-items-center justify-content-center bg-primary text-white rounded" style="width: 80px; height: 80px; font-weight: bold; text-transform: uppercase; border: 2px solid #0d6efd;">${fileExt}</div>`;
|
||||
|
||||
$previewWrapper.removeClass('d-none');
|
||||
$previewWrapper.append(`
|
||||
<div class="position-relative new-comment-file-item" data-index="${currentIndex}">
|
||||
${content}
|
||||
<button type="button" class="btn btn-danger btn-sm position-absolute top-0 end-0 remove-new-comment-img"
|
||||
style="padding: 0 5px; margin: 2px; line-height: 1;">
|
||||
<i class="bi bi-x-lg" style="font-size: 0.7rem;"></i>
|
||||
</button>
|
||||
</div>`);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@
|
||||
var RATING_ANON_SET = '{$comment_rating_anon_set|default:0}';
|
||||
var ALLOW_FILES_ANON = '{$comment_allow_files_anon|default:0}';
|
||||
// --- ПЕРЕМЕННЫЕ ДЛЯ ВАЛИДАЦИИ ФАЙЛОВ ---
|
||||
var ALLOWED_EXTENSIONS = '{$comment_allowed_extensions|default:"jpg,jpeg,png,gif"}';
|
||||
var ALLOWED_EXTENSIONS = '{$comment_allowed_extensions|default:"jpg,jpeg,png,gif,webp"}';
|
||||
var MAX_FILE_SIZE_KB = '{$comment_max_file_size|default:2048}';
|
||||
var MAX_FILES_COUNT = '{$comment_max_files|default:5}';
|
||||
</script>
|
||||
|
||||
@@ -64,24 +64,58 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{* Вывод изображения (ИСПРАВЛЕНО ДЛЯ MULTIPLE) *}
|
||||
{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="photos" value=","|explode:$c.comment_file}
|
||||
{foreach from=$photos item=photo}
|
||||
{if $photo|trim}
|
||||
<div class="comment-image-item">
|
||||
<a href="{$ABS_PATH}uploads/comments/{$photo|trim}" target="_blank" class="d-block">
|
||||
<img src="{$ABS_PATH}uploads/comments/{$photo|trim}"
|
||||
class="img-fluid rounded border shadow-sm"
|
||||
style="max-height: 150px; width: auto; object-fit: cover;"
|
||||
alt="Изображение" />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{/foreach}
|
||||
{* Вывод файлов (Картинки ПЕРВЫМИ, остальное в КОНЦЕ) *}
|
||||
{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">
|
||||
<a href="{$ABS_PATH}uploads/comments/{$f_name}" target="_blank" class="d-block">
|
||||
<img src="{$ABS_PATH}uploads/comments/{$f_name}"
|
||||
class="img-fluid rounded border shadow-sm"
|
||||
style="width: 100px; height: 100px; object-fit: cover;"
|
||||
alt="Изображение" />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{/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">
|
||||
<a href="{$ABS_PATH}uploads/comments/{$f_name}" target="_blank" class="text-decoration-none d-block text-center">
|
||||
{* Блок с расширением *}
|
||||
<div class="d-flex align-items-center justify-content-center bg-light text-dark rounded border shadow-sm mb-1"
|
||||
style="width: 100px; height: 100px; font-weight: bold; text-transform: uppercase; font-size: 14px;">
|
||||
<i class="bi bi-file-earmark-arrow-down me-1"></i>{$f_ext}
|
||||
</div>
|
||||
{* Название файла *}
|
||||
<div class="text-muted small text-truncate" style="max-width: 100px;" title="{$f_name}">
|
||||
{$f_name}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{/foreach}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user