удаления не должны закрываться, пока обновляются данные

This commit is contained in:
2026-09-24 15:23:41 +03:00
parent cf751a4d49
commit 7c85d83627

View File

@@ -1,5 +1,6 @@
// BUILD159_COUNTDOWN_TRANSITION_FIXES
// BUILD155: all hockey game/penalty timers use native vMix Countdown; no per-second SetText mirroring.
// BUILD161: live data refresh cannot rebuild an open infraction picker on the main Game tab.
// BUILD160: strict settings freeze; background vMix inventory refresh never rebuilds an open settings form.
// 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.
@@ -161,6 +162,7 @@
timerEngineStarted: false,
hockeyPenaltyBoards: {},
hockeyPenaltyBoardNodes: new Map(),
hockeyInfractionMenuRenderPending: false,
hockeyGameControl: {},
hockeyGameControlLoading: new Set(),
hockeyTimerGameId: "",
@@ -7432,6 +7434,7 @@ function openTimerQuickEditor(focusActionId = "") {
history: [],
historyOpen: false,
search: { home: "", away: "", infractions: "" },
infractionDropdownOpen: false,
lastPersistAt: 0
};
@@ -8074,6 +8077,19 @@ function openTimerQuickEditor(focusActionId = "") {
function refreshHockeyBoardNodes(component) {
const nodes = state.hockeyPenaltyBoardNodes.get(component.action_id) || [];
const board = ensureHockeyBoardState(component);
const menuOpen = Boolean(board?.infractionDropdownOpen)
|| [...nodes].some((node) => Boolean(node?.querySelector?.(".hpd-infraction-dropdown[open]")));
// BUILD161: do not rebuild the penalty dashboard under an open infraction menu.
// Live match polling and penalty-state refreshes can still update state/tickers,
// but the operator's dropdown/search stays physically intact until it is closed.
if (menuOpen) {
state.hockeyInfractionMenuRenderPending = true;
updateHockeyBoardTickerNodes(component);
return;
}
nodes.forEach((node) => renderHockeyPenaltyDashboard(node, component, true));
}
@@ -8362,7 +8378,15 @@ function hockeyInfractionRow(component, infraction, runtime) {
`;
if (runtime) {
row.addEventListener("click", () => chooseHockeyInfraction(component, infraction));
row.addEventListener("click", () => {
// A deliberate choice may close the menu; only background refreshes are frozen.
const dropdown = row.closest(".hpd-infraction-dropdown");
if (dropdown) {
board.infractionDropdownOpen = false;
dropdown.open = false;
}
chooseHockeyInfraction(component, infraction);
});
row.addEventListener("dragstart", (dragEvent) => {
setHockeyDragData(dragEvent, "infraction", infraction);
row.classList.add("is-dragging");
@@ -8406,6 +8430,7 @@ function hockeyInfractionDropdown(component, runtime) {
const board = ensureHockeyBoardState(component);
const details = document.createElement("details");
details.className = "hpd-infraction-dropdown";
details.open = Boolean(board.infractionDropdownOpen);
const summary = document.createElement("summary");
summary.innerHTML = `
@@ -8444,7 +8469,19 @@ function hockeyInfractionDropdown(component, runtime) {
});
details.addEventListener("toggle", () => {
if (details.open) requestAnimationFrame(() => search.focus());
board.infractionDropdownOpen = details.open;
if (details.open) {
requestAnimationFrame(() => search.focus({ preventScroll: true }));
return;
}
// Apply the freshest match data only after the operator has finished working
// with the menu. This avoids the 1-second online refresh closing the dropdown
// or resetting the search cursor midway through selection.
if (state.hockeyInfractionMenuRenderPending) {
state.hockeyInfractionMenuRenderPending = false;
requestAnimationFrame(() => renderRuntime());
}
});
return details;
}
@@ -14257,6 +14294,13 @@ function renderHockeyPenaltyDashboard(node, component, runtime) {
state.hockeySettingsRenderPending = true;
return;
}
// BUILD161: while the infraction picker is open on the main Game tab, keep the
// current DOM untouched. Online match polling may continue in the background;
// the newest data is rendered immediately after the picker is closed.
if (el.runtimeStage.querySelector?.(".hpd-infraction-dropdown[open]")) {
state.hockeyInfractionMenuRenderPending = true;
return;
}
// Keep manual text editing stable while background match-data refreshes arrive.
if (state.activeTab === "custom_pluses"
&& document.activeElement?.closest?.(".hcp-workspace")