From cd20df315d645d96a1f5ad99547bbb2904b807f1 Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Thu, 9 Jul 2026 02:33:56 +0200 Subject: [PATCH] Stop click/drag-on-a-name from reassigning the wrong paragraph (v1.14.13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The intended flow is: click the broken paragraph's speaker label to open "Assign to", then supply the name (type, click it anywhere in the text, or drag-select it). But clicking or drag-selecting a name with no popup open yet used to open/target a popup for whichever paragraph that name lived in, silently reassigning THAT paragraph instead of the one the user meant to fix. Both paths now require an already-open popup before they do anything — a paragraph is only ever selected via its own speaker label (or the existing double-click fast-assign shortcut). Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 7 ++++++ VERSION | 2 +- static/index.html | 6 ++--- static/js/audiobook.js | 51 +++++++++++++++++------------------------- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 358c1b9..9d4fd13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi --- +## [1.14.13] — 2026-07-09 + +### Fixed +- **Clicking or drag-selecting a name could reassign the wrong paragraph** — the intended flow is: click the broken (Unknown/Narrator/misattributed) paragraph's speaker label first to open "Assign to", *then* supply the name by typing, clicking it anywhere in the text, or drag-selecting it. But clicking/dragging a name with no popup open yet used to open (and target) the popup for whichever paragraph that name happened to live in — silently reassigning that paragraph instead of the one the user meant to fix. Clicking/dragging a name now only ever fills an already-open popup; a paragraph is only ever selected via its own speaker label (or the existing double-click-a-name fast-assign shortcut). + +--- + ## [1.14.12] — 2026-07-09 ### Added diff --git a/VERSION b/VERSION index 4ed70fa..517e041 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.14.12 +1.14.13 diff --git a/static/index.html b/static/index.html index 4e2f24e..244796d 100644 --- a/static/index.html +++ b/static/index.html @@ -10,7 +10,7 @@ - + @@ -27,7 +27,7 @@ - + @@ -365,7 +365,7 @@ window.toggleNavTree = function(treeId, chevronId) { - + diff --git a/static/js/audiobook.js b/static/js/audiobook.js index 8227ba0..ebdf888 100644 --- a/static/js/audiobook.js +++ b/static/js/audiobook.js @@ -2797,28 +2797,26 @@ STRIKTE FORMAT- UND TEXTREGELN: _abOpenAssignPopup(spk.closest('.ab-cv-row'), spk, ''); return; } - // Click a name/word inside the narration text itself — same popup, - // pre-filled with the clicked word so you don't have to retype it. - // Dragging across several words is handled by the native-selection - // listener below instead of a custom span-drag tracker, so it can't - // conflict with the existing "select text to split this segment" flow, - // which also reacts to window.getSelection() over the same text. That - // listener clears the selection once it acts, so this guard (rather than - // just isCollapsed) stops the click that follows a drag's mouseup from - // re-opening the popup with just the single word under the pointer. + // This guard (rather than just isCollapsed) stops the click that follows + // a drag's mouseup from also firing the word-click branch below. if (_abJustHandledSelection) { _abJustHandledSelection = false; return; } const txtEl = e.target.closest('.ab-cv-txt'); if (txtEl && window.getSelection().isCollapsed) { + // Clicking a name/word never opens or retargets a popup by itself — + // only the speaker label (handled above) selects a paragraph. This + // requires an assign popup to already be open (via that label click, + // or a double-click fast-assign): a click on a name anywhere in the + // text then just borrows that name into the search box, targeting + // whichever paragraph was actually selected. Without this, clicking a + // name that happens to live in some OTHER paragraph's text (the + // common way to "grab a name I see") silently reassigned THAT + // paragraph instead of the one the user meant to fix. + if (!assignModeRow) return; const row = txtEl.closest('.ab-cv-row'); const nameHit = e.target.closest('.ab-name-hit'); const clickedWord = nameHit ? (nameHit.dataset.name || nameHit.textContent.trim()) : _abWordRangeAtPoint(e.clientX, e.clientY)?.word; - // If a popup is already open targeting a DIFFERENT paragraph, a click on - // a name elsewhere in the text only borrows that name into the search - // box — it must not silently retarget/highlight the paragraph under the - // cursor, which used to make it look like THAT paragraph was being - // reassigned instead of the one the user actually opened the popup for. - if (assignModeRow && assignModeRow !== row) { + if (assignModeRow !== row) { if (clickedWord) { const inp = assignPopup.querySelector('input'); inp.value = clickedWord; @@ -3003,23 +3001,14 @@ STRIKTE FORMAT- UND TEXTREGELN: // alone for the "Split text to Unknown Speaker" button (wired via // selectionchange below) instead of hijacking them into the assign popup. if (/^[»„“"'‘]/.test(text)) return; + // Dragging to select a name only ever feeds an ALREADY-open popup (opened + // by clicking a paragraph's speaker label) — it must not open/retarget a + // popup for whichever paragraph happens to contain the dragged text, + // which used to reassign the wrong paragraph (the one you dragged a name + // out of, not the one you actually meant to fix). + if (!assignModeSeg) return; _abJustHandledSelection = true; // stop the click that follows this mouseup from also firing - if (assignModeSeg) { - // Popup already open (e.g. from clicking the speaker label) — a short - // selection refines/confirms the assignment directly, as before. - assignName(text); - sel.removeAllRanges(); - return; - } - // No popup yet: dragging across a name inside the narration text (e.g. a - // multi-word name like "Sharraz Garthai" the roster doesn't have) opens - // the popup pre-filled with the dragged text instead of doing nothing. - const anchorEl = sel.anchorNode.nodeType === 3 ? sel.anchorNode.parentNode : sel.anchorNode; - const txtSpan = anchorEl.closest('.ab-cv-txt'); - if (!txtSpan) { _abJustHandledSelection = false; return; } - const row = txtSpan.closest('.ab-cv-row'); - if (!row) { _abJustHandledSelection = false; return; } - _abOpenAssignPopup(row, anchorEl, text); + assignName(text); sel.removeAllRanges(); });