Закрытие модальных окон нажатием снаружи
Требование и реализация — 2026-10-28
Пользователь попросил закрывать модальное окно нажатием вне его границ. Новый независимый модуль src/runtime/modal-backdrop.mjs экспортирует createModalBackdrop, bindModalBackdropEvents и unbindModalBackdropEvents. Зависимостей игрового контекста нет (requiredPorts=[]). Интегратор подключает фабрику через registerFeature и один раз вызывает bindModalBackdropEvents() при привязке интерфейса.
Обработчики установлены через addEventListener в фазе capture на документе. Это охватывает все 23 статических <dialog> в src/index.html, а также позднее созданные projectEditorDialog и unitDesignerDialog. Общие обработчики onclick не заменяются. Меню производства role=dialog внутри города является вложенным списком; оно уже обрабатывает штатную отмену города первым, поэтому отдельной имитации модального backdrop для него нет.
Закрытие выполняется только после полного основного жеста pointerdown → pointerup → click: начало, конец и нажатие находятся строго снаружи текущего getBoundingClientRect, а целевой элемент — сам native dialog, на который браузер перенаправляет события его backdrop. Рамка, padding, внутреннее содержимое, дочерний элемент с выступающими границами, правая/средняя кнопки и клавиатурный click не считаются наружным нажатием. Перетаскивание из содержимого наружу не закрывает окно. Движение более 8 CSS px, прокрутка, pointercancel, потеря фокуса или закрытие окна сбрасывают незавершённый жест. Небольшое естественное смещение касания допустимо.
Перед close() отправляется отменяемое небулькающее событие cancel, соответствующее пути Escape. Обработчики черновиков расформирования, модернизации, дипломатической миссии, нарушения эмбарго и генерации новой карты сохраняют свою очистку; редактор завершает мазок, отменяет worker и сохраняет проект. Обработчик не отправляет игровые команды, не нажимает кнопки действий и не меняет pendingDecisions. Закрытие governor без применения сохраняет настройки партии; открытие заново берёт их из игрового состояния. Вложенные native dialog закрываются по одному, без переноса клика на карту.
Обязательные решения и ограничение
Существующие preventDefault() продолжают действовать: захват/культурное присоединение города, входящие мир и торговля всегда запрещают отмену; выбор правительства, науки/бесплатной технологии и производства запрещает отмену при соответствующем обязательном решении. У production сначала может закрыться вложенный список, оставив город открытым. Редактор типов юнитов также запрещает отмену во время своей операции working.
Наружное нажатие на эти обязательные экраны не выбирает ответ и не скрывает требуемое решение. Это существующее ограничение самой отмены, не новая проверка ядра. Сейчас у захвата/мира/входящей торговли нет отдельного пути повторно открыть временно скрытое решение; принудительное закрытие могло бы оставить игрока без доступного продолжения. Изменение такого поведения требует отдельного согласованного интерфейса возврата к сохранённому решению. Правила партии в этой задаче не ослаблены.
Проверка
tests/modal-backdrop.test.mjs непосредственно импортирует исходный модуль и проверяет отмену/очистку до close, запрет отмены, геометрию, drag, scroll, touch, pointercancel, разные указатели/кнопки, повторную привязку/освобождение обработчиков и минимальный DOM без defaultView.
tests/browser-modal-backdrop.cjs --isolated использует отдельную HTTP-страницу с исходным модулем и настоящими native dialog Chromium: padding, drag наружу, прокрутка, ПКМ, наружный click/cancel, preventDefault, вложенные окна, отсутствие click-through и мобильное касание. Shared dist при этом не читается и не изменяется. Отчёт: research/original-game/data/browser-modal-backdrop-isolated-verification.json.
Полный драйвер без --isolated дополнительно проверяет интегрированную сборку: параметры, новую партию, обычную науку с неприменённым бюджетом, D/очистку подтверждения, губернатора, последовательную отмену списка производства/города, обычные переговоры, существующие cancel-guards захвата/мира/входящей торговли, динамические редакторы карты/типов юнитов и параметры при ширине 390 px. Guard-проверки открывают существующие DOM-окна напрямую, без поддельных игровых решений; сохранность реальных обязательных решений проверяется также прежними тематическими сценариями. Отчёт полного прогона: research/original-game/data/browser-modal-backdrop-verification.json.
Все запуски выполняются через python3 scripts/run-limited.py -- … (35% CPU). Сборку, полный браузерный прогон и публикацию общей рабочей копии выполняет интегратор. На момент передачи интеграции полный прогон и публикация ещё не выполнены.
Передача интегратору в 04:57 МСК: 11/11 модульных проверок прошли; изолированный Chromium прошёл все пять групп проверок, включая реальное мобильное касание; ошибок страницы и запросов нет. Desktop и mobile используют отдельные последовательные процессы Chromium из-за известного ограничения --single-process при смене browser context. В минимальном DOM допустимо отсутствие defaultView. Исходник модуля заморожен для общей сборки.
Публичная интеграцияv0.10.0
Опубликовано28.10.2026 в05:13 МСК, кодf1d04cdd4cd1b1be. Сценарий реально выполнен вChromium локально и на основном HTTPS-сайте. Текущий отчёт. Общая сверка146 файлов кода/данных/ресурсов не нашла расхождений; независимые служебные страницы сохранены. Полный Windows-оригинал этими проверками не объявлен воспроизведённым.