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:
Tim van der Meij 2021-01-23 19:35:08 +01:00 committed by GitHub
commit d4c4f5d4e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 178 additions and 56 deletions

View File

@ -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 };

View File

@ -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;
}

View File

@ -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;

View File

@ -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":

View File

@ -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;
}

View File

@ -121,6 +121,10 @@ class PDFSinglePageViewer extends BaseViewer {
_updateScrollMode() {}
_updateSpreadMode() {}
_getPageAdvance() {
return 1;
}
}
export { PDFSinglePageViewer };

View File

@ -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;
}

View File

@ -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,
});
}