Merge pull request #9858 from Snuffleupagus/scrollMode-refactor

Additional Scroll/Spread mode clean-up (PR 9832 follow-up)
This commit is contained in:
Tim van der Meij 2018-06-30 22:13:42 +02:00 committed by GitHub
commit 872c6e4af0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 187 additions and 127 deletions

View File

@ -973,8 +973,7 @@ let PDFViewerApplication = {
this.toolbar.setPagesCount(pdfDocument.numPages, false);
this.secondaryToolbar.setPagesCount(pdfDocument.numPages);
let id = this.documentFingerprint = pdfDocument.fingerprint;
let store = this.store = new ViewHistory(id);
const store = this.store = new ViewHistory(pdfDocument.fingerprint);
let baseDocumentUrl;
if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
@ -1003,7 +1002,7 @@ let PDFViewerApplication = {
// The browsing history is only enabled when the viewer is standalone,
// i.e. not when it is embedded in a web page.
let resetHistory = !AppOptions.get('showPreviousViewOnLoad');
this.pdfHistory.initialize(id, resetHistory);
this.pdfHistory.initialize(pdfDocument.fingerprint, resetHistory);
if (this.pdfHistory.initialBookmark) {
this.initialBookmark = this.pdfHistory.initialBookmark;
@ -1044,12 +1043,8 @@ let PDFViewerApplication = {
rotation = parseInt(values.rotation, 10);
sidebarView = sidebarView || (values.sidebarView | 0);
if (values.scrollMode !== null) {
scrollMode = values.scrollMode;
}
if (values.spreadMode !== null) {
spreadMode = values.spreadMode;
}
scrollMode = scrollMode || (values.scrollMode | 0);
spreadMode = spreadMode || (values.spreadMode | 0);
}
if (pageMode && !AppOptions.get('disablePageMode')) {
// Always let the user preference/history take precedence.
@ -1246,23 +1241,26 @@ let PDFViewerApplication = {
});
},
setInitialView(storedHash, values = {}) {
let { rotation, sidebarView, scrollMode, spreadMode, } = values;
setInitialView(storedHash, { rotation, sidebarView,
scrollMode, spreadMode, } = {}) {
let setRotation = (angle) => {
if (isValidRotation(angle)) {
this.pdfViewer.pagesRotation = angle;
}
};
let setViewerModes = (scroll, spread) => {
if (Number.isInteger(scroll)) {
this.pdfViewer.scrollMode = scroll;
}
if (Number.isInteger(spread)) {
this.pdfViewer.spreadMode = spread;
}
};
// Putting these before isInitialViewSet = true prevents these values from
// being stored in the document history (and overriding any future changes
// made to the corresponding global preferences), just this once.
if (Number.isInteger(scrollMode)) {
this.pdfViewer.setScrollMode(scrollMode);
}
if (Number.isInteger(spreadMode)) {
this.pdfViewer.setSpreadMode(spreadMode);
}
setViewerModes(scrollMode, spreadMode);
this.isInitialViewSet = true;
this.pdfSidebar.setInitialView(sidebarView);
@ -2021,10 +2019,10 @@ function webViewerRotateCcw() {
PDFViewerApplication.rotatePages(-90);
}
function webViewerSwitchScrollMode(evt) {
PDFViewerApplication.pdfViewer.setScrollMode(evt.mode);
PDFViewerApplication.pdfViewer.scrollMode = evt.mode;
}
function webViewerSwitchSpreadMode(evt) {
PDFViewerApplication.pdfViewer.setSpreadMode(evt.mode);
PDFViewerApplication.pdfViewer.spreadMode = evt.mode;
}
function webViewerDocumentProperties() {
PDFViewerApplication.pdfDocumentProperties.open();

View File

@ -116,6 +116,16 @@ const defaultOptions = {
value: 0,
kind: OptionKind.VIEWER,
},
scrollModeOnLoad: {
/** @type {number} */
value: 0,
kind: OptionKind.VIEWER,
},
spreadModeOnLoad: {
/** @type {number} */
value: 0,
kind: OptionKind.VIEWER,
},
textLayerMode: {
/** @type {number} */
value: 1,

View File

@ -73,14 +73,6 @@ const SpreadMode = {
* size in total pixels, i.e. width * height. Use -1 for no limit.
* The default value is 4096 * 4096 (16 mega-pixels).
* @property {IL10n} l10n - Localization service.
* @property {number} scrollMode - (optional) The direction in which the
* document pages should be laid out within the scrolling container. The
* constants from {ScrollMode} should be used. The default value is
* `ScrollMode.VERTICAL`.
* @property {number} spreadMode - (optional) If not `SpreadMode.NONE`, groups
* pages into spreads, starting with odd- or even-numbered pages. The
* constants from {SpreadMode} should be used. The default value is
* `SpreadMode.NONE`.
*/
function PDFPageViewBuffer(size) {
@ -162,8 +154,6 @@ class BaseViewer {
this.useOnlyCssZoom = options.useOnlyCssZoom || false;
this.maxCanvasPixels = options.maxCanvasPixels;
this.l10n = options.l10n || NullL10n;
this.scrollMode = options.scrollMode || ScrollMode.VERTICAL;
this.spreadMode = options.spreadMode || SpreadMode.NONE;
this.defaultRenderingQueue = !options.renderingQueue;
if (this.defaultRenderingQueue) {
@ -181,8 +171,17 @@ class BaseViewer {
if (this.removePageBorders) {
this.viewer.classList.add('removePageBorders');
}
if (this.scrollMode !== ScrollMode.VERTICAL) {
this._updateScrollModeClasses();
if ((typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) &&
('scrollMode' in options || 'spreadMode' in options)) {
console.error(`The ${this._name} constructor options ` +
'`scrollMode`/`spreadMode` are deprecated, use the setters instead.');
if (options.scrollMode !== undefined) {
this.scrollMode = options.scrollMode;
}
if (options.spreadMode !== undefined) {
this.spreadMode = options.spreadMode;
}
}
}
@ -441,8 +440,8 @@ class BaseViewer {
bindOnAfterAndBeforeDraw(pageView);
this._pages.push(pageView);
}
if (this.spreadMode !== SpreadMode.NONE) {
this._regroupSpreads();
if (this._spreadMode !== SpreadMode.NONE) {
this._updateSpreadMode();
}
// Fetch all the pages since the viewport is needed before printing
@ -524,9 +523,13 @@ class BaseViewer {
this._pagesRotation = 0;
this._pagesRequests = [];
this._pageViewsReady = false;
this._scrollMode = ScrollMode.VERTICAL;
this._spreadMode = SpreadMode.NONE;
// Remove the pages from the DOM.
// Remove the pages from the DOM...
this.viewer.textContent = '';
// ... and reset the Scroll mode CSS class(es) afterwards.
this._updateScrollMode();
}
_scrollUpdate() {
@ -1023,26 +1026,132 @@ class BaseViewer {
});
}
setScrollMode(mode) {
/**
* @return {number} One of the values in {ScrollMode}.
*/
get scrollMode() {
return this._scrollMode;
}
/**
* @param {number} mode - The direction in which the document pages should be
* laid out within the scrolling container.
* The constants from {ScrollMode} should be used.
*/
set scrollMode(mode) {
if (this._scrollMode === mode) {
return; // The Scroll mode didn't change.
}
if (!Number.isInteger(mode) || !Object.values(ScrollMode).includes(mode)) {
throw new Error(`Invalid scroll mode: ${mode}`);
}
this.scrollMode = mode;
this._scrollMode = mode;
this.eventBus.dispatch('scrollmodechanged', { source: this, mode, });
this._updateScrollMode(/* pageNumber = */ this._currentPageNumber);
}
_updateScrollModeClasses() {
// No-op in the base class.
_updateScrollMode(pageNumber = null) {
const scrollMode = this._scrollMode, viewer = this.viewer;
if (scrollMode === ScrollMode.HORIZONTAL) {
viewer.classList.add('scrollHorizontal');
} else {
viewer.classList.remove('scrollHorizontal');
}
if (scrollMode === ScrollMode.WRAPPED) {
viewer.classList.add('scrollWrapped');
} else {
viewer.classList.remove('scrollWrapped');
}
if (!this.pdfDocument || !pageNumber) {
return;
}
// Non-numeric scale values can be sensitive to the scroll orientation.
// Call this before re-scrolling to the current page, to ensure that any
// changes in scale don't move the current page.
if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
this._setScale(this._currentScaleValue, true);
}
this.scrollPageIntoView({ pageNumber, });
this.update();
}
setSpreadMode(mode) {
setScrollMode(mode) {
if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
console.error(`${this._name}.setScrollMode() is deprecated, ` +
`use the ${this._name}.scrollMode setter instead.`);
this.scrollMode = mode;
}
}
/**
* @return {number} One of the values in {SpreadMode}.
*/
get spreadMode() {
return this._spreadMode;
}
/**
* @param {number} mode - Group the pages in spreads, starting with odd- or
* even-number pages (unless `SpreadMode.NONE` is used).
* The constants from {SpreadMode} should be used.
*/
set spreadMode(mode) {
if (this._spreadMode === mode) {
return; // The Spread mode didn't change.
}
if (!Number.isInteger(mode) || !Object.values(SpreadMode).includes(mode)) {
throw new Error(`Invalid spread mode: ${mode}`);
}
this.spreadMode = mode;
this._spreadMode = mode;
this.eventBus.dispatch('spreadmodechanged', { source: this, mode, });
this._updateSpreadMode(/* pageNumber = */ this._currentPageNumber);
}
_regroupSpreads() {
// No-op in the base class.
_updateSpreadMode(pageNumber = null) {
if (!this.pdfDocument) {
return;
}
const viewer = this.viewer, pages = this._pages;
// Temporarily remove all the pages from the DOM.
viewer.textContent = '';
if (this._spreadMode === SpreadMode.NONE) {
for (let i = 0, iMax = pages.length; i < iMax; ++i) {
viewer.appendChild(pages[i].div);
}
} else {
const parity = this._spreadMode - 1;
let spread = null;
for (let i = 0, iMax = pages.length; i < iMax; ++i) {
if (spread === null) {
spread = document.createElement('div');
spread.className = 'spread';
viewer.appendChild(spread);
} else if (i % 2 === parity) {
spread = spread.cloneNode(false);
viewer.appendChild(spread);
}
spread.appendChild(pages[i].div);
}
}
if (!pageNumber) {
return;
}
this.scrollPageIntoView({ pageNumber, });
this.update();
}
setSpreadMode(mode) {
if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
console.error(`${this._name}.setSpreadMode() is deprecated, ` +
`use the ${this._name}.spreadMode setter instead.`);
this.spreadMode = mode;
}
}
}

View File

@ -147,6 +147,10 @@ class PDFSinglePageViewer extends BaseViewer {
// The Scroll/Spread modes are never used in `PDFSinglePageViewer`.
return shadow(this, '_isScrollModeHorizontal', false);
}
_updateScrollMode() { }
_updateSpreadMode() { }
}
export {

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import { BaseViewer, ScrollMode, SpreadMode } from './base_viewer';
import { BaseViewer, ScrollMode } from './base_viewer';
import { getVisibleElements, scrollIntoView } from './ui_utils';
import { shadow } from 'pdfjs-lib';
@ -27,7 +27,7 @@ class PDFViewer extends BaseViewer {
const left = pageDiv.offsetLeft + pageDiv.clientLeft;
const right = left + pageDiv.clientWidth;
const { scrollLeft, clientWidth, } = this.container;
if (this.scrollMode === ScrollMode.HORIZONTAL ||
if (this._scrollMode === ScrollMode.HORIZONTAL ||
left < scrollLeft || right > scrollLeft + clientWidth) {
pageSpot = { left: 0, top: 0, };
}
@ -38,7 +38,7 @@ class PDFViewer extends BaseViewer {
_getVisiblePages() {
if (!this.isInPresentationMode) {
return getVisibleElements(this.container, this._pages, true,
this.scrollMode === ScrollMode.HORIZONTAL);
this._scrollMode === ScrollMode.HORIZONTAL);
}
// The algorithm in getVisibleElements doesn't work in all browsers and
// configurations when presentation mode is active.
@ -91,86 +91,7 @@ class PDFViewer extends BaseViewer {
// Used to ensure that pre-rendering of the next/previous page works
// correctly, since Scroll/Spread modes are ignored in Presentation Mode.
return (this.isInPresentationMode ?
false : this.scrollMode === ScrollMode.HORIZONTAL);
}
setScrollMode(mode) {
if (mode === this.scrollMode) {
return;
}
super.setScrollMode(mode);
this.eventBus.dispatch('scrollmodechanged', { mode, });
this._updateScrollModeClasses();
if (!this.pdfDocument) {
return;
}
const pageNumber = this._currentPageNumber;
// Non-numeric scale modes can be sensitive to the scroll orientation.
// Call this before re-scrolling to the current page, to ensure that any
// changes in scale don't move the current page.
if (isNaN(this._currentScaleValue)) {
this._setScale(this._currentScaleValue, true);
}
this.scrollPageIntoView({ pageNumber, });
this.update();
}
_updateScrollModeClasses() {
const { scrollMode, viewer, } = this;
if (scrollMode === ScrollMode.HORIZONTAL) {
viewer.classList.add('scrollHorizontal');
} else {
viewer.classList.remove('scrollHorizontal');
}
if (scrollMode === ScrollMode.WRAPPED) {
viewer.classList.add('scrollWrapped');
} else {
viewer.classList.remove('scrollWrapped');
}
}
setSpreadMode(mode) {
if (mode === this.spreadMode) {
return;
}
super.setSpreadMode(mode);
this.eventBus.dispatch('spreadmodechanged', { mode, });
this._regroupSpreads();
}
_regroupSpreads() {
if (!this.pdfDocument) {
return;
}
const viewer = this.viewer, pages = this._pages;
// Temporarily remove all the pages from the DOM.
viewer.textContent = '';
if (this.spreadMode === SpreadMode.NONE) {
for (let i = 0, iMax = pages.length; i < iMax; ++i) {
viewer.appendChild(pages[i].div);
}
} else {
const parity = this.spreadMode - 1;
let spread = null;
for (let i = 0, iMax = pages.length; i < iMax; ++i) {
if (spread === null) {
spread = document.createElement('div');
spread.className = 'spread';
viewer.appendChild(spread);
} else if (i % 2 === parity) {
spread = spread.cloneNode(false);
viewer.appendChild(spread);
}
spread.appendChild(pages[i].div);
}
}
this.scrollPageIntoView({ pageNumber: this._currentPageNumber, });
this.update();
false : this._scrollMode === ScrollMode.HORIZONTAL);
}
}

View File

@ -140,6 +140,10 @@ class SecondaryToolbar {
this.pageNumber = 0;
this.pagesCount = 0;
this._updateUIState();
// Reset the Scroll/Spread buttons too, since they're document specific.
this.eventBus.dispatch('resetscrollmode', { source: this, });
this.eventBus.dispatch('resetspreadmode', { source: this, });
}
_updateUIState() {
@ -189,7 +193,7 @@ class SecondaryToolbar {
}
_bindScrollModeListener(buttons) {
this.eventBus.on('scrollmodechanged', function(evt) {
function scrollModeChanged(evt) {
buttons.scrollVerticalButton.classList.remove('toggled');
buttons.scrollHorizontalButton.classList.remove('toggled');
buttons.scrollWrappedButton.classList.remove('toggled');
@ -205,11 +209,18 @@ class SecondaryToolbar {
buttons.scrollWrappedButton.classList.add('toggled');
break;
}
}
this.eventBus.on('scrollmodechanged', scrollModeChanged);
this.eventBus.on('resetscrollmode', (evt) => {
if (evt.source === this) {
scrollModeChanged({ mode: ScrollMode.VERTICAL, });
}
});
}
_bindSpreadModeListener(buttons) {
this.eventBus.on('spreadmodechanged', function(evt) {
function spreadModeChanged(evt) {
buttons.spreadNoneButton.classList.remove('toggled');
buttons.spreadOddButton.classList.remove('toggled');
buttons.spreadEvenButton.classList.remove('toggled');
@ -225,6 +236,13 @@ class SecondaryToolbar {
buttons.spreadEvenButton.classList.add('toggled');
break;
}
}
this.eventBus.on('spreadmodechanged', spreadModeChanged);
this.eventBus.on('resetspreadmode', (evt) => {
if (evt.source === this) {
spreadModeChanged({ mode: SpreadMode.NONE, });
}
});
}