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
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
This commit is contained in:
parent
f5f887bb1d
commit
11142842c2
@ -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
|
||||
|
||||
### Added
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<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="icon" href="/static/icon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/static/icon.svg">
|
||||
@ -27,12 +27,12 @@
|
||||
|
||||
<!-- ── Core styles (local — no CDN dependency for first paint) ────────── -->
|
||||
<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/css/resource-diagnostics.css?v=1.26.11">
|
||||
<link rel="stylesheet" href="/static/css/background-jobs.css?v=1.26.11">
|
||||
<link rel="stylesheet" href="/static/css/voice-design.css?v=1.26.11">
|
||||
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.26.11">
|
||||
<link rel="stylesheet" href="/static/css/audiobook.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.12">
|
||||
<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.12">
|
||||
<link rel="stylesheet" href="/static/css/rehearser.css?v=1.26.12">
|
||||
<link rel="stylesheet" href="/static/css/audiobook.css?v=1.26.12">
|
||||
|
||||
|
||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||
|
||||
@ -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() {
|
||||
installGlobalMagDropGuard();
|
||||
const zone = $('mag-dropzone');
|
||||
const input = $('mag-new-file');
|
||||
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;
|
||||
zone.dataset.magDropzoneWired = '1';
|
||||
|
||||
@ -242,12 +242,22 @@ function setupMagDropzone() {
|
||||
// dragenter AND dragover both need preventDefault() -- some browsers only
|
||||
// arm the element as a valid drop target once dragenter itself has been
|
||||
// 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('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) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
zone.classList.remove('dragover');
|
||||
const file = e.dataTransfer?.files?.[0];
|
||||
if (!file) return;
|
||||
@ -1750,12 +1760,21 @@ function syncDrivingPlayButton() {
|
||||
|
||||
// ── Boot ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
async function magOnShow() {
|
||||
setupMagDropzone();
|
||||
setupMagIngestPreviewResize();
|
||||
if ($('mag-library-list')) {
|
||||
magLoadLibrary();
|
||||
magLoadVoices();
|
||||
}
|
||||
}
|
||||
|
||||
async function magInit() {
|
||||
setupMagDropzone();
|
||||
setupMagIngestPreviewResize();
|
||||
if (!$('mag-library-list')) return; // section not mounted
|
||||
magLoadLibrary();
|
||||
magLoadVoices();
|
||||
setupMagDropzone();
|
||||
setupMagIngestPreviewResize();
|
||||
let lastId = null;
|
||||
try { lastId = localStorage.getItem(MAG_LAST_DOC_KEY); } catch (_) {}
|
||||
if (lastId) {
|
||||
@ -1775,6 +1794,7 @@ async function magInit() {
|
||||
magShow('library');
|
||||
}
|
||||
|
||||
root.magOnShow = magOnShow;
|
||||
root.magOpen = magOpen;
|
||||
root.magDelete = magDelete;
|
||||
root.magCreate = magCreate;
|
||||
|
||||
@ -179,6 +179,7 @@
|
||||
}
|
||||
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-magazine' && typeof window.magOnShow === 'function') window.magOnShow();
|
||||
if (typeof window.initCollapsibleCards === 'function') window.initCollapsibleCards();
|
||||
setStoredSection(sectionId);
|
||||
setSectionHash(sectionId);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user