From f0acfe56a7ab85c284e37f41d28655afaab8c440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80?= <78488229+viktor138irk@users.noreply.github.com> Date: Thu, 7 May 2026 07:06:46 +0900 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D1=89=D0=B8=D1=82=D0=B0=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BE=D0=BA=20=D0=BE=D1=82=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D0=BC=D0=B5=D0=BD=D1=8E=20=D0=B1=D1=8B=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/patch_upload_navigation_guard.py | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 scripts/patch_upload_navigation_guard.py diff --git a/scripts/patch_upload_navigation_guard.py b/scripts/patch_upload_navigation_guard.py new file mode 100644 index 0000000..6f14fb8 --- /dev/null +++ b/scripts/patch_upload_navigation_guard.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +from pathlib import Path +import sys + +app_dir = Path(sys.argv[1]).resolve().parent if len(sys.argv) > 1 else Path('/opt/virtuality/web') +templates_dir = app_dir / 'templates' +changed = [] + +guard_script = r''' + + function setUploadNavigationGuard(active) { + window.virtualityUploadActive = Boolean(active); + document.body.classList.toggle('upload-locked', window.virtualityUploadActive); + } + + window.addEventListener('beforeunload', function (event) { + if (!window.virtualityUploadActive) return; + event.preventDefault(); + event.returnValue = 'Идёт загрузка файла. Переход остановит передачу.'; + return event.returnValue; + }); + + document.addEventListener('click', function (event) { + if (!window.virtualityUploadActive) return; + const target = event.target.closest('a, button, input[type="submit"]'); + if (!target) return; + if (target.id === 'iso-upload-button' || target.id === 'disk-upload-button') return; + event.preventDefault(); + event.stopPropagation(); + alert('Идёт загрузка файла. Дождись завершения или нажми «Отменить загрузку». Переход по меню сейчас заблокирован, чтобы файл не оборвался.'); + }, true); + + document.addEventListener('submit', function (event) { + if (!window.virtualityUploadActive) return; + if (event.target && (event.target.id === 'iso-upload-form' || event.target.id === 'disk-upload-form')) return; + event.preventDefault(); + event.stopPropagation(); + alert('Идёт загрузка файла. Дождись завершения или нажми «Отменить загрузку».'); + }, true); +''' + + +def patch_template(path: Path, active_token: str, form_id: str) -> None: + if not path.exists(): + return + text = path.read_text() + original = text + + if 'function setUploadNavigationGuard(active)' not in text: + marker = ' function bytesText(bytes) {' + if marker not in text: + raise SystemExit(f'bytesText marker not found in {path}') + text = text.replace(marker, guard_script + '\n' + marker, 1) + + text = text.replace(' uploadActive = active;\n', ' uploadActive = active;\n setUploadNavigationGuard(active);\n') + + # During server-side post-processing after upload, file transfer is done, so page navigation is safe again. + text = text.replace(" window.location.href = '/iso';", " setUploadNavigationGuard(false);\n window.location.href = '/iso';") + text = text.replace(" window.location.href = '/disk-images';", " setUploadNavigationGuard(false);\n window.location.href = '/disk-images';") + + # Conversion polling is not an active browser upload anymore; allow navigation while backend operation continues. + text = text.replace(" setUploadMode(false);\n fileInput.disabled = true;", " setUploadMode(false);\n setUploadNavigationGuard(false);\n fileInput.disabled = true;") + + if text != original: + path.write_text(text) + changed.append(str(path)) + +patch_template(templates_dir / 'iso.html', 'iso-upload-button', 'iso-upload-form') +patch_template(templates_dir / 'disk_images.html', 'disk-upload-button', 'disk-upload-form') + +print('upload navigation guard patch applied:') +for item in changed or ['already applied']: + print(f'- {item}')