Форма завантаження файлів: 5 виправлень без редизайну
Запит із вкладеннями, анкета кандидата, заявка на гарантію з фото з телефона: людина обирає файл, натискає «Надіслати» й отримує відповідь «файл завеликий». Пробує вдруге зі скриншотом, поле очищається, вкладка закривається. Форма завантаження файлів перевіряється в ці дві хвилини, і лагодиться вона дешевше за все інше у формі.
Код: Oat-Upload, ліцензія MIT.
Oat Upload це невелике розширення бібліотеки Oat UI. Воно обгортає нативний <input type="file"> і додає зону перетягування, прев’ю, видалення, перевірку й прогрес. Залежностей у рантаймі немає, збирання на сервері немає, форма надсилається навіть тоді, коли скрипт не завантажився.
Де форма завантаження файлів втрачає людину
П’ять провалів повторюються з проєкту в проєкт, і саме завантаження серед них не винне.
Людина не бачить, що прикріпила. Камера телефона називає файли IMG_4821. Без прев’ю не той документ їде в підтримку, і через день його правлять руками.
Про ліміт повідомляють після спроби. «До 5 МБ» дрібним сірим шрифтом під полем це підказка, а підказка не перевірка. Компонент порівнює розмір до того, як запит пішов із браузера, тому відмова коштує секунди, а не кола до сервера й назад.
Помилка стирає вибір. Відхилений файл із очищенням поля змушує обирати все заново. Тут відхилений файл випадає зі списку, решта лишається.
На повільному зв’язку не відбувається нічого. Без індикатора сорок секунд завантаження виглядають застиглою сторінкою, і людина перезавантажує вкладку. Перезавантаження скасовує завантаження.
Видалити файл не можна. Прикріпили не той договір, і єдиний вихід це перезавантаження сторінки, яке забирає решту форми.
Поле лишається джерелом істини
<ot-upload> не замінює поле, а росте навколо нього:
<ot-upload max-size="5242880" max-files="5">
<input type="file" name="attachments" multiple accept="image/*,.pdf">
</ot-upload>
Це вся інтеграція. Форма надсилає attachments так само, як раніше, сервер тримає свою перевірку, а розробник у шаблоні бачить поле файла, а не фреймворк.
Список файлів на сторінці й список у браузері синхронізуються через DataTransfer там, де браузер це вміє. Прев’ю й надсилання не розходяться.
Перевірка, яка говорить до запиту
Перевірка читає спершу нативний input, потім атрибути <ot-upload>, тому accept, multiple і disabled поводяться так, як визначив браузер. max-size і max-files закривають два ліміти, яких браузер сам не тримає.
Відхилений файл викликає ot-upload-error із причиною type, size, count або disabled і повідомленням для людини. Із цієї причини форма збирає «PDF важить 12 МБ, ліміт 5 МБ» замість «неприпустимий файл».
Прогрес і видалення без спінера
Прогрес це нативний <progress>, який оновлює setProgress(). Код завантаження передає число від 0 до 100, і смуга показує реальний стан, а не анімацію. Виклик із null або resetProgress() ховає її.
Видалення це кнопка в рядку, а remove() приймає індекс, файл або ідентифікатор елемента. Поле оновлюється разом зі списком, тому на сервер іде те, що людина бачить.
Для команд зі своєю розміткою частини названі явно: data-upload-dropzone, data-upload-list, data-upload-error, data-upload-progress, data-upload-status. Компонент заповнює те, що дали, і збирає решту, якщо не дали нічого.
Де це не підходить
Завантаження відео на 2 ГБ, докачування після обриву мережі й передавання шматками в S3 це інша задача, і компонент навколо нативного поля її не вирішує. Десять тисяч файлів в одному запиті теж інша задача, і відповідь там це черга на сервері та інший інтерфейс.
Для форми з п’ятьма вкладеннями рамка правильна, і сторінка лишається сторінкою.
Скільки це коштує
Одна таблиця стилів, один скрипт, MIT, без залежностей. Для проєкту по 30–50 $ за годину це ранок роботи, і він забирає клас звернень у підтримку, які ніхто не виставляє в рахунок: звернення про файли.
Поруч: веб-розробка про те, як рахується обсяг форми, і сортування таблиці HTML про той самий довід на користь нативної розмітки замість її заміни.
