Files
obsidian-vault/personal/plans/ohotnichy-bilety-interaktiv.md
T

6.6 KiB
Raw Blame History

Интерактивные билеты охотника (a1-tir.ru/bilety)

Проект: скачать страницу билетов для экзамена на гражданское оружие и превратить в интерактивный тренажёр.

Возможности: номер правильного ответа скрыт · ответы кликабельны · выбранный неправильный → красный, правильный → зелёный.

Файлы (исходники в ~/Downloads/):

  • bilety.html — скачанная + расширенная страница (инъекция CSS/JS + метаданные)
  • bilety.js — enhancer: парсер вопросов + click-логика
  • bilety.css — стили подсветки (зелёный/красный)
  • a1-tir_bilety_raw.html — оригинальная скачанная копия (667 КБ)

Статус

  • Страница скачана и переработана в интерактив.
  • ⏸️ Доставка в Eagle Dashboard Pages не завершена — упирается в права: /Library/WebServer/Documents/ root-owned, sudo cp требует пароль из неинтерактивного шелла. Нужно либо получить sudo-пароль от Alex, либо он запустит вручную:
    sudo cp ~/Downloads/bilety.html ~/Downloads/bilety.js ~/Downloads/bilety.css /Library/WebServer/Documents/
    
    После копирования страница появится в http://localhost:8880/?tab=pages под именем bilety (title/purpose/contains уже заполнены). Рестарт дашборда не нужен.

Источник и структура (Tilda)

Страница — Tilda-лендинг, весь исходный HTML на одной строке (a1-tir_bilety_raw.html, строка 228 содержит контент).

Экзамен разложен по 4 блокам data-record-type="106" (Tilda text-блок div.field-text.t-text):

  • rec465410787 — «Правовая подготовка», вопросы 1.1–1.49
  • rec1120437831 — без заголовка (продолжение правовой), 1.50–1.93
  • rec1120438216 — «Огневая подготовка», 2.1–2.41
  • rec465410788 — без заголовка (правила охоты), 58–103 · вопросы из нескольких <strong>
  • Итого ~180 вопросов.

Структура одного вопроса в DOM (проверено по сырым данным)

Каждый блок — один большой div; внутри childNodes:

  • <br/> — разделители (шум)
  • <strong>Вопрос</strong> — текст вопроса; может занимать несколько подряд <strong> (напр. вопрос 58); внутри возможен вложенный <a> (consultantplus)
  • шапка раздела — <p><strong>Заголовок</strong></p> (strong вложен в p → не ловится как вопрос)
  • текстовые узлы ответов: "1. Текст", "2. ...", "3. ..." (бывают ведущие пробелы)
  • <em>N</em>номер правильного ответа (чистое число)
  • примечание — <em><u>Примечание</u>: …</em> (НЕ номер, сохранить)
  • шум: <strong>&nbsp;</strong>, <em>&nbsp;</em>, пустой <em> с <strong data-redactor-tag>

Контентных <img>/<svg> в блоках вопросов нет — только текст.


Решение — чисто клиентский JS (без библиотек/backend)

bilety.js на DOMContentLoaded обрабатывает каждый [data-record-type="106"] .t-text:

Парсер parseQuiz (конечный автомат по childNodes):

  • <strong> с непустым текстом, не &nbsp;: если у текущего вопроса ещё нет ответов и фаза questionмержим текст (многострочный вопрос); иначе → новый вопрос.
  • текстовый узел, матчащий ^\d+[\.\s:] и при отсутствии заданного correct → ответ {n, text} (фаза → answers); иначе — продолжение последнего ответа.
  • <em> с чистым числом → question.correct = N (только в фазе answers, чтобы не спутать с «Примечание»); с текстом → question.note = innerHTML (сохранить); пустой/&nbsp; → шум.
  • <p> при cur === null и нет вопросов → headerHTML (заголовок раздела сохраняем).
  • фильтр: оставляем только вопросы с correct !== null.

Рендер renderQuestion: карточка .whale-q.whale-q-text (вопрос, textContent, жирный) + .whale-answers с кнопками .whale-a (data-n = номер ответа) + опционально .whale-note.

Click-логика: первый клик блокируется (data-locked). Если n === correct → класс correct (зелёный); иначе класс wrong (красный) и правильный ответ получает correct (чтобы показать верный). Управляется data-correct на карточке.

Инъекция в страницу:

  • <link rel="stylesheet" href="bilety.css"> перед </head>
  • <script src="bilety.js" charset="utf-8"></script> перед </body>
  • мета для дашборда в <head>: eagle-test-purpose, eagle-test-contains.

Дизайн .whale-a: карточки-кнопки (flex column), #f5f5f5, hover #ececec; .correct=#d4edda/#28a745, .wrong=#f8d7da/#dc3545 (с !important).


Pitfall: локальное открытие file://

Страница Tilda использует sessionStorage для анимации появления .t-records — при открытии локально это работает. Просто открыть bilety.html двойным кликом достаточно для проверки функционала.


Связанное

  • Доставка в дашборд — механика Pages: personal/projects/personal-os/eagle-dashboard.md.