Release v1.26.12: Fix page-wide drag-and-drop interception & magOnShow navigation hook
Some checks are pending
Test and SonarQube / quality (push) Waiting to run

This commit is contained in:
mARTin-B78 2026-09-10 13:22:26 +02:00
parent f5f887bb1d
commit 11142842c2
5 changed files with 55 additions and 25 deletions

View File

@ -5,6 +5,15 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi
--- ---
## [1.26.12] — 2026-09-10
### Fixed
- **Page-Wide PDF Drag-and-Drop Interception & Dropzone Navigation Hook.**
- Installed an immediate, eager `window` drag-and-drop safety net (`installGlobalMagDropGuard()`) that prevents dropping a PDF anywhere on the page from opening the PDF in the browser tab.
- Added `window.magOnShow()` navigation hook in `nav.js` and guaranteed `setupMagDropzone()` wires the `#mag-dropzone` target whenever the Magazine section is visited or mounted, stopping `magInit()` from exiting silently if the DOM element was not yet present at script load time.
---
## [1.26.11] — 2026-09-10 ## [1.26.11] — 2026-09-10
### Added ### Added

View File

@ -1 +1 @@
1.26.11 1.26.12

View File

@ -10,7 +10,7 @@
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#2563EB"> <meta name="theme-color" content="#2563EB">
<meta name="app-version" content="1.26.11"> <meta name="app-version" content="1.26.12">
<link rel="manifest" href="/manifest.webmanifest"> <link rel="manifest" href="/manifest.webmanifest">
<link rel="icon" href="/static/icon.svg" type="image/svg+xml"> <link rel="icon" href="/static/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/static/icon.svg"> <link rel="apple-touch-icon" href="/static/icon.svg">
@ -27,12 +27,12 @@
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── --> <!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
<link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css"> <link rel="stylesheet" href="/static/vendor/mdi/materialdesignicons.min.css">
<link rel="stylesheet" href="/static/style.css?v=1.26.11"> <link rel="stylesheet" href="/static/style.css?v=1.26.12">
<link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.26.11"> <link rel="stylesheet" href="/static/css/resource-diagnostics.css?v=1.26.12">
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.26.11"> <link rel="stylesheet" href="/static/css/background-jobs.css?v=1.26.12">
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.26.11"> <link rel="stylesheet" href="/static/css/voice-design.css?v=1.26.12">
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.26.11"> <link rel="stylesheet" href="/static/css/rehearser.css?v=1.26.12">
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.26.11"> <link rel="stylesheet" href="/static/css/audiobook.css?v=1.26.12">
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── --> <!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->

View File

@ -210,25 +210,25 @@ function magShowDroppedFile(file) {
} }
} }
let _magDropGuardInstalled = false; function installGlobalMagDropGuard() {
if (window._magDropGuardInstalled) return;
window._magDropGuardInstalled = true;
window.addEventListener('dragover', (e) => {
e.preventDefault();
if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
});
window.addEventListener('drop', (e) => {
e.preventDefault();
});
}
installGlobalMagDropGuard();
function setupMagDropzone() { function setupMagDropzone() {
installGlobalMagDropGuard();
const zone = $('mag-dropzone'); const zone = $('mag-dropzone');
const input = $('mag-new-file'); const input = $('mag-new-file');
if (!zone || !input) return; if (!zone || !input) return;
// A page-wide safety net: if a drop ever lands outside the zone (or the
// zone's own handler below fails to intercept it for any reason), the
// browser's native behaviour is to navigate to/open the dropped file --
// confirmed live as exactly what happened before this existed. Installed
// once regardless of which section is active, since a stray drop can land
// anywhere on the page.
if (!_magDropGuardInstalled) {
_magDropGuardInstalled = true;
window.addEventListener('dragover', (e) => { e.preventDefault(); });
window.addEventListener('drop', (e) => { e.preventDefault(); });
}
if (zone.dataset.magDropzoneWired) return; if (zone.dataset.magDropzoneWired) return;
zone.dataset.magDropzoneWired = '1'; zone.dataset.magDropzoneWired = '1';
@ -242,12 +242,22 @@ function setupMagDropzone() {
// dragenter AND dragover both need preventDefault() -- some browsers only // dragenter AND dragover both need preventDefault() -- some browsers only
// arm the element as a valid drop target once dragenter itself has been // arm the element as a valid drop target once dragenter itself has been
// cancelled, not just the dragover events that follow it. // cancelled, not just the dragover events that follow it.
const armDropTarget = (e) => { e.preventDefault(); zone.classList.add('dragover'); }; const armDropTarget = (e) => {
e.preventDefault();
e.stopPropagation();
if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
zone.classList.add('dragover');
};
zone.addEventListener('dragenter', armDropTarget); zone.addEventListener('dragenter', armDropTarget);
zone.addEventListener('dragover', armDropTarget); zone.addEventListener('dragover', armDropTarget);
zone.addEventListener('dragleave', () => zone.classList.remove('dragover')); zone.addEventListener('dragleave', (e) => {
e.preventDefault();
e.stopPropagation();
zone.classList.remove('dragover');
});
zone.addEventListener('drop', (e) => { zone.addEventListener('drop', (e) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
zone.classList.remove('dragover'); zone.classList.remove('dragover');
const file = e.dataTransfer?.files?.[0]; const file = e.dataTransfer?.files?.[0];
if (!file) return; if (!file) return;
@ -1750,12 +1760,21 @@ function syncDrivingPlayButton() {
// ── Boot ───────────────────────────────────────────────────────────────────── // ── Boot ─────────────────────────────────────────────────────────────────────
async function magOnShow() {
setupMagDropzone();
setupMagIngestPreviewResize();
if ($('mag-library-list')) {
magLoadLibrary();
magLoadVoices();
}
}
async function magInit() { async function magInit() {
setupMagDropzone();
setupMagIngestPreviewResize();
if (!$('mag-library-list')) return; // section not mounted if (!$('mag-library-list')) return; // section not mounted
magLoadLibrary(); magLoadLibrary();
magLoadVoices(); magLoadVoices();
setupMagDropzone();
setupMagIngestPreviewResize();
let lastId = null; let lastId = null;
try { lastId = localStorage.getItem(MAG_LAST_DOC_KEY); } catch (_) {} try { lastId = localStorage.getItem(MAG_LAST_DOC_KEY); } catch (_) {}
if (lastId) { if (lastId) {
@ -1775,6 +1794,7 @@ async function magInit() {
magShow('library'); magShow('library');
} }
root.magOnShow = magOnShow;
root.magOpen = magOpen; root.magOpen = magOpen;
root.magDelete = magDelete; root.magDelete = magDelete;
root.magCreate = magCreate; root.magCreate = magCreate;

View File

@ -179,6 +179,7 @@
} }
if (sectionId === 's-library' && typeof window.libraryRender === 'function') window.libraryRender(window._libraryView || 'books'); if (sectionId === 's-library' && typeof window.libraryRender === 'function') window.libraryRender(window._libraryView || 'books');
if (sectionId === 's-caststudio' && typeof window.studioOnShow === 'function') window.studioOnShow(); if (sectionId === 's-caststudio' && typeof window.studioOnShow === 'function') window.studioOnShow();
if (sectionId === 's-magazine' && typeof window.magOnShow === 'function') window.magOnShow();
if (typeof window.initCollapsibleCards === 'function') window.initCollapsibleCards(); if (typeof window.initCollapsibleCards === 'function') window.initCollapsibleCards();
setStoredSection(sectionId); setStoredSection(sectionId);
setSectionHash(sectionId); setSectionHash(sectionId);