diff --git a/chrome/content/zotero/elements/tagsBox.js b/chrome/content/zotero/elements/tagsBox.js index bfda8a1699..37ad453b51 100644 --- a/chrome/content/zotero/elements/tagsBox.js +++ b/chrome/content/zotero/elements/tagsBox.js @@ -374,11 +374,16 @@ } let delimiters = [',', ';']; let interceptRegex = new RegExp(`[\\p{L}\\p{N}]+\\s*(${delimiters.join('|')})\\s*[\\p{L}\\p{N}]+`, 'iu'); - let match = str.match(interceptRegex); + // Combine existing field value with pasted text at cursor position + let existing = textbox.ref?.value || ''; + let selStart = textbox.ref?.selectionStart ?? existing.length; + let selEnd = textbox.ref?.selectionEnd ?? existing.length; + let combined = existing.slice(0, selStart) + str + existing.slice(selEnd); + let match = combined.match(interceptRegex); if (match) { event.preventDefault(); - textbox.value = str.trim(); - this.openTagSplitterWindow(str, match[1], textbox); + textbox.value = combined.trim(); + this.openTagSplitterWindow(combined, match[1], textbox); } }; diff --git a/test/tests/tagsboxTest.js b/test/tests/tagsboxTest.js index 7ea1fa57ac..e7178f84af 100644 --- a/test/tests/tagsboxTest.js +++ b/test/tests/tagsboxTest.js @@ -313,5 +313,32 @@ describe("Item Tags Box", function () { await item.eraseTx(); } }); + + it("should insert pasted text at cursor position within existing value", async function () { + let item = await createDataObject('item'); + let tagsbox = doc.querySelector('#zotero-editpane-tags'); + let stub = sinon.stub(tagsbox, 'openTagSplitterWindow'); + + let row = tagsbox.newTag(); + let editable = row.querySelector('editable-text'); + + // Simulate user having typed "foobar" with cursor before "b" (position 3) + editable.value = 'foobar'; + editable.ref.value = 'foobar'; + editable.ref.selectionStart = 3; + editable.ref.selectionEnd = 3; + + let event = createPasteEvent('s,a'); + editable.dispatchEvent(event); + + assert.isTrue(event.defaultPrevented, 'paste should be intercepted'); + assert.isTrue(stub.calledOnce, 'tag splitter should open'); + // "foobar" with "s,a" inserted at position 3 -> "foos,abar" + assert.equal(stub.args[0][0], 'foos,abar', 'should pass combined string with paste inserted at cursor'); + assert.equal(stub.args[0][1], ',', 'delimiter should be comma'); + + stub.restore(); + await item.eraseTx(); + }); }); })