Skip to content

Commit

Permalink
Merge pull request #12870 from Snuffleupagus/page-advance
Browse files Browse the repository at this point in the history
Add previous/next-page functionality that takes scroll/spread-modes into account (issue 11946)
  • Loading branch information
timvandermeij authored Jan 23, 2021
2 parents 7102e4a + a2b592f commit d4c4f5d
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 56 deletions.
20 changes: 15 additions & 5 deletions test/unit/ui_utils_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
12 changes: 4 additions & 8 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2829,10 +2829,10 @@ function webViewerLastPage() {
}
}
function webViewerNextPage() {
PDFViewerApplication.page++;
PDFViewerApplication.pdfViewer.nextPage();
}
function webViewerPreviousPage() {
PDFViewerApplication.page--;
PDFViewerApplication.pdfViewer.previousPage();
}
function webViewerZoomIn() {
PDFViewerApplication.zoomIn();
Expand Down Expand Up @@ -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;
}
Expand Down
134 changes: 134 additions & 0 deletions web/base_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 2 additions & 6 deletions web/pdf_link_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down
38 changes: 7 additions & 31 deletions web/pdf_presentation_mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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
*/
Expand Down Expand Up @@ -315,9 +291,9 @@ class PDFPresentationMode {
evt.preventDefault();

if (evt.shiftKey) {
this._goToPreviousPage();
this.pdfViewer.previousPage();
} else {
this._goToNextPage();
this.pdfViewer.nextPage();
}
}
}
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 4 additions & 0 deletions web/pdf_single_page_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class PDFSinglePageViewer extends BaseViewer {
_updateScrollMode() {}

_updateSpreadMode() {}

_getPageAdvance() {
return 1;
}
}

export { PDFSinglePageViewer };
7 changes: 6 additions & 1 deletion web/pdf_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 6 additions & 5 deletions web/ui_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}

Expand Down

0 comments on commit d4c4f5d

Please sign in to comment.