henry_flower: A melancholy wolf (Default)
henry_flower ([personal profile] henry_flower) wrote2025-01-27 04:02 pm

Шльопання форм статичних

Я уявляю це собі так: ув старі добрі часи для швидкого анкетування можна було пнути хропучого сисадміна, який би написав html форму та елементарний сервер (на його улюбленій мові), що з'їдав би post ріквеста і складав результат ув якійсь директорії. Після чого сисадмін вертався до своєї комірки сопти далі, а ікзéк'ютів починав спамити колег адресою 172.20.1.15/surveys/job-satisfaction.html.

Тобто, як то воно була насправді, я гадки не маю. 10+ років тому, коли потрібні були анкети, я робив їх ув гоогл хформах і читав результати ув гоогл шітс. Зараз, звичайно, варіянти коливаються від $0/mo (вся дейта вільно продається кому завгодно) чи $199/mo за "1 active project" з "10K сабмітів" (вся дейта дістається русскім з рансомware угрупувань) до селф-хостинґу з хропучим дівопсом фултайм ув комплекті (вся дейта губиться, коли дівопс звільняється).

Чомусь останній варіянт з селф-хостинґом завжди виглядає як конкурс мошин Руба Голдберґа, хоча такий "проєкта" має бути на рівні можливостей будь-якого школяра. 2 файли ув найпростішому вигляді: form.html та server.js. Ні?

Орхітектура

server.js містить статичного http сервера. На GET /simplest шукає public_html/simplest/index.html та виставляє сесію ув cookie. Автор анкети пише simplest/index.html руками ув текстовому редакторі. Найпростіша анкета:

<form method="post">
Name? <input name="name" type="text" required>
<input type="submit">
</form>

Це є класичний postback, тобто POST ріквест форма відсилає на той самий pathname за яким було GET сторінки. Ув даному випадку це дозволяє з URL викопирсати ім'я анкети. Ув директорії public_html/simplest/ можуть бути будь-які файли, які треба для рендеренгу екстравагантної форми: світлини, відео, джаваскрипт і т.ін.

Число анкет обмежується лише лімітами файлової системи. Додавати анкети можна ув ріалтайм, перезапускати сервера є непотрібно.

Якщо POST був без помилок, application/x-www-form-urlencoded конвертується ув json і ✍️ ув окремій директорії.

Сервер

Бовзерна валідація хформ працює всюди > 10 років (окрім ондроїдного файрфоксу, тому що кожного року треба усім світом збирати мульйони долярів на зарплату CEO і часу на все не вистачає). Перевірку пейлоаду з post ріквеста можна робити загальнопролетарським json schema, який можна генерувати зі статичного form.html на льоту.

Є купа мотлоху який генерує html з json schema, але не навпаки: я знайшов нічого, що оналізує якийсь <input type="text" minlength="2" maxlength="50"> і випльовує скіму, але з ноудівським cheerio можна написати свій генератор за кілька годин. Форми не можуть бути вкладеними одна в одну, тому складність генератора буде рости лише з кількістю віджетів.

Наприклад, з

<input type="radio" name="os" value="linux" required> Linux
<input type="radio" name="os" value="macos"> macOS

генерується

{
  "type": "object",
  "properties": {
    "os": { "enum": [ "linux", "macos" ] }
    ...
  },
  "required": [ "os", ... ]
}

Ванільний фронтенд не був ви фронтендом, якщо би всі стандартні віджети працювали однаково. Якщо для множини radio кнопок підтримується валідація "required", то для множини чекбоксів немає ані "required", ані перевірки мінімальної кількості увімкнених прапорців (навіщо bother, як то кажуть ув Калґарі). Я виставляв data-required="true" та data-min="N" на парентному div.

Коли анкетування є номінально анонімним, auth можна пропустити і просто встановлювати cookie щоб користувач, який згадає шо він цейво, як його, забувсь, шо він хотів написати, міг якийсь час свою анкету редагувати. З

Set-Cookie: sid=2025/01/26/a8b92708-f1dc-4870-abee-907a50a10800; Max-Age=31536000; Path=/js101/
Set-Cookie: signature=3c564fa3f3b534b85fdab82deb575c2ab2af48b7; Max-Age=31536000; Path=/js101/

результати записуються ув db/js101/2025/01/26/XXXX/results.json, які ~легко трансформуються ув csv. Без couchbase, mongo чи mariadb. Жах.

(Здогадайтеся для чого потрібна "signature".)

Анкета стає автоматично 403, якщо хфайл з формою має mtime < зараз. Тобто, валідна анкета має обов'язково мати дату модифікації ув майбутньому, що є трохи незвично, але звільняє від необхідності тримати якогось конфігураційного хфайла.

Якщо над директорією з results.json запустити іншого статичного http сервера, то анкета, сімлінка якої пишеться поряд з results.json, може читати results.json і заповнювати ту саму форму результатами тяжкої роботи користувача.

Віджети

Стандартних має вистачити, але як тільки закортить мінімального дайґрешона, треба готуватися до ведмежих кутів бовзерних ойпіай.

Наприклад, я хотів вертикального слайдера з підписом рисок:

spartaforms-slider

Кастомний уйоб-компонента якого виглядає ось так:

<spartaforms-slider name="knowledge" min="0" max="4" value="0" required>
  <span data-value="4">I'm Douglas Crockford 🧙‍♂️</span>
  <span data-value="3"><i>Très bien</i></span>
  <span data-value="2">Can code with an LLM</span>
  <span data-value="1">Syntax only</span>
  <span data-value="0">Nil</span>
</spartaforms-slider>

Всередині то є звичайний <input type=range>, розвернутий на -90°; зі <span> генерується datalist, з якими слайдер стає схожим на словацького термометра. Можна було би писати datalist самотужки, та його відмовляється рендерити ie6 еплівський вебкіт.

Але <input type=range> сидить ув shadow dom уйоб-компонента, тому форма на сторінці його не бачить! Будь-які зміні ув атрибутах <spartaforms-slider> треба переносити до <input> (і навпаки) самому. Щоб дружити з формами існує спеціяльний ойпіай, який став з ~2023 таким популярним, що про нього користоґо є ~0, окрім скупих речень на whatwg.org.

Якоїсь підтримки ув збереженні інпуту, набраного користувачем ув елементах форми, від бовзера чекати є марно. Доводиться перехоплювати submit івента щоб зберігати їх десь (хоча би ув localStorage) і самотужки відновлювати, коли користувач вирішує ту форму відредагувати. Все це вміють робити різноманітні фреймвоки багато років, а ванільний джаваскрипта полишає нічого, окрім дратування через витрачання часу на цю ґілімат'ю.

Ін конклуз'йоне

Загалом, екперимента визнано невдалим. Що здавалося елементарним 1+N файловим рішенням (де N--кількість анкет), ув реальності з 3ма анкетами виросло на

$ tree --gitignore -I test --dirsfirst
.
├── public_html
│   ├── eng210
│   │   ├── form.css -> ../form.css
│   │   ├── form.js -> ../form.js
│   │   ├── index.html
│   │   └── widgets.js -> ../widgets.js
│   ├── js101
│   │   ├── form.css -> ../form.css
│   │   ├── form.js -> ../form.js
│   │   ├── index.html
│   │   └── widgets.js -> ../widgets.js
│   ├── simplest
│   │   └── index.html
│   ├── 60438.svg
│   ├── favicon.ico
│   ├── form.css
│   ├── form.js
│   ├── index.html
│   ├── posted.html
│   └── widgets.js
├── Makefile
├── mkschema.js
├── package.json
└── server.js

з малонадихаючим розміром джаваскрипта:

$ wc -lc *js public_html/*js
  196  5260 mkschema.js
  249  8322 server.js
  136  4193 public_html/form.js
  101  2906 public_html/widgets.js
  682 20681 total

Приклад анкети є ось тут. Чи має сенс цей ковгосп викладати на ґітгаб, я не знаю.


Post a comment in response:

If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting