diff --git a/test/integration/reorganize_pages_spec.mjs b/test/integration/reorganize_pages_spec.mjs index 389a69f3602c5..b0f03231c547f 100644 --- a/test/integration/reorganize_pages_spec.mjs +++ b/test/integration/reorganize_pages_spec.mjs @@ -190,13 +190,12 @@ describe("Reorganize Pages View", () => { return false; } ); - const dndPromise = dragAndDrop( + await dragAndDrop( page, getThumbnailSelector(1), [[0, rect2.y - rect1.y + rect2.height / 2]], 10 ); - await dndPromise; await awaitPromise(handleAddedMarker); await awaitPromise(handleRemovedMarker); }) @@ -1639,4 +1638,66 @@ describe("Reorganize Pages View", () => { ); }); }); + + describe("Dragging mustn't be possible when pasting (bug 2021934)", () => { + let pages; + + beforeEach(async () => { + pages = await loadAndWait( + "page_with_number.pdf", + "#viewsManagerToggleButton", + "page-fit", + null, + { enableSplitMerge: true } + ); + }); + + afterEach(async () => { + await closePages(pages); + }); + + it("should check that dragging is disabled when pasting", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + await waitForThumbnailVisible(page, 1); + + await Promise.all([ + page.waitForSelector(`#thumbnailsView.isDragging`, { + visible: true, + }), + dragAndDrop(page, getThumbnailSelector(1), [[0, 10]], 10), + ]); + + await page.waitForSelector(`#thumbnailsView.isDragging`, { + hidden: true, + }); + await waitAndClick( + page, + `.thumbnail:has(${getThumbnailSelector(1)}) input` + ); + await waitAndClick(page, "#viewsManagerStatusActionButton"); + await waitAndClick(page, "#viewsManagerStatusActionCopy"); + + // If dragging isn't disabled, the promise will resolve with the + // selector. Otherwise, it will resolve with undefined (dragAndDrop + // has no return), which is the expected behavior. + const abortController = new AbortController(); + const first = await Promise.race([ + page.waitForSelector(`#thumbnailsView.isDragging`, { + visible: true, + signal: abortController.signal, + }), + dragAndDrop(page, getThumbnailSelector(1), [[0, 10]], 10), + ]); + abortController.abort(); + + expect(first) + .withContext( + `In ${browserName}, dragging should be disabled when pasting` + ) + .toBeUndefined(); + }) + ); + }); + }); }); diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js index 8ee1cb29473f4..734684bffa34a 100644 --- a/web/pdf_thumbnail_viewer.js +++ b/web/pdf_thumbnail_viewer.js @@ -159,6 +159,8 @@ class PDFThumbnailViewer { #undoCloseButton = null; + #isInPasteMode = false; + /** * @param {PDFThumbnailViewerOptions} options */ @@ -525,6 +527,7 @@ class PDFThumbnailViewer { } #updateThumbnails(currentPageNumber) { + this.#resetCurrentThumbnail(0); let newCurrentPageNumber = 0; const pagesMapper = this.#pagesMapper; const prevThumbnails = (this.#savedThumbnails = this._thumbnails); @@ -658,13 +661,13 @@ class PDFThumbnailViewer { const newIndex = lastDraggedOverIndex + 1; const pagesToMove = Array.from(selectedPages).sort((a, b) => a - b); const pagesMapper = this.#pagesMapper; - let currentPageNumber = isNaN(this.#pageNumberToRemove) + const currentPageNumber = isNaN(this.#pageNumberToRemove) ? pagesToMove[0] : this.#pageNumberToRemove; pagesMapper.movePages(selectedPages, pagesToMove, newIndex); - currentPageNumber = this.#updateThumbnails(currentPageNumber); + this.#updateCurrentPage(this.#updateThumbnails(currentPageNumber)); this.#computeThumbnailsPosition(); selectedPages.clear(); @@ -676,8 +679,6 @@ class PDFThumbnailViewer { pagesMapper, type: "move", }); - - this.#updateCurrentPage(currentPageNumber); } if (!isNaN(this.#pageNumberToRemove)) { @@ -695,7 +696,6 @@ class PDFThumbnailViewer { #updateCurrentPage(currentPageNumber) { setTimeout(() => { - this.#resetCurrentThumbnail(0); this.forceRendering(); const newPageNumber = currentPageNumber || 1; this.linkService.goToPage(newPageNumber); @@ -765,6 +765,7 @@ class PDFThumbnailViewer { } #togglePasteMode(enable) { + this.#isInPasteMode = enable; if (enable) { this.container.classList.add("pasteMode"); for (const thumbnail of this._thumbnails) { @@ -822,14 +823,14 @@ class PDFThumbnailViewer { this.#toggleMenuEntries(true); const pagesMapper = this.#pagesMapper; - let currentPageNumber = this.#copiedPageNumbers.includes( + const currentPageNumber = this.#copiedPageNumbers.includes( this._currentPageNumber ) ? 0 : this._currentPageNumber; pagesMapper.pastePages(index); - currentPageNumber = this.#updateThumbnails(currentPageNumber); + this.#updateCurrentPage(this.#updateThumbnails(currentPageNumber)); this.eventBus.dispatch("pagesedited", { source: this, @@ -842,8 +843,6 @@ class PDFThumbnailViewer { this.#isCut = false; this.#updateMenuEntries(); this.#updateStatus("select"); - - this.#updateCurrentPage(currentPageNumber); } #deletePages(type = "delete") { @@ -855,7 +854,7 @@ class PDFThumbnailViewer { this.#updateStatus("delete"); } const pagesMapper = this.#pagesMapper; - let currentPageNumber = selectedPages.has(this._currentPageNumber) + const currentPageNumber = selectedPages.has(this._currentPageNumber) ? 0 : this._currentPageNumber; const pagesToDelete = (this.#deletedPageNumbers = Uint32Array.from( @@ -863,7 +862,7 @@ class PDFThumbnailViewer { ).sort((a, b) => a - b)); pagesMapper.deletePages(pagesToDelete); - currentPageNumber = this.#updateThumbnails(currentPageNumber); + this.#updateCurrentPage(this.#updateThumbnails(currentPageNumber)); selectedPages.clear(); this.#updateMenuEntries(); @@ -873,8 +872,6 @@ class PDFThumbnailViewer { pageNumbers: pagesToDelete, type, }); - - this.#updateCurrentPage(currentPageNumber); } #updateMenuEntries() { @@ -1224,7 +1221,7 @@ class PDFThumbnailViewer { } = e; if ( e.button !== 0 || // Skip right click. - this.#pagesMapper.copiedPageNumbers?.length > 0 || + this.#isInPasteMode || !isNaN(this.#lastDraggedOverIndex) || !draggedImage.classList.contains("thumbnailImageContainer") ) {