Merge pull request #12870 from Snuffleupagus/page-advance
Add previous/next-page functionality that takes scroll/spread-modes into account (issue 11946)
This commit is contained in:
commit
d4c4f5d4e5
@ -650,11 +650,21 @@ describe("ui_utils", function () {
|
||||
const hiddenWidth =
|
||||
Math.max(0, scrollLeft - viewLeft) +
|
||||
Math.max(0, viewRight - scrollRight);
|
||||
const visibleArea =
|
||||
(div.clientHeight - hiddenHeight) * (div.clientWidth - hiddenWidth);
|
||||
const percent =
|
||||
((visibleArea * 100) / div.clientHeight / div.clientWidth) | 0;
|
||||
views.push({ id: view.id, x: viewLeft, y: viewTop, view, percent });
|
||||
|
||||
const fractionHeight =
|
||||
(div.clientHeight - hiddenHeight) / div.clientHeight;
|
||||
const fractionWidth =
|
||||
(div.clientWidth - hiddenWidth) / div.clientWidth;
|
||||
const percent = (fractionHeight * fractionWidth * 100) | 0;
|
||||
|
||||
views.push({
|
||||
id: view.id,
|
||||
x: viewLeft,
|
||||
y: viewTop,
|
||||
view,
|
||||
percent,
|
||||
widthPercent: (fractionWidth * 100) | 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
return { first: views[0], last: views[views.length - 1], views };
|
||||
|
12
web/app.js
12
web/app.js
@ -2829,10 +2829,10 @@ function webViewerLastPage() {
|
||||
}
|
||||
}
|
||||
function webViewerNextPage() {
|
||||
PDFViewerApplication.page++;
|
||||
PDFViewerApplication.pdfViewer.nextPage();
|
||||
}
|
||||
function webViewerPreviousPage() {
|
||||
PDFViewerApplication.page--;
|
||||
PDFViewerApplication.pdfViewer.previousPage();
|
||||
}
|
||||
function webViewerZoomIn() {
|
||||
PDFViewerApplication.zoomIn();
|
||||
@ -3351,13 +3351,9 @@ function webViewerKeyDown(evt) {
|
||||
(!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")
|
||||
) {
|
||||
if (turnPage > 0) {
|
||||
if (PDFViewerApplication.page < PDFViewerApplication.pagesCount) {
|
||||
PDFViewerApplication.page++;
|
||||
}
|
||||
pdfViewer.nextPage();
|
||||
} else {
|
||||
if (PDFViewerApplication.page > 1) {
|
||||
PDFViewerApplication.page--;
|
||||
}
|
||||
pdfViewer.previousPage();
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
|
@ -1507,6 +1507,140 @@ class BaseViewer {
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getPageAdvance(currentPageNumber, previous = false) {
|
||||
if (this.isInPresentationMode) {
|
||||
return 1;
|
||||
}
|
||||
switch (this._scrollMode) {
|
||||
case ScrollMode.WRAPPED: {
|
||||
const { views } = this._getVisiblePages(),
|
||||
pageLayout = new Map();
|
||||
|
||||
// Determine the current (visible) page layout.
|
||||
for (const { id, y, percent, widthPercent } of views) {
|
||||
if (percent === 0 || widthPercent < 100) {
|
||||
continue;
|
||||
}
|
||||
let yArray = pageLayout.get(y);
|
||||
if (!yArray) {
|
||||
pageLayout.set(y, (yArray ||= []));
|
||||
}
|
||||
yArray.push(id);
|
||||
}
|
||||
// Find the row of the current page.
|
||||
for (const yArray of pageLayout.values()) {
|
||||
const currentIndex = yArray.indexOf(currentPageNumber);
|
||||
if (currentIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
const numPages = yArray.length;
|
||||
if (numPages === 1) {
|
||||
break;
|
||||
}
|
||||
// Handle documents with varying page sizes.
|
||||
if (previous) {
|
||||
for (let i = currentIndex - 1, ii = 0; i >= ii; i--) {
|
||||
const currentId = yArray[i],
|
||||
expectedId = yArray[i + 1] - 1;
|
||||
if (currentId < expectedId) {
|
||||
return currentPageNumber - expectedId;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = currentIndex + 1, ii = numPages; i < ii; i++) {
|
||||
const currentId = yArray[i],
|
||||
expectedId = yArray[i - 1] + 1;
|
||||
if (currentId > expectedId) {
|
||||
return expectedId - currentPageNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The current row is "complete", advance to the previous/next one.
|
||||
if (previous) {
|
||||
const firstId = yArray[0];
|
||||
if (firstId < currentPageNumber) {
|
||||
return currentPageNumber - firstId + 1;
|
||||
}
|
||||
} else {
|
||||
const lastId = yArray[numPages - 1];
|
||||
if (lastId > currentPageNumber) {
|
||||
return lastId - currentPageNumber + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ScrollMode.HORIZONTAL: {
|
||||
break;
|
||||
}
|
||||
case ScrollMode.VERTICAL: {
|
||||
if (this._spreadMode === SpreadMode.NONE) {
|
||||
break; // Normal vertical scrolling.
|
||||
}
|
||||
const parity = this._spreadMode - 1;
|
||||
|
||||
if (previous && currentPageNumber % 2 !== parity) {
|
||||
break; // Left-hand side page.
|
||||
} else if (!previous && currentPageNumber % 2 === parity) {
|
||||
break; // Right-hand side page.
|
||||
}
|
||||
const { views } = this._getVisiblePages(),
|
||||
expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1;
|
||||
|
||||
for (const { id, percent, widthPercent } of views) {
|
||||
if (id !== expectedId) {
|
||||
continue;
|
||||
}
|
||||
if (percent > 0 && widthPercent === 100) {
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the next page, taking scroll/spread-modes into account.
|
||||
* @returns {boolean} Whether navigation occured.
|
||||
*/
|
||||
nextPage() {
|
||||
const currentPageNumber = this._currentPageNumber,
|
||||
pagesCount = this.pagesCount;
|
||||
|
||||
if (currentPageNumber >= pagesCount) {
|
||||
return false;
|
||||
}
|
||||
const advance =
|
||||
this._getPageAdvance(currentPageNumber, /* previous = */ false) || 1;
|
||||
|
||||
this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the previous page, taking scroll/spread-modes into account.
|
||||
* @returns {boolean} Whether navigation occured.
|
||||
*/
|
||||
previousPage() {
|
||||
const currentPageNumber = this._currentPageNumber;
|
||||
|
||||
if (currentPageNumber <= 1) {
|
||||
return false;
|
||||
}
|
||||
const advance =
|
||||
this._getPageAdvance(currentPageNumber, /* previous = */ true) || 1;
|
||||
|
||||
this.currentPageNumber = Math.max(currentPageNumber - advance, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
initializeScriptingEvents() {
|
||||
if (!this.enableScripting || this._pageOpenPendingSet) {
|
||||
return;
|
||||
|
@ -401,15 +401,11 @@ class PDFLinkService {
|
||||
break;
|
||||
|
||||
case "NextPage":
|
||||
if (this.page < this.pagesCount) {
|
||||
this.page++;
|
||||
}
|
||||
this.pdfViewer.nextPage();
|
||||
break;
|
||||
|
||||
case "PrevPage":
|
||||
if (this.page > 1) {
|
||||
this.page--;
|
||||
}
|
||||
this.pdfViewer.previousPage();
|
||||
break;
|
||||
|
||||
case "LastPage":
|
||||
|
@ -138,7 +138,9 @@ class PDFPresentationMode {
|
||||
const totalDelta = this.mouseScrollDelta;
|
||||
this._resetMouseScrollState();
|
||||
const success =
|
||||
totalDelta > 0 ? this._goToPreviousPage() : this._goToNextPage();
|
||||
totalDelta > 0
|
||||
? this.pdfViewer.previousPage()
|
||||
: this.pdfViewer.nextPage();
|
||||
if (success) {
|
||||
this.mouseScrollTimeStamp = currentTime;
|
||||
}
|
||||
@ -153,32 +155,6 @@ class PDFPresentationMode {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_goToPreviousPage() {
|
||||
const page = this.pdfViewer.currentPageNumber;
|
||||
// If we're at the first page, we don't need to do anything.
|
||||
if (page <= 1) {
|
||||
return false;
|
||||
}
|
||||
this.pdfViewer.currentPageNumber = page - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_goToNextPage() {
|
||||
const page = this.pdfViewer.currentPageNumber;
|
||||
// If we're at the last page, we don't need to do anything.
|
||||
if (page >= this.pdfViewer.pagesCount) {
|
||||
return false;
|
||||
}
|
||||
this.pdfViewer.currentPageNumber = page + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -315,9 +291,9 @@ class PDFPresentationMode {
|
||||
evt.preventDefault();
|
||||
|
||||
if (evt.shiftKey) {
|
||||
this._goToPreviousPage();
|
||||
this.pdfViewer.previousPage();
|
||||
} else {
|
||||
this._goToNextPage();
|
||||
this.pdfViewer.nextPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -422,9 +398,9 @@ class PDFPresentationMode {
|
||||
delta = dy;
|
||||
}
|
||||
if (delta > 0) {
|
||||
this._goToPreviousPage();
|
||||
this.pdfViewer.previousPage();
|
||||
} else if (delta < 0) {
|
||||
this._goToNextPage();
|
||||
this.pdfViewer.nextPage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -121,6 +121,10 @@ class PDFSinglePageViewer extends BaseViewer {
|
||||
_updateScrollMode() {}
|
||||
|
||||
_updateSpreadMode() {}
|
||||
|
||||
_getPageAdvance() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
export { PDFSinglePageViewer };
|
||||
|
@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ScrollMode, SpreadMode } from "./ui_utils.js";
|
||||
import { BaseViewer } from "./base_viewer.js";
|
||||
import { shadow } from "pdfjs-lib";
|
||||
|
||||
@ -57,7 +58,11 @@ class PDFViewer extends BaseViewer {
|
||||
if (page.percent < 100) {
|
||||
break;
|
||||
}
|
||||
if (page.id === currentId) {
|
||||
if (
|
||||
page.id === currentId &&
|
||||
this._scrollMode === ScrollMode.VERTICAL &&
|
||||
this._spreadMode === SpreadMode.NONE
|
||||
) {
|
||||
stillFullyVisible = true;
|
||||
break;
|
||||
}
|
||||
|
@ -563,17 +563,18 @@ function getVisibleElements({
|
||||
Math.max(0, top - currentHeight) + Math.max(0, viewBottom - bottom);
|
||||
const hiddenWidth =
|
||||
Math.max(0, left - currentWidth) + Math.max(0, viewRight - right);
|
||||
const percent =
|
||||
(((viewHeight - hiddenHeight) * (viewWidth - hiddenWidth) * 100) /
|
||||
viewHeight /
|
||||
viewWidth) |
|
||||
0;
|
||||
|
||||
const fractionHeight = (viewHeight - hiddenHeight) / viewHeight,
|
||||
fractionWidth = (viewWidth - hiddenWidth) / viewWidth;
|
||||
const percent = (fractionHeight * fractionWidth * 100) | 0;
|
||||
|
||||
visible.push({
|
||||
id: view.id,
|
||||
x: currentWidth,
|
||||
y: currentHeight,
|
||||
view,
|
||||
percent,
|
||||
widthPercent: (fractionWidth * 100) | 0,
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user