Вход

Просмотр полной версии : Форма загрузки изображения. Рефакторинг


sdareios
20.01.2020, 11:16
Всем привет!

Пишу впервые на этом форуме. Так что простите, если что не так)

Написал HTML-форму, с помощью которой пользователь загружает свое фото (аву) на сайт. Сначала все это было на HTML + jQuery. Но меня в последнее время одолевает желание отказаться от jQuery в пользу нативного Javascript'а где это только возможно. Да, лучше позже, как говориться))

Скрипт получился вполне себе рабочий. Вот только видел я много разного кода и более чем адекватно оцениваю свои знания. Поэтому обращаюсь к более опытным людям за советом. Может кто подскажет как можно сделать грамотно рефакторинг?

Сама форма
<div id="customer_photo" data-maxfilesize="{{ max_file_size }}">
<img id="customer_photo_img" src="{{ photo }}" class="img-fluid">

<form id="customer_photo_form">
<input id="customer_photo_input" type="file" name="photo" accept="{{ mime_allowed }}" required>
</form>

<div id="customer_photo_callback"
data-error_validation_by_type="{{ error_validation_by_type }}"
data-error_validation_by_size="{{ error_validation_by_size }}">
</div>
</div>
document.getElementById('customer_photo_input').ad dEventListener('change', changePhoto, false);

function changePhoto(evt) {
let file = evt.target.files[0];

if (file.length !== 0) {
if (!fileValidationByType(file)) {
let message = document.getElementById('customer_photo_callback') .getAttribute('data-error_validation_by_type');

document.getElementById('customer_photo_callback') .innerHTML = message;
} else if (!fileValidationBySize(file)) {
let message = document.getElementById('customer_photo_callback') .getAttribute('data-error_validation_by_size');

document.getElementById('customer_photo_callback') .innerHTML = message;
} else {
fileUpload(file);
}
} else {
console.log('Selected file is empty!');
}
}

function fileValidationByType(file) {
var fileTypes = [
{% for mime in mime_allowed_array %}
'{{ mime }}',
{% endfor %}
]

for (var i = 0; i < fileTypes.length; i++) {
if (file.type === fileTypes[i]) {
return true;
}
}

return false;
}

function fileValidationBySize(file) {
var maxfilesize = document.getElementById('customer_photo').getAttri bute('data-maxfilesize');

if (file.size <= maxfilesize) {
return true;
}

return false;
}

function fileUpload(file) {
var url = '{{ url }}',
data = new FormData();

data.append('photo', file);

var xhr = new XMLHttpRequest();

xhr.onload = function() {
if (xhr.readyState === xhr.DONE) {
if (xhr.status === 200) {
try {
var data = JSON.parse(xhr.responseText);
} catch (e) {
// console.log(e.message + " in " + xhr.responseText);
return;
}

fileUploadCallback(file, data);
}
}
};

xhr.open('POST', url, true);
xhr.send(data);
}

function fileUploadCallback(file, data) {
if (data.error) {
// responseText
document.getElementById('customer_photo_callback') .innerHTML = data.error;
} else if (data.success) {
// responseText
document.getElementById('customer_photo_callback') .innerHTML = data.success;

// replacePhoto
var img = document.createElement('img');
img.id = 'customer_photo_img';
img.className = 'img-fluid';
img.src = window.URL.createObjectURL(file);

document.getElementById('customer_photo_img').repl aceWith(img);
}
}

P.S. Надеюсь, все здесь понятно. Старался писать аккуратно)

laimas
20.01.2020, 16:04
{% for mime in mime_allowed_array %}
        '{{ mime }}',
      {% endfor %}


как разу и должно быть вот здесь accept="{{ mime_allowed }}", и проверятся рег. выражением. А

var url  = '{{ url }}',

вот тут <form action="{{ url }}".

Вообще, старайтесь, без большой на то надобности, не трогать JS вставками сервера.

sdareios
20.01.2020, 16:51
как разу и должно быть вот здесь accept="{{ mime_allowed }}", и проверятся рег. выражением.

Оно то да, вот только пользователь все равно сможет загрузить файл другого типа выбрав его в окне выбора файла

https://i.imgur.com/4Ob4WSy.png

Поэтому я и добавил проверку по типу файла

laimas
20.01.2020, 17:31
вот только пользователь все равно сможет загрузить файл другого типа выбрав его в окне выбора файла

Это как? Значения accept не все браузеры в общем то слушаются так как вам хочется, но тип файла file.type будет определен (есть небольшие косяки с мелкософтовскими документами, как выяснилось, но вам это боком). А указанные типы в accept как image/jpeg,image/png... легко превратить в шаблон рег. выражения и создав по нему RegExp. Проверка file.type по этому шаблону никак не даст загрузить с диска не тот тип.

Другой тип можно загрузить только левым запросом, и в случае если сервер не проверяет данные извне. Поэтому проверка типа совсем не требует отдельного кода аж с 23 по 37 строки.


Вы мусортите в js коде вставками php, если потребуется подключение js, то это уже работать не будет.

PS. Значение accept можно превратить и в массив, искать в нем вхождение file.type (indexOf(), includes()).