Stop click/drag-on-a-name from reassigning the wrong paragraph (v1.14.13)
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 <noreply@anthropic.com>
This commit is contained in:
parent
3db3616830
commit
cd20df315d
@ -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
|
## [1.14.12] — 2026-07-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -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.14.12">
|
<meta name="app-version" content="1.14.13">
|
||||||
<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,7 +27,7 @@
|
|||||||
|
|
||||||
<!-- ── 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.14.12">
|
<link rel="stylesheet" href="/static/style.css?v=1.14.13">
|
||||||
|
|
||||||
|
|
||||||
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
<!-- ── Flag icons — non-blocking (loaded async, icons appear after JS) ── -->
|
||||||
@ -365,7 +365,7 @@ window.toggleNavTree = function(treeId, chevronId) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
<!-- loader.js: fetches sections → loads JS modules → removes skeleton -->
|
||||||
<script src="/static/loader.js?v=1.14.12"></script>
|
<script src="/static/loader.js?v=1.14.13"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -2797,28 +2797,26 @@ STRIKTE FORMAT- UND TEXTREGELN:
|
|||||||
_abOpenAssignPopup(spk.closest('.ab-cv-row'), spk, '');
|
_abOpenAssignPopup(spk.closest('.ab-cv-row'), spk, '');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Click a name/word inside the narration text itself — same popup,
|
// This guard (rather than just isCollapsed) stops the click that follows
|
||||||
// pre-filled with the clicked word so you don't have to retype it.
|
// a drag's mouseup from also firing the word-click branch below.
|
||||||
// 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.
|
|
||||||
if (_abJustHandledSelection) { _abJustHandledSelection = false; return; }
|
if (_abJustHandledSelection) { _abJustHandledSelection = false; return; }
|
||||||
const txtEl = e.target.closest('.ab-cv-txt');
|
const txtEl = e.target.closest('.ab-cv-txt');
|
||||||
if (txtEl && window.getSelection().isCollapsed) {
|
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 row = txtEl.closest('.ab-cv-row');
|
||||||
const nameHit = e.target.closest('.ab-name-hit');
|
const nameHit = e.target.closest('.ab-name-hit');
|
||||||
const clickedWord = nameHit ? (nameHit.dataset.name || nameHit.textContent.trim())
|
const clickedWord = nameHit ? (nameHit.dataset.name || nameHit.textContent.trim())
|
||||||
: _abWordRangeAtPoint(e.clientX, e.clientY)?.word;
|
: _abWordRangeAtPoint(e.clientX, e.clientY)?.word;
|
||||||
// If a popup is already open targeting a DIFFERENT paragraph, a click on
|
if (assignModeRow !== row) {
|
||||||
// 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 (clickedWord) {
|
if (clickedWord) {
|
||||||
const inp = assignPopup.querySelector('input');
|
const inp = assignPopup.querySelector('input');
|
||||||
inp.value = clickedWord;
|
inp.value = clickedWord;
|
||||||
@ -3003,23 +3001,14 @@ STRIKTE FORMAT- UND TEXTREGELN:
|
|||||||
// alone for the "Split text to Unknown Speaker" button (wired via
|
// alone for the "Split text to Unknown Speaker" button (wired via
|
||||||
// selectionchange below) instead of hijacking them into the assign popup.
|
// selectionchange below) instead of hijacking them into the assign popup.
|
||||||
if (/^[»„“"'‘]/.test(text)) return;
|
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
|
_abJustHandledSelection = true; // stop the click that follows this mouseup from also firing
|
||||||
if (assignModeSeg) {
|
assignName(text);
|
||||||
// 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);
|
|
||||||
sel.removeAllRanges();
|
sel.removeAllRanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user