# CAPS Enhancer — Chrome Extension Chrome-расширение (Manifest V3) для улучшения интерфейса CAPS/UTP: навигационные кнопки, автологин, замена логотипа, редирект noVNC. ## Архитектура ``` caps_enhancer-1/ ├── manifest.json # MV3, update URL, content scripts on ├── js/ │ ├── background.js # Service worker: проверка обновлений (chrome.alarms) │ ├── content.js # Инициализация: роутинг по типу страницы │ ├── popup.js # Popup: быстрые переключатели │ ├── options.js # Страница настроек: загрузка/сохранение конфига │ └── strings.js # Все строки UI (русский) ├── modules/ │ ├── core.js # CONFIG, утилиты, loadConfig(), updateConfig() │ ├── mnemoschema.js # Кнопки «Мнемосхема» и «Лещ» на главной странице │ ├── video-window.js # Кнопка с IP или «Лещ» в заголовке видео-окна │ ├── novnc-redirect.js # Редирект или кнопка на noVNC-странице │ ├── auto-login.js # Автологин с профилями и правилами подсетей │ └── close-handler.js # ESC закрывает видео-окна и карточки ├── options.html / popup.html ├── css/options.css / popup.css └── server/ # Деплой: .crx, nginx.conf, .reg, update.xml ``` ## Конфигурация (core.js CONFIG) Хранится в `chrome.storage.sync` под ключом `config`. Структура: ```javascript { debug: { enabled, modules: { core, video, mnemo, close, content, novnc, autologin } }, ports: { video: '5000', scheme: '8080' }, videoWindow: { ipButtonMode: 'button' // 'button' — кнопка «🔗 IP:порт», 'clickable-title' — кнопка «Лещ» }, novnc: { mode: 'button'|'redirect', redirectDelay: 500 }, mnemo: { mode: 'host-port'|'host-scheme', skipOnDomain, addVideoButton, addSchemeButton }, autologin: { enabled, profilePage1, profilePage2, subnetRules, profiles }, disabledSites: [], replaceLogo: true, uiVisible: true } ``` При добавлении нового поля конфига: обновить `CONFIG` в `core.js`, `updateConfig()` в `core.js`, `DEFAULT_CONFIG` в `options.js`, добавить элемент в `options.html`, загрузку/сохранение в `options.js`, строки в `strings.js`. ## Типы страниц (core.checkPageType) | Тип | Признаки | |-----|---------| | `isMainPage` | логотип CleverPark + noscript-маркер | | `isVideoPage` | noscript-маркер, нет логотипа | | `isNoVNCPage` | noscript "You need to enable JavaScript" + один из признаков ниже | **Признаки noVNC (второй критерий):** - `div[class*="app_AppWindow__"]` — старый тип страницы (CSS-модульный класс React-компонента) - `document.title` содержит `"Платёжный терминал"` — новый тип страницы (присутствует в HTML сразу при загрузке, до инициализации React) **Важно:** не использовать DOM-элементы, которые появляются после загрузки React (например `div#app.App`, `div.multi-find-menu-container`) — они не существуют в момент первой проверки, что приводит к неверному определению типа страницы. ## Модуль video-window.js Добавляет ссылку на IP устройства в заголовок видео-окна. Два режима (настройка `videoWindow.ipButtonMode`): - **`button`** (по умолчанию): кнопка `🔗 IP:5000` после `

` в заголовке. Tooltip не задан. - **`clickable-title`**: кнопка **«Лещ»** с тем же стилем и тем же переходом. При наведении — нативный tooltip с полным URL (`button.title`). Оба режима используют `core.createStyledButton()` — одинаковая стилизация. IP извлекается из src видео-элемента `img[src*=":8888/screen"][src*="/getVideo/"]` через regex `/\/getVideo\/http:\/\/([^\/:?#]+)(?::(\d+))?/i`. ## Модуль novnc-redirect.js Два режима (`novnc.mode`): - **`redirect`**: автоматический переход на `http://:`. Редирект происходит если текущий порт **не равен** целевому (не жёсткая привязка к порту 80). - **`button`**: фиксированная кнопка в правом верхнем углу. После добавления следит за удалением через `MutationObserver` (15 сек) и добавляет кнопку снова — защита от React-рендеринга, который может очищать body. Важно: у кнопки задан `dataset.capsUiDisplay = 'inline-block'`, чтобы `applyVisibility` не сбрасывала её display в `''`. ## Видимость UI (Shift+F1) - `data-caps-ui="true"` — элементы расширения (скрываются при `uiVisible=false`) - `data-caps-ui-display` — исходное значение `display`, восстанавливается при `uiVisible=true`; **обязательно задавать** при создании кнопок с нестандартным display - `data-caps-original="true"` — оригинальные элементы (скрываются при `uiVisible=true`) - Логотип меняет `src` вместо `display` ## Паттерны - Каждый модуль — IIFE, расширяет `window.VideoIPRedirect` - Общие утилиты: `core.createStyledButton()`, `core.debugLog()`, `core.retryWithBackoff()` - Конфиг обновляется через `chrome.runtime.onMessage` → `CONFIG_UPDATED` - Строки: все тексты UI только в `js/strings.js`, доступ через `getStr('options.key')` ## Деплой См. [DEPLOY.md](DEPLOY.md). Кратко: упаковать `.crx` → загрузить на сервер → обновить `update.xml` с новой версией → версия в `manifest.json`.