BUILD153 — исправление выпадающих меню в настройках
This commit is contained in:
385658
agent/agent.log.1
385658
agent/agent.log.1
File diff suppressed because it is too large
Load Diff
2
app.py
2
app.py
@@ -30,7 +30,7 @@ from ui_builder import install_ui_builder
|
||||
from khl_site.khl_data_center import APP as khl_site_app
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
BUILD_VERSION = "2026.09.18.10"
|
||||
BUILD_VERSION = "2026.09.18.11"
|
||||
# compatibility: BUILD_VERSION = "2026.08.26.1"
|
||||
# compatibility: BUILD_VERSION = "2026.08.25.1"
|
||||
# compatibility: BUILD_VERSION = "2026.08.24.15"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// BUILD153: settings freeze all data-driven DOM rendering and keep dropdown popovers open.
|
||||
// BUILD152: all browser-side hockey data polling pauses while operator settings are open.
|
||||
// BUILD151: Schedule ONLINE is a toggle; one-second live polling uses isolated schedule_live.
|
||||
// BUILD150: Schedule ONLINE button refreshes score/status from language-specific per-game JSON.
|
||||
@@ -2028,7 +2029,19 @@
|
||||
closeControlPopover();
|
||||
}, true);
|
||||
document.addEventListener("keydown", (event) => { if (event.key === "Escape" && activeControlPopover) closeControlPopover(); }, true);
|
||||
window.addEventListener("resize", closeControlPopover);
|
||||
window.addEventListener("resize", () => {
|
||||
if (!activeControlPopover) return;
|
||||
// BUILD153: opening a styled dropdown inside full-screen settings can
|
||||
// change the document scrollbar and produce a tiny resize event. The
|
||||
// old handler immediately closed the dropdown, which made settings
|
||||
// selects unusable. While settings are open, keep the popover alive
|
||||
// and only recalculate its position.
|
||||
if (hockeySettingsDataRefreshPaused() && activeControlPopover.anchor?.isConnected) {
|
||||
positionControlPopover(activeControlPopover.anchor, activeControlPopover.popup);
|
||||
return;
|
||||
}
|
||||
closeControlPopover();
|
||||
});
|
||||
window.addEventListener("scroll", () => activeControlPopover && positionControlPopover(activeControlPopover.anchor, activeControlPopover.popup), true);
|
||||
}
|
||||
|
||||
@@ -2684,6 +2697,12 @@ function startCustomTooltips() {
|
||||
}
|
||||
|
||||
async function loadData(showToast = false) {
|
||||
// BUILD153: settings are a hard UI/data pause. Do not start a generic
|
||||
// data reload while an operator is choosing values in a settings modal.
|
||||
if (hockeySettingsDataRefreshPaused()) {
|
||||
state.hockeySettingsReloadPending = true;
|
||||
return clone(state.data);
|
||||
}
|
||||
try {
|
||||
state.data = await api(`/data/${encodeURIComponent(state.config.data_source)}`);
|
||||
state.dataPaths = flattenPaths(state.data);
|
||||
@@ -5733,11 +5752,21 @@ function mergeExternalData(target, patch) {
|
||||
function applyExternalDataPatch(patch, { render = true } = {}) {
|
||||
state.data = mergeExternalData(state.data, patch || {});
|
||||
state.dataPaths = flattenPaths(state.data);
|
||||
if (el.rawData) el.rawData.textContent = JSON.stringify(state.data, null, 2);
|
||||
renderDataPaths();
|
||||
if (render) {
|
||||
renderCanvas();
|
||||
renderRuntime();
|
||||
|
||||
// BUILD153: data may still arrive from an already-started request while the
|
||||
// operator is inside settings. Keep the newest values in memory, but do
|
||||
// not mutate any DOM until settings close. Rebuilding runtime/editor DOM
|
||||
// can otherwise destroy focus and close styled select popovers.
|
||||
const settingsPaused = hockeySettingsDataRefreshPaused();
|
||||
if (settingsPaused) {
|
||||
if (render) state.hockeySettingsRenderPending = true;
|
||||
} else {
|
||||
if (el.rawData) el.rawData.textContent = JSON.stringify(state.data, null, 2);
|
||||
renderDataPaths();
|
||||
if (render) {
|
||||
renderCanvas();
|
||||
renderRuntime();
|
||||
}
|
||||
}
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("ui-builder:data-patched", { detail: clone(patch || {}) })
|
||||
@@ -13830,6 +13859,12 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
|
||||
|
||||
function renderRuntime() {
|
||||
if (!el.runtimeStage || (!state.preview && boot.mode !== "runtime")) return;
|
||||
// BUILD153: never rebuild the runtime DOM underneath a settings modal.
|
||||
// Incoming data is retained and rendered once after the modal closes.
|
||||
if (hockeySettingsDataRefreshPaused()) {
|
||||
state.hockeySettingsRenderPending = true;
|
||||
return;
|
||||
}
|
||||
const activeShootoutSearch = document.activeElement?.matches?.("[data-shootout-search]")
|
||||
? {
|
||||
side: document.activeElement.dataset.shootoutSearch,
|
||||
@@ -15419,7 +15454,25 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
|
||||
const paused = Boolean(event?.detail?.paused);
|
||||
if (paused) {
|
||||
stopQuickPanelOverlayPolling();
|
||||
} else if (boot.mode === "runtime") {
|
||||
return;
|
||||
}
|
||||
|
||||
// BUILD153: flush all DOM work exactly once after settings disappear.
|
||||
// This preserves focus/popovers for the whole editing session.
|
||||
if (state.hockeySettingsRenderPending) {
|
||||
state.hockeySettingsRenderPending = false;
|
||||
if (el.rawData) el.rawData.textContent = JSON.stringify(state.data, null, 2);
|
||||
renderDataPaths();
|
||||
renderCanvas();
|
||||
renderRuntime();
|
||||
}
|
||||
if (state.hockeySettingsReloadPending) {
|
||||
state.hockeySettingsReloadPending = false;
|
||||
loadData(false).catch((error) => console.warn("[Hockey] deferred data reload failed:", error));
|
||||
}
|
||||
|
||||
if (boot.mode === "runtime") {
|
||||
state.hockeySettingsGameRefreshPending = false;
|
||||
startQuickPanelOverlayPolling();
|
||||
refreshHockeyRuntimeAfterSettings();
|
||||
}
|
||||
@@ -15429,6 +15482,14 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
|
||||
refreshHockeyRuntimeAfterSettings();
|
||||
});
|
||||
window.addEventListener("hockey:game-selected", (event) => {
|
||||
// BUILD153: an in-flight Stat2TV request can finish after settings have
|
||||
// already opened. Ignore its runtime side effects until the settings
|
||||
// session ends; the fresh selected-game state will be reconciled on
|
||||
// resume.
|
||||
if (hockeySettingsDataRefreshPaused()) {
|
||||
state.hockeySettingsGameRefreshPending = true;
|
||||
return;
|
||||
}
|
||||
const gameId = String(event?.detail?.game?.external_id || event?.detail?.game?.id || "").trim();
|
||||
if (!gameId) return;
|
||||
// Live Stat2TV polling emits this event every second. Timer state must
|
||||
|
||||
Reference in New Issue
Block a user