new InputFile(
{
elementContainer: container,
element: document.getElementById('<?=$inputId?>'),
maxSize: <?=$maxSize ?? 0?>,
defaultFileName: '<?=CUtil::JSEscape($defaultFileName)?>',
allowedExtensions: <?=CUtil::PhpToJSObject($extensions)?>,
truncate: <?=$truncate ?? 0?>,
isRequired: '<?=CUtil::JSEscape($required)?>',
multiple: '<?=$multiple?>',
multipleLimit: <?=$multipleLimit?>,
}
); class InputFile {
constructor(parameters) {
this.defaultFileName = 'Загрузить'
this.elementContainer = parameters.elementContainer;
this.element = parameters.element; // Input
this.truncate = parameters.truncate || 0; // После скольки символов обрезаем.
this.isRequired = parameters.isRequired || false;
this.multiple = parameters.multiple === 'Y';
this.multipleLimit = parameters.multipleLimit || 0;
// Дозволенные расширения.
this.allowedExtensions = parameters.allowedExtensions || {} // Пустой объект - любые файлы принимаем.
this.allowedExtensionsString = null
if (this.allowedExtensions) {
// Преобразуем объект в строку из ключей.
this.allowedExtensionsString = Object.keys(this.allowedExtensions).join(", ");
}
// Максимальный размер файла в байтах (по умолчанию бесконечность).
this.maxSize = parameters.maxSize || Infinity;
this.maxSizeInMb = null
if (this.maxSize !== Infinity) {
this.maxSizeInMb = this.bytesToMB(this.maxSize);
}
this.nodeName = null // Заголовок.
this.nodeInfo = null // Инфо о загруженном файле и перечень расширений.
this.nodeError = null // Куда пихаем ошибки.
this.nodeClearFile = null // Кнопка очистки input.
if (this.elementContainer) {
this.nodeName = this.elementContainer.querySelector('.input_file__name');
this.nodeInfo = this.elementContainer.querySelector('.input_file__info');
this.nodeError = this.elementContainer.querySelector('.input_file__error');
this.nodeClearFile = this.elementContainer.querySelector('.input_file__delete');
}
if (this.nodeClearFile) {
this.clearButtonHandler(this.nodeClearFile)
}
this.errors = {}
this.inputHandler();
}
inputHandler() {
this.element.addEventListener('change', (event) => {
const files = event.target.files; // Получаем загруженные файлы.
let filesQty = files.length
if (filesQty > 0) {
const file = files[0]; // Возьмем только первый файл.
// Чистим ошибки.
this.clearErrors();
if (this.validator(file, filesQty)) { // Все ОК!
this.setFileName(this.truncateString(file.name))
this.setFileInfo(file)
this.removeErrorClass(this.elementContainer)
} else {
this.setFileName(this.defaultFileName)
this.setFileInfo()
}
// Отображаем ошибки, если есть.
this.displayErrors();
}
});
}
/**
* Выводим название файла.
*/
setFileName(name) {
if (this.nodeName) {
this.nodeName.textContent = name;
}
}
/**
* Выводим информацию о загружаемом файле.
* Если def === true - скидываем на default.
*/
setFileInfo(file = null) {
if (this.nodeInfo) {
let info = ''
if (!file) {
info = this.allowedExtensionsString
} else {
let size = this.bytesToMB(file.size)
let extension = this.getFileExtension(file.name)
if (size) {
info = size + ' Мб'
}
if (extension) {
info += ', ' + extension
}
}
this.nodeInfo.textContent = info;
}
}
/**
* Получает расширение файла.
* Возвращаем последнее значение после точки или пустую строку.
*/
getFileExtension(fileName) {
const parts = fileName.split('.');
return parts.length > 1 ? parts.pop().toLowerCase() : '';
}
validator(file, filesQty) {
let countErrors = 0;
console.log(this.multiple, this.multipleLimit, filesQty)
// Проверяем количество файлов
if(this.multiple && this.multipleLimit !== 0) {
if(!this.validateMultipleLimit(filesQty)) {
this.errors.push(`Максимальное количество ${filesQty} шт.`);
countErrors++
return false; // Прерываем сразу, дальнейшие проверки не имеют смысла.
}
}
if (!this.validateMaxSize(file)) {
this.errors.push(`Ваш файл ${this.bytesToMB(file.size)} Мб, макс. размер ${this.maxSizeInMb} Мб.`);
countErrors++
}
if (!this.validateFileExtension(file)) {
countErrors++;
}
return countErrors === 0;
}
/**
* Проверяем размер файла.
*/
validateMaxSize(file) {
return file.size <= this.maxSize;
}
/**
* Проверяем на допустимое расширение файла.
*/
validateFileExtension(file) {
const fileExtension = this.getFileExtension(file.name); // Получаем расширение файла.
console.log(fileExtension)
console.log(this.allowedExtensions)
// Проверяем, существует ли расширение файла в объекте разрешенных расширений.
if (!(fileExtension in this.allowedExtensions)) {
this.errors.push(`Недопустимое расширение файла: ${fileExtension}`);
/*this.errors.push(`Недопустимое расширение файла: ${fileExtension}
. Разрешены: ${Object.keys(this.allowedExtensions).join(', ')}.`);*/
return false;
}
return true;
}
/**
* Проверяем количество загруженных файлов.
*/
validateMultipleLimit(filesQty) {
return this.multipleLimit !== 0 && filesQty <= this.multipleLimit;
}
bytesToMB(bytes) {
if (typeof bytes !== 'number' || bytes < 0) {
throw new Error('Введите допустимое число байтов (ноль или больше).');
}
return (bytes / (1024 * 1024)).toFixed(2);
}
/**
* Очищаем предыдущие ошибки.
*/
clearErrors() {
this.errors = [];
if (this.nodeError) {
this.nodeError.classList.remove('active');
this.nodeError.textContent = '';
}
}
/**
* Отображаем ошибки в элементе.
*/
displayErrors() {
if (this.nodeError && this.errors.length > 0) {
this.nodeError.innerHTML = this.errors.join('<br>');
this.nodeError.classList.add('active');
} else {
this.nodeError.innerHTML = '';
this.nodeError.classList.remove('active');
}
}
/**
* Обрезаем строку до заданной длины и добавляем три точки, если она длиннее.
*/
truncateString(str) {
if (this.truncate !== 0) {
if (str.length > this.truncate) {
return str.slice(0, this.truncate) + '...';
}
}
return str;
}
/**
* Очищаем input.
*/
clearInput(element) {
element.value = ''
this.setFileName(this.defaultFileName)
this.setFileInfo()
// Если поле обязательное, добавляем класс с ошибкой.
if(this.isRequired !== false) {
this.addErrorClass(this.elementContainer)
}
}
/**
* Обработчик клика кнопки "Удалить"
*/
clearButtonHandler(button) {
button.addEventListener('click', (event) => {
event.preventDefault()
event.stopPropagation()
let containerSelector = this.elementContainer.getAttribute('id');
let targetInput = button.closest('#' + containerSelector).querySelector('input[type="file"]')
if (targetInput && targetInput.value !== '') {
this.clearInput(targetInput)
}
})
}
addErrorClass(element) {
element.classList.add('_error')
}
removeErrorClass(element) {
if (element.classList.contains('_error')) {
element.classList.remove('_error')
}
}
}
Метод валидации Bootstrap
initValidation() {
'use strict';
this.form.addEventListener('submit', event => {
event.preventDefault();
event.stopPropagation();
this.form.classList.add('was-validated');
if (this.form.checkValidity()) {
this.sendRequest()
}
}, false);
}