Merge pull request #5295 from yurydelendik/pdfviewer
Refactoring to move page display code into separate class
This commit is contained in:
commit
1145eb8c09
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* globals chrome, PDFJS, PDFView */
|
||||
/* globals chrome, PDFJS, PDFViewerApplication */
|
||||
'use strict';
|
||||
|
||||
var ChromeCom = (function ChromeComClosure() {
|
||||
@ -64,10 +64,10 @@ var ChromeCom = (function ChromeComClosure() {
|
||||
var streamUrl = response.streamUrl;
|
||||
if (streamUrl) {
|
||||
console.log('Found data stream for ' + file);
|
||||
PDFView.open(streamUrl, 0, undefined, undefined, {
|
||||
PDFViewerApplication.open(streamUrl, 0, undefined, undefined, {
|
||||
length: response.contentLength
|
||||
});
|
||||
PDFView.setTitleUsingUrl(file);
|
||||
PDFViewerApplication.setTitleUsingUrl(file);
|
||||
return;
|
||||
}
|
||||
if (isFTPFile && !response.extensionSupportsFTP) {
|
||||
@ -91,7 +91,7 @@ var ChromeCom = (function ChromeComClosure() {
|
||||
resolveLocalFileSystemURL(file, function onResolvedFSURL(fileEntry) {
|
||||
fileEntry.file(function(fileObject) {
|
||||
var blobUrl = URL.createObjectURL(fileObject);
|
||||
PDFView.open(blobUrl, 0, undefined, undefined, {
|
||||
PDFViewerApplication.open(blobUrl, 0, undefined, undefined, {
|
||||
length: fileObject.size
|
||||
});
|
||||
});
|
||||
@ -100,11 +100,11 @@ var ChromeCom = (function ChromeComClosure() {
|
||||
// usual way of getting the File's data (via the Web worker).
|
||||
console.warn('Cannot resolve file ' + file + ', ' + error.name + ' ' +
|
||||
error.message);
|
||||
PDFView.open(file, 0);
|
||||
PDFViewerApplication.open(file, 0);
|
||||
});
|
||||
return;
|
||||
}
|
||||
PDFView.open(file, 0);
|
||||
PDFViewerApplication.open(file, 0);
|
||||
});
|
||||
};
|
||||
return ChromeCom;
|
||||
|
@ -14,20 +14,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFView, DownloadManager, getFileName */
|
||||
/* globals DownloadManager, getFileName */
|
||||
|
||||
'use strict';
|
||||
|
||||
var DocumentAttachmentsView = function documentAttachmentsView(attachments) {
|
||||
var attachmentsView = document.getElementById('attachmentsView');
|
||||
var DocumentAttachmentsView = function documentAttachmentsView(options) {
|
||||
var attachments = options.attachments;
|
||||
var attachmentsView = options.attachmentsView;
|
||||
while (attachmentsView.firstChild) {
|
||||
attachmentsView.removeChild(attachmentsView.firstChild);
|
||||
}
|
||||
|
||||
if (!attachments) {
|
||||
if (!attachmentsView.classList.contains('hidden')) {
|
||||
PDFView.switchSidebarView('thumbs');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -14,27 +14,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFView */
|
||||
|
||||
'use strict';
|
||||
|
||||
var DocumentOutlineView = function documentOutlineView(outline) {
|
||||
var outlineView = document.getElementById('outlineView');
|
||||
var DocumentOutlineView = function documentOutlineView(options) {
|
||||
var outline = options.outline;
|
||||
var outlineView = options.outlineView;
|
||||
while (outlineView.firstChild) {
|
||||
outlineView.removeChild(outlineView.firstChild);
|
||||
}
|
||||
|
||||
if (!outline) {
|
||||
if (!outlineView.classList.contains('hidden')) {
|
||||
PDFView.switchSidebarView('thumbs');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var linkService = options.linkService;
|
||||
|
||||
function bindItemLink(domObj, item) {
|
||||
domObj.href = PDFView.getDestinationHash(item.dest);
|
||||
domObj.href = linkService.getDestinationHash(item.dest);
|
||||
domObj.onclick = function documentOutlineViewOnclick(e) {
|
||||
PDFView.navigateTo(item.dest);
|
||||
linkService.navigateTo(item.dest);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFView, Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */
|
||||
/* globals Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -35,6 +35,8 @@ var DocumentProperties = {
|
||||
producerField: null,
|
||||
versionField: null,
|
||||
pageCountField: null,
|
||||
url: null,
|
||||
pdfDocument: null,
|
||||
|
||||
initialize: function documentPropertiesInitialize(options) {
|
||||
this.overlayName = options.overlayName;
|
||||
@ -72,7 +74,7 @@ var DocumentProperties = {
|
||||
return;
|
||||
}
|
||||
// Get the file size (if it hasn't already been set).
|
||||
PDFView.pdfDocument.getDownloadInfo().then(function(data) {
|
||||
this.pdfDocument.getDownloadInfo().then(function(data) {
|
||||
if (data.length === this.rawFileSize) {
|
||||
return;
|
||||
}
|
||||
@ -81,10 +83,10 @@ var DocumentProperties = {
|
||||
}.bind(this));
|
||||
|
||||
// Get the document properties.
|
||||
PDFView.pdfDocument.getMetadata().then(function(data) {
|
||||
this.pdfDocument.getMetadata().then(function(data) {
|
||||
var fields = [
|
||||
{ field: this.fileNameField,
|
||||
content: getPDFFileNameFromURL(PDFView.url) },
|
||||
content: getPDFFileNameFromURL(this.url) },
|
||||
{ field: this.fileSizeField, content: this.parseFileSize() },
|
||||
{ field: this.titleField, content: data.info.Title },
|
||||
{ field: this.authorField, content: data.info.Author },
|
||||
@ -97,7 +99,7 @@ var DocumentProperties = {
|
||||
{ field: this.creatorField, content: data.info.Creator },
|
||||
{ field: this.producerField, content: data.info.Producer },
|
||||
{ field: this.versionField, content: data.info.PDFFormatVersion },
|
||||
{ field: this.pageCountField, content: PDFView.pdfDocument.numPages }
|
||||
{ field: this.pageCountField, content: this.pdfDocument.numPages }
|
||||
];
|
||||
|
||||
// Show the properties in the dialog.
|
||||
|
81
web/interfaces.js
Normal file
81
web/interfaces.js
Normal file
@ -0,0 +1,81 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
function IPDFLinkService() {}
|
||||
IPDFLinkService.prototype = {
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get page() {},
|
||||
/**
|
||||
* @param {number} value
|
||||
*/
|
||||
set page(value) {},
|
||||
/**
|
||||
* @param dest - The PDF destination object.
|
||||
*/
|
||||
navigateTo: function (dest) {},
|
||||
/**
|
||||
* @param dest - The PDF destination object.
|
||||
* @returns {string} The hyperlink to the PDF object.
|
||||
*/
|
||||
getDestinationHash: function (dest) {},
|
||||
/**
|
||||
* @param hash - The PDF parameters/hash.
|
||||
* @returns {string} The hyperlink to the PDF object.
|
||||
*/
|
||||
getAnchorUrl: function (hash) {},
|
||||
/**
|
||||
* @param {string} hash
|
||||
*/
|
||||
setHash: function (hash) {},
|
||||
};
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
function IRenderableView() {}
|
||||
IRenderableView.prototype = {
|
||||
/**
|
||||
* @returns {string} - Unique ID for rendering queue.
|
||||
*/
|
||||
get renderingId() {},
|
||||
/**
|
||||
* @returns {RenderingStates}
|
||||
*/
|
||||
get renderingState() {},
|
||||
/**
|
||||
* @param {function} callback - The draw completion callback.
|
||||
*/
|
||||
draw: function (callback) {},
|
||||
resume: function () {},
|
||||
};
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
function ILastScrollSource() {}
|
||||
ILastScrollSource.prototype = {
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get lastScroll() {},
|
||||
};
|
160
web/page_view.js
160
web/page_view.js
@ -14,16 +14,31 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals RenderingStates, PDFView, PDFHistory, PDFJS, mozL10n, CustomStyle,
|
||||
PresentationMode, scrollIntoView, SCROLLBAR_PADDING, CSS_UNITS,
|
||||
UNKNOWN_SCALE, DEFAULT_SCALE, getOutputScale, TextLayerBuilder,
|
||||
cache, Stats */
|
||||
/* globals RenderingStates, PDFJS, mozL10n, CustomStyle,
|
||||
SCROLLBAR_PADDING, CSS_UNITS, UNKNOWN_SCALE, DEFAULT_SCALE,
|
||||
getOutputScale, scrollIntoView, Stats, PresentationModeState */
|
||||
|
||||
'use strict';
|
||||
|
||||
var PageView = function pageView(container, id, scale,
|
||||
navigateTo, defaultViewport) {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {HTMLDivElement} container - The viewer element.
|
||||
* @param {number} id - The page unique ID (normally its number).
|
||||
* @param {number} scale - The page scale display.
|
||||
* @param {PageViewport} defaultViewport - The page viewport.
|
||||
* @param {IPDFLinkService} linkService - The navigation/linking service.
|
||||
* @param {PDFRenderingQueue} renderingQueue - The rendering queue object.
|
||||
* @param {Cache} cache - The page cache.
|
||||
* @param {PDFPageSource} pageSource
|
||||
* @param {PDFViewer} viewer
|
||||
*
|
||||
* @implements {IRenderableView}
|
||||
*/
|
||||
var PageView = function pageView(container, id, scale, defaultViewport,
|
||||
linkService, renderingQueue, cache,
|
||||
pageSource, viewer) {
|
||||
this.id = id;
|
||||
this.renderingId = 'page' + id;
|
||||
|
||||
this.rotation = 0;
|
||||
this.scale = scale || 1.0;
|
||||
@ -31,6 +46,12 @@ var PageView = function pageView(container, id, scale,
|
||||
this.pdfPageRotate = defaultViewport.rotation;
|
||||
this.hasRestrictedScaling = false;
|
||||
|
||||
this.linkService = linkService;
|
||||
this.renderingQueue = renderingQueue;
|
||||
this.cache = cache;
|
||||
this.pageSource = pageSource;
|
||||
this.viewer = viewer;
|
||||
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.resume = null;
|
||||
|
||||
@ -241,10 +262,10 @@ var PageView = function pageView(container, id, scale,
|
||||
function setupAnnotations(pageDiv, pdfPage, viewport) {
|
||||
|
||||
function bindLink(link, dest) {
|
||||
link.href = PDFView.getDestinationHash(dest);
|
||||
link.href = linkService.getDestinationHash(dest);
|
||||
link.onclick = function pageViewSetupLinksOnclick() {
|
||||
if (dest) {
|
||||
PDFView.navigateTo(dest);
|
||||
linkService.navigateTo(dest);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@ -254,47 +275,9 @@ var PageView = function pageView(container, id, scale,
|
||||
}
|
||||
|
||||
function bindNamedAction(link, action) {
|
||||
link.href = PDFView.getAnchorUrl('');
|
||||
link.href = linkService.getAnchorUrl('');
|
||||
link.onclick = function pageViewSetupNamedActionOnClick() {
|
||||
// See PDF reference, table 8.45 - Named action
|
||||
switch (action) {
|
||||
case 'GoToPage':
|
||||
document.getElementById('pageNumber').focus();
|
||||
break;
|
||||
|
||||
case 'GoBack':
|
||||
PDFHistory.back();
|
||||
break;
|
||||
|
||||
case 'GoForward':
|
||||
PDFHistory.forward();
|
||||
break;
|
||||
|
||||
case 'Find':
|
||||
if (!PDFView.supportsIntegratedFind) {
|
||||
PDFView.findBar.toggle();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'NextPage':
|
||||
PDFView.page++;
|
||||
break;
|
||||
|
||||
case 'PrevPage':
|
||||
PDFView.page--;
|
||||
break;
|
||||
|
||||
case 'LastPage':
|
||||
PDFView.page = PDFView.pages.length;
|
||||
break;
|
||||
|
||||
case 'FirstPage':
|
||||
PDFView.page = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break; // No action according to spec
|
||||
}
|
||||
linkService.executeNamedAction(action);
|
||||
return false;
|
||||
};
|
||||
link.className = 'internalLink';
|
||||
@ -376,14 +359,16 @@ var PageView = function pageView(container, id, scale,
|
||||
};
|
||||
|
||||
this.scrollIntoView = function pageViewScrollIntoView(dest) {
|
||||
if (PresentationMode.active) {
|
||||
if (PDFView.page !== this.id) {
|
||||
// Avoid breaking PDFView.getVisiblePages in presentation mode.
|
||||
PDFView.page = this.id;
|
||||
if (this.viewer.presentationModeState ===
|
||||
PresentationModeState.FULLSCREEN) {
|
||||
if (this.linkService.page !== this.id) {
|
||||
// Avoid breaking getVisiblePages in presentation mode.
|
||||
this.linkService.page = this.id;
|
||||
return;
|
||||
}
|
||||
dest = null;
|
||||
PDFView.setScale(PDFView.currentScaleValue, true, true);
|
||||
// Fixes the case when PDF has different page sizes.
|
||||
this.viewer.currentScaleValue = this.viewer.currentScaleValue;
|
||||
}
|
||||
if (!dest) {
|
||||
scrollIntoView(div);
|
||||
@ -431,9 +416,10 @@ var PageView = function pageView(container, id, scale,
|
||||
y = dest[3];
|
||||
width = dest[4] - x;
|
||||
height = dest[5] - y;
|
||||
widthScale = (PDFView.container.clientWidth - SCROLLBAR_PADDING) /
|
||||
var viewerContainer = this.viewer.container;
|
||||
widthScale = (viewerContainer.clientWidth - SCROLLBAR_PADDING) /
|
||||
width / CSS_UNITS;
|
||||
heightScale = (PDFView.container.clientHeight - SCROLLBAR_PADDING) /
|
||||
heightScale = (viewerContainer.clientHeight - SCROLLBAR_PADDING) /
|
||||
height / CSS_UNITS;
|
||||
scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
|
||||
break;
|
||||
@ -441,10 +427,10 @@ var PageView = function pageView(container, id, scale,
|
||||
return;
|
||||
}
|
||||
|
||||
if (scale && scale !== PDFView.currentScale) {
|
||||
PDFView.setScale(scale, true, true);
|
||||
} else if (PDFView.currentScale === UNKNOWN_SCALE) {
|
||||
PDFView.setScale(DEFAULT_SCALE, true, true);
|
||||
if (scale && scale !== this.viewer.currentScale) {
|
||||
this.viewer.currentScaleValue = scale;
|
||||
} else if (this.viewer.currentScale === UNKNOWN_SCALE) {
|
||||
this.viewer.currentScaleValue = DEFAULT_SCALE;
|
||||
}
|
||||
|
||||
if (scale === 'page-fit' && !dest[4]) {
|
||||
@ -462,12 +448,6 @@ var PageView = function pageView(container, id, scale,
|
||||
scrollIntoView(div, { left: left, top: top });
|
||||
};
|
||||
|
||||
this.getTextContent = function pageviewGetTextContent() {
|
||||
return PDFView.getPage(this.id).then(function(pdfPage) {
|
||||
return pdfPage.getTextContent();
|
||||
});
|
||||
};
|
||||
|
||||
this.draw = function pageviewDraw(callback) {
|
||||
var pdfPage = this.pdfPage;
|
||||
|
||||
@ -475,7 +455,7 @@ var PageView = function pageView(container, id, scale,
|
||||
return;
|
||||
}
|
||||
if (!pdfPage) {
|
||||
var promise = PDFView.getPage(this.id);
|
||||
var promise = this.pageSource.getPage();
|
||||
promise.then(function(pdfPage) {
|
||||
delete this.pagePdfPromise;
|
||||
this.setPdfPage(pdfPage);
|
||||
@ -543,6 +523,7 @@ var PageView = function pageView(container, id, scale,
|
||||
canvas._viewport = viewport;
|
||||
|
||||
var textLayerDiv = null;
|
||||
var textLayer = null;
|
||||
if (!PDFJS.disableTextLayer) {
|
||||
textLayerDiv = document.createElement('div');
|
||||
textLayerDiv.className = 'textLayer';
|
||||
@ -554,16 +535,12 @@ var PageView = function pageView(container, id, scale,
|
||||
} else {
|
||||
div.appendChild(textLayerDiv);
|
||||
}
|
||||
|
||||
textLayer = this.viewer.createTextLayerBuilder(textLayerDiv, this.id - 1,
|
||||
this.viewport);
|
||||
}
|
||||
var textLayer = this.textLayer =
|
||||
textLayerDiv ? new TextLayerBuilder({
|
||||
textLayerDiv: textLayerDiv,
|
||||
pageIndex: this.id - 1,
|
||||
lastScrollSource: PDFView,
|
||||
viewport: this.viewport,
|
||||
isViewerInPresentationMode: PresentationMode.active,
|
||||
findController: PDFView.findController
|
||||
}) : null;
|
||||
this.textLayer = textLayer;
|
||||
|
||||
// TODO(mack): use data attributes to store these
|
||||
ctx._scaleX = outputScale.sx;
|
||||
ctx._scaleY = outputScale.sy;
|
||||
@ -598,22 +575,7 @@ var PageView = function pageView(container, id, scale,
|
||||
self.zoomLayer = null;
|
||||
}
|
||||
|
||||
//#if (FIREFOX || MOZCENTRAL)
|
||||
// if (self.textLayer && self.textLayer.textDivs &&
|
||||
// self.textLayer.textDivs.length > 0 &&
|
||||
// !PDFView.supportsDocumentColors) {
|
||||
// console.error(mozL10n.get('document_colors_disabled', null,
|
||||
// 'PDF documents are not allowed to use their own colors: ' +
|
||||
// '\'Allow pages to choose their own colors\' ' +
|
||||
// 'is deactivated in the browser.'));
|
||||
// PDFView.fallback();
|
||||
// }
|
||||
//#endif
|
||||
if (error) {
|
||||
PDFView.error(mozL10n.get('rendering_error', null,
|
||||
'An error occurred while rendering the page.'), error);
|
||||
}
|
||||
|
||||
self.error = error;
|
||||
self.stats = pdfPage.stats;
|
||||
self.updateStats();
|
||||
if (self.onAfterDraw) {
|
||||
@ -626,18 +588,6 @@ var PageView = function pageView(container, id, scale,
|
||||
});
|
||||
div.dispatchEvent(event);
|
||||
|
||||
//#if (FIREFOX || MOZCENTRAL)
|
||||
// FirefoxCom.request('reportTelemetry', JSON.stringify({
|
||||
// type: 'pageInfo'
|
||||
// }));
|
||||
// // It is a good time to report stream and font types
|
||||
// PDFView.pdfDocument.getStats().then(function (stats) {
|
||||
// FirefoxCom.request('reportTelemetry', JSON.stringify({
|
||||
// type: 'documentStats',
|
||||
// stats: stats
|
||||
// }));
|
||||
// });
|
||||
//#endif
|
||||
callback();
|
||||
}
|
||||
|
||||
@ -646,7 +596,7 @@ var PageView = function pageView(container, id, scale,
|
||||
viewport: this.viewport,
|
||||
// intent: 'default', // === 'display'
|
||||
continueCallback: function pdfViewcContinueCallback(cont) {
|
||||
if (PDFView.highestPriorityPage !== 'page' + self.id) {
|
||||
if (!self.renderingQueue.isHighestPriority(self)) {
|
||||
self.renderingState = RenderingStates.PAUSED;
|
||||
self.resume = function resumeCallback() {
|
||||
self.renderingState = RenderingStates.RUNNING;
|
||||
@ -663,7 +613,7 @@ var PageView = function pageView(container, id, scale,
|
||||
function pdfPageRenderCallback() {
|
||||
pageViewDrawCallback(null);
|
||||
if (textLayer) {
|
||||
self.getTextContent().then(
|
||||
self.pdfPage.getTextContent().then(
|
||||
function textContentResolved(textContent) {
|
||||
textLayer.setTextContent(textContent);
|
||||
}
|
||||
|
@ -13,10 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, FindStates, FirefoxCom, Promise */
|
||||
/* globals PDFJS, FirefoxCom, Promise */
|
||||
|
||||
'use strict';
|
||||
|
||||
var FindStates = {
|
||||
FIND_FOUND: 0,
|
||||
FIND_NOTFOUND: 1,
|
||||
FIND_WRAPPED: 2,
|
||||
FIND_PENDING: 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides "search" or "find" functionality for the PDF.
|
||||
* This object actually performs the search for a given string.
|
||||
@ -41,7 +48,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
this.state = null;
|
||||
this.dirtyMatch = false;
|
||||
this.findTimeout = null;
|
||||
this.pdfPageSource = options.pdfPageSource || null;
|
||||
this.pdfViewer = options.pdfViewer || null;
|
||||
this.integratedFind = options.integratedFind || false;
|
||||
this.charactersToNormalize = {
|
||||
'\u2018': '\'', // Left single quotation mark
|
||||
@ -137,7 +144,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
|
||||
this.pageContents = [];
|
||||
var extractTextPromisesResolves = [];
|
||||
var numPages = this.pdfPageSource.pdfDocument.numPages;
|
||||
var numPages = this.pdfViewer.pagesCount;
|
||||
for (var i = 0; i < numPages; i++) {
|
||||
this.extractTextPromises.push(new Promise(function (resolve) {
|
||||
extractTextPromisesResolves.push(resolve);
|
||||
@ -146,7 +153,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
|
||||
var self = this;
|
||||
function extractPageText(pageIndex) {
|
||||
self.pdfPageSource.pages[pageIndex].getTextContent().then(
|
||||
self.pdfViewer.getPageTextContent(pageIndex).then(
|
||||
function textContentResolved(textContent) {
|
||||
var textItems = textContent.items;
|
||||
var str = [];
|
||||
@ -159,7 +166,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
self.pageContents.push(str.join(''));
|
||||
|
||||
extractTextPromisesResolves[pageIndex](pageIndex);
|
||||
if ((pageIndex + 1) < self.pdfPageSource.pages.length) {
|
||||
if ((pageIndex + 1) < self.pdfViewer.pagesCount) {
|
||||
extractPageText(pageIndex + 1);
|
||||
}
|
||||
}
|
||||
@ -189,7 +196,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
},
|
||||
|
||||
updatePage: function PDFFindController_updatePage(index) {
|
||||
var page = this.pdfPageSource.pages[index];
|
||||
var page = this.pdfViewer.getPageView(index);
|
||||
|
||||
if (this.selected.pageIdx === index) {
|
||||
// If the page is selected, scroll the page into view, which triggers
|
||||
@ -205,8 +212,8 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
|
||||
nextMatch: function PDFFindController_nextMatch() {
|
||||
var previous = this.state.findPrevious;
|
||||
var currentPageIndex = this.pdfPageSource.page - 1;
|
||||
var numPages = this.pdfPageSource.pages.length;
|
||||
var currentPageIndex = this.pdfViewer.currentPageNumber - 1;
|
||||
var numPages = this.pdfViewer.pagesCount;
|
||||
|
||||
this.active = true;
|
||||
|
||||
@ -346,7 +353,7 @@ var PDFFindController = (function PDFFindControllerClosure() {
|
||||
|
||||
this.updateUIState(state, this.state.findPrevious);
|
||||
if (this.selected.pageIdx !== -1) {
|
||||
this.updatePage(this.selected.pageIdx, true);
|
||||
this.updatePage(this.selected.pageIdx);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFJS, PDFView, PresentationMode */
|
||||
/* globals PDFJS, PresentationMode */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -22,12 +22,11 @@ var PDFHistory = {
|
||||
initialized: false,
|
||||
initialDestination: null,
|
||||
|
||||
initialize: function pdfHistoryInitialize(fingerprint) {
|
||||
if (PDFJS.disableHistory || PDFView.isViewerEmbedded) {
|
||||
// The browsing history is only enabled when the viewer is standalone,
|
||||
// i.e. not when it is embedded in a web page.
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* @param {string} fingerprint
|
||||
* @param {IPDFLinkService} linkService
|
||||
*/
|
||||
initialize: function pdfHistoryInitialize(fingerprint, linkService) {
|
||||
this.initialized = true;
|
||||
this.reInitialized = false;
|
||||
this.allowHashChange = true;
|
||||
@ -42,6 +41,7 @@ var PDFHistory = {
|
||||
this.nextHashParam = '';
|
||||
|
||||
this.fingerprint = fingerprint;
|
||||
this.linkService = linkService;
|
||||
this.currentUid = this.uid = 0;
|
||||
this.current = {};
|
||||
|
||||
@ -52,7 +52,7 @@ var PDFHistory = {
|
||||
if (state.target.dest) {
|
||||
this.initialDestination = state.target.dest;
|
||||
} else {
|
||||
PDFView.initialBookmark = state.target.hash;
|
||||
linkService.setHash(state.target.hash);
|
||||
}
|
||||
this.currentUid = state.uid;
|
||||
this.uid = state.uid + 1;
|
||||
@ -203,7 +203,7 @@ var PDFHistory = {
|
||||
params.hash = (this.current.hash && this.current.dest &&
|
||||
this.current.dest === params.dest) ?
|
||||
this.current.hash :
|
||||
PDFView.getDestinationHash(params.dest).split('#')[1];
|
||||
this.linkService.getDestinationHash(params.dest).split('#')[1];
|
||||
}
|
||||
if (params.page) {
|
||||
params.page |= 0;
|
||||
@ -212,7 +212,7 @@ var PDFHistory = {
|
||||
var target = window.history.state.target;
|
||||
if (!target) {
|
||||
// Invoked when the user specifies an initial bookmark,
|
||||
// thus setting PDFView.initialBookmark, when the document is loaded.
|
||||
// thus setting initialBookmark, when the document is loaded.
|
||||
this._pushToHistory(params, false);
|
||||
this.previousHash = window.location.hash.substring(1);
|
||||
}
|
||||
@ -337,9 +337,9 @@ var PDFHistory = {
|
||||
this.historyUnlocked = false;
|
||||
|
||||
if (state.target.dest) {
|
||||
PDFView.navigateTo(state.target.dest);
|
||||
this.linkService.navigateTo(state.target.dest);
|
||||
} else {
|
||||
PDFView.setHash(state.target.hash);
|
||||
this.linkService.setHash(state.target.hash);
|
||||
}
|
||||
this.currentUid = state.uid;
|
||||
if (state.uid > this.uid) {
|
||||
|
176
web/pdf_rendering_queue.js
Normal file
176
web/pdf_rendering_queue.js
Normal file
@ -0,0 +1,176 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var CLEANUP_TIMEOUT = 30000;
|
||||
|
||||
var RenderingStates = {
|
||||
INITIAL: 0,
|
||||
RUNNING: 1,
|
||||
PAUSED: 2,
|
||||
FINISHED: 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Controls rendering of the views for pages and thumbnails.
|
||||
* @class
|
||||
*/
|
||||
var PDFRenderingQueue = (function PDFRenderingQueueClosure() {
|
||||
/**
|
||||
* @constructs
|
||||
*/
|
||||
function PDFRenderingQueue() {
|
||||
this.pdfViewer = null;
|
||||
this.pdfThumbnailViewer = null;
|
||||
this.onIdle = null;
|
||||
|
||||
this.highestPriorityPage = null;
|
||||
this.idleTimeout = null;
|
||||
this.printing = false;
|
||||
this.isThumbnailViewEnabled = false;
|
||||
}
|
||||
|
||||
PDFRenderingQueue.prototype = /** @lends PDFRenderingQueue.prototype */ {
|
||||
/**
|
||||
* @param {PDFViewer} pdfViewer
|
||||
*/
|
||||
setViewer: function PDFRenderingQueue_setViewer(pdfViewer) {
|
||||
this.pdfViewer = pdfViewer;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {PDFThumbnailViewer} pdfThumbnailViewer
|
||||
*/
|
||||
setThumbnailViewer:
|
||||
function PDFRenderingQueue_setThumbnailViewer(pdfThumbnailViewer) {
|
||||
this.pdfThumbnailViewer = pdfThumbnailViewer;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {IRenderableView} view
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isHighestPriority: function PDFRenderingQueue_isHighestPriority(view) {
|
||||
return this.highestPriorityPage === view.renderingId;
|
||||
},
|
||||
|
||||
renderHighestPriority: function
|
||||
PDFRenderingQueue_renderHighestPriority(currentlyVisiblePages) {
|
||||
if (this.idleTimeout) {
|
||||
clearTimeout(this.idleTimeout);
|
||||
this.idleTimeout = null;
|
||||
}
|
||||
|
||||
// Pages have a higher priority than thumbnails, so check them first.
|
||||
if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {
|
||||
return;
|
||||
}
|
||||
// No pages needed rendering so check thumbnails.
|
||||
if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) {
|
||||
if (this.pdfThumbnailViewer.forceRendering()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.printing) {
|
||||
// If printing is currently ongoing do not reschedule cleanup.
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.onIdle) {
|
||||
this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);
|
||||
}
|
||||
},
|
||||
|
||||
getHighestPriority: function
|
||||
PDFRenderingQueue_getHighestPriority(visible, views, scrolledDown) {
|
||||
// The state has changed figure out which page has the highest priority to
|
||||
// render next (if any).
|
||||
// Priority:
|
||||
// 1 visible pages
|
||||
// 2 if last scrolled down page after the visible pages
|
||||
// 2 if last scrolled up page before the visible pages
|
||||
var visibleViews = visible.views;
|
||||
|
||||
var numVisible = visibleViews.length;
|
||||
if (numVisible === 0) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < numVisible; ++i) {
|
||||
var view = visibleViews[i].view;
|
||||
if (!this.isViewFinished(view)) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
// All the visible views have rendered, try to render next/previous pages.
|
||||
if (scrolledDown) {
|
||||
var nextPageIndex = visible.last.id;
|
||||
// ID's start at 1 so no need to add 1.
|
||||
if (views[nextPageIndex] &&
|
||||
!this.isViewFinished(views[nextPageIndex])) {
|
||||
return views[nextPageIndex];
|
||||
}
|
||||
} else {
|
||||
var previousPageIndex = visible.first.id - 2;
|
||||
if (views[previousPageIndex] &&
|
||||
!this.isViewFinished(views[previousPageIndex])) {
|
||||
return views[previousPageIndex];
|
||||
}
|
||||
}
|
||||
// Everything that needs to be rendered has been.
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {IRenderableView} view
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isViewFinished: function PDFRenderingQueue_isViewFinished(view) {
|
||||
return view.renderingState === RenderingStates.FINISHED;
|
||||
},
|
||||
|
||||
/**
|
||||
* Render a page or thumbnail view. This calls the appropriate function
|
||||
* based on the views state. If the view is already rendered it will return
|
||||
* false.
|
||||
* @param {IRenderableView} view
|
||||
*/
|
||||
renderView: function PDFRenderingQueue_renderView(view) {
|
||||
var state = view.renderingState;
|
||||
switch (state) {
|
||||
case RenderingStates.FINISHED:
|
||||
return false;
|
||||
case RenderingStates.PAUSED:
|
||||
this.highestPriorityPage = view.renderingId;
|
||||
view.resume();
|
||||
break;
|
||||
case RenderingStates.RUNNING:
|
||||
this.highestPriorityPage = view.renderingId;
|
||||
break;
|
||||
case RenderingStates.INITIAL:
|
||||
this.highestPriorityPage = view.renderingId;
|
||||
view.draw(this.renderHighestPriority.bind(this));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
return PDFRenderingQueue;
|
||||
})();
|
571
web/pdf_viewer.js
Normal file
571
web/pdf_viewer.js
Normal file
@ -0,0 +1,571 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PageView, UNKNOWN_SCALE,
|
||||
SCROLLBAR_PADDING, VERTICAL_PADDING, MAX_AUTO_SCALE, CSS_UNITS,
|
||||
getVisibleElements, RenderingStates, Promise,
|
||||
PDFJS, TextLayerBuilder, PDFRenderingQueue */
|
||||
|
||||
'use strict';
|
||||
|
||||
var PresentationModeState = {
|
||||
UNKNOWN: 0,
|
||||
NORMAL: 1,
|
||||
CHANGING: 2,
|
||||
FULLSCREEN: 3,
|
||||
};
|
||||
|
||||
var IGNORE_CURRENT_POSITION_ON_ZOOM = false;
|
||||
|
||||
//#include pdf_rendering_queue.js
|
||||
//#include page_view.js
|
||||
//#include text_layer_builder.js
|
||||
|
||||
/**
|
||||
* @typedef {Object} PDFViewerOptions
|
||||
* @property {HTMLDivElement} container - The container for the viewer element.
|
||||
* @property {HTMLDivElement} viewer - (optional) The viewer element.
|
||||
* @property {IPDFLinkService} linkService - The navigation/linking service.
|
||||
* @property {PDFRenderingQueue} renderingQueue - (optional) The rendering
|
||||
* queue object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple viewer control to display PDF content/pages.
|
||||
* @class
|
||||
* @implements {ILastScrollSource}
|
||||
* @implements {IRenderableView}
|
||||
*/
|
||||
var PDFViewer = (function pdfViewer() {
|
||||
/**
|
||||
* @constructs PDFViewer
|
||||
* @param {PDFViewerOptions} options
|
||||
*/
|
||||
function PDFViewer(options) {
|
||||
this.container = options.container;
|
||||
this.viewer = options.viewer || options.container.firstElementChild;
|
||||
this.linkService = options.linkService;
|
||||
|
||||
this.defaultRenderingQueue = !options.renderingQueue;
|
||||
if (this.defaultRenderingQueue) {
|
||||
// Custom rendering queue is not specified, using default one
|
||||
this.renderingQueue = new PDFRenderingQueue();
|
||||
this.renderingQueue.setViewer(this);
|
||||
} else {
|
||||
this.renderingQueue = options.renderingQueue;
|
||||
}
|
||||
|
||||
this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this));
|
||||
this.lastScroll = 0;
|
||||
this.updateInProgress = false;
|
||||
this.presentationModeState = PresentationModeState.UNKNOWN;
|
||||
this._resetView();
|
||||
}
|
||||
|
||||
PDFViewer.prototype = /** @lends PDFViewer.prototype */{
|
||||
get pagesCount() {
|
||||
return this.pages.length;
|
||||
},
|
||||
|
||||
getPageView: function (index) {
|
||||
return this.pages[index];
|
||||
},
|
||||
|
||||
get currentPageNumber() {
|
||||
return this._currentPageNumber;
|
||||
},
|
||||
|
||||
set currentPageNumber(val) {
|
||||
if (!this.pdfDocument) {
|
||||
this._currentPageNumber = val;
|
||||
return;
|
||||
}
|
||||
|
||||
var event = document.createEvent('UIEvents');
|
||||
event.initUIEvent('pagechange', true, true, window, 0);
|
||||
event.updateInProgress = this.updateInProgress;
|
||||
|
||||
if (!(0 < val && val <= this.pagesCount)) {
|
||||
event.pageNumber = this.page;
|
||||
event.previousPageNumber = val;
|
||||
this.container.dispatchEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
this.pages[val - 1].updateStats();
|
||||
event.previousPageNumber = this._currentPageNumber;
|
||||
this._currentPageNumber = val;
|
||||
event.pageNumber = val;
|
||||
this.container.dispatchEvent(event);
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get currentScale() {
|
||||
return this._currentScale;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} val - Scale of the pages in percents.
|
||||
*/
|
||||
set currentScale(val) {
|
||||
if (isNaN(val)) {
|
||||
throw new Error('Invalid numeric scale');
|
||||
}
|
||||
if (!this.pdfDocument) {
|
||||
this._currentScale = val;
|
||||
this._currentScaleValue = val.toString();
|
||||
return;
|
||||
}
|
||||
this._setScale(val, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
get currentScaleValue() {
|
||||
return this._currentScaleValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param val - The scale of the pages (in percent or predefined value).
|
||||
*/
|
||||
set currentScaleValue(val) {
|
||||
if (!this.pdfDocument) {
|
||||
this._currentScale = isNaN(val) ? UNKNOWN_SCALE : val;
|
||||
this._currentScaleValue = val;
|
||||
return;
|
||||
}
|
||||
this._setScale(val, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get pagesRotation() {
|
||||
return this._pagesRotation;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} rotation - The rotation of the pages (0, 90, 180, 270).
|
||||
*/
|
||||
set pagesRotation(rotation) {
|
||||
this._pagesRotation = rotation;
|
||||
|
||||
for (var i = 0, l = this.pages.length; i < l; i++) {
|
||||
var page = this.pages[i];
|
||||
page.update(page.scale, rotation);
|
||||
}
|
||||
|
||||
this._setScale(this._currentScaleValue, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param pdfDocument {PDFDocument}
|
||||
*/
|
||||
setDocument: function (pdfDocument) {
|
||||
if (this.pdfDocument) {
|
||||
this._resetView();
|
||||
}
|
||||
|
||||
this.pdfDocument = pdfDocument;
|
||||
if (!pdfDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pagesCount = pdfDocument.numPages;
|
||||
var pagesRefMap = this.pagesRefMap = {};
|
||||
var self = this;
|
||||
|
||||
var resolvePagesPromise;
|
||||
var pagesPromise = new Promise(function (resolve) {
|
||||
resolvePagesPromise = resolve;
|
||||
});
|
||||
this.pagesPromise = pagesPromise;
|
||||
pagesPromise.then(function () {
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('pagesloaded', true, true, {
|
||||
pagesCount: pagesCount
|
||||
});
|
||||
self.container.dispatchEvent(event);
|
||||
});
|
||||
|
||||
var isOnePageRenderedResolved = false;
|
||||
var resolveOnePageRendered = null;
|
||||
var onePageRendered = new Promise(function (resolve) {
|
||||
resolveOnePageRendered = resolve;
|
||||
});
|
||||
this.onePageRendered = onePageRendered;
|
||||
|
||||
var bindOnAfterDraw = function (pageView) {
|
||||
// when page is painted, using the image as thumbnail base
|
||||
pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
|
||||
if (!isOnePageRenderedResolved) {
|
||||
isOnePageRenderedResolved = true;
|
||||
resolveOnePageRendered();
|
||||
}
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('pagerendered', true, true, {
|
||||
pageNumber: pageView.id
|
||||
});
|
||||
self.container.dispatchEvent(event);
|
||||
};
|
||||
};
|
||||
|
||||
var firstPagePromise = pdfDocument.getPage(1);
|
||||
this.firstPagePromise = firstPagePromise;
|
||||
|
||||
// Fetch a single page so we can get a viewport that will be the default
|
||||
// viewport for all pages
|
||||
return firstPagePromise.then(function(pdfPage) {
|
||||
var scale = this._currentScale || 1.0;
|
||||
var viewport = pdfPage.getViewport(scale * CSS_UNITS);
|
||||
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
|
||||
var pageSource = new PDFPageSource(pdfDocument, pageNum);
|
||||
var pageView = new PageView(this.viewer, pageNum, scale,
|
||||
viewport.clone(), this.linkService,
|
||||
this.renderingQueue, this.cache,
|
||||
pageSource, this);
|
||||
bindOnAfterDraw(pageView);
|
||||
this.pages.push(pageView);
|
||||
}
|
||||
|
||||
// Fetch all the pages since the viewport is needed before printing
|
||||
// starts to create the correct size canvas. Wait until one page is
|
||||
// rendered so we don't tie up too many resources early on.
|
||||
onePageRendered.then(function () {
|
||||
if (!PDFJS.disableAutoFetch) {
|
||||
var getPagesLeft = pagesCount;
|
||||
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
|
||||
pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) {
|
||||
var pageView = self.pages[pageNum - 1];
|
||||
if (!pageView.pdfPage) {
|
||||
pageView.setPdfPage(pdfPage);
|
||||
}
|
||||
var refStr = pdfPage.ref.num + ' ' + pdfPage.ref.gen + ' R';
|
||||
pagesRefMap[refStr] = pageNum;
|
||||
getPagesLeft--;
|
||||
if (!getPagesLeft) {
|
||||
resolvePagesPromise();
|
||||
}
|
||||
}.bind(null, pageNum));
|
||||
}
|
||||
} else {
|
||||
// XXX: Printing is semi-broken with auto fetch disabled.
|
||||
resolvePagesPromise();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.defaultRenderingQueue) {
|
||||
firstPagePromise.then(this.update.bind(this));
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_resetView: function () {
|
||||
this.cache = new Cache(DEFAULT_CACHE_SIZE);
|
||||
this.pages = [];
|
||||
this._currentPageNumber = 1;
|
||||
this._currentScale = UNKNOWN_SCALE;
|
||||
this._currentScaleValue = null;
|
||||
this.location = null;
|
||||
this._pagesRotation = 0;
|
||||
|
||||
var container = this.viewer;
|
||||
while (container.hasChildNodes()) {
|
||||
container.removeChild(container.lastChild);
|
||||
}
|
||||
},
|
||||
|
||||
_scrollUpdate: function () {
|
||||
this.lastScroll = Date.now();
|
||||
|
||||
if (this.pagesCount === 0) {
|
||||
return;
|
||||
}
|
||||
this.update();
|
||||
},
|
||||
|
||||
_setScaleUpdatePages: function pdfViewer_setScaleUpdatePages(
|
||||
newScale, newValue, noScroll, preset) {
|
||||
this._currentScaleValue = newValue;
|
||||
if (newScale === this._currentScale) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0, ii = this.pages.length; i < ii; i++) {
|
||||
this.pages[i].update(newScale);
|
||||
}
|
||||
this._currentScale = newScale;
|
||||
|
||||
if (!noScroll) {
|
||||
var page = this._currentPageNumber, dest;
|
||||
var inPresentationMode =
|
||||
this.presentationModeState === PresentationModeState.CHANGING ||
|
||||
this.presentationModeState === PresentationModeState.FULLSCREEN;
|
||||
if (this.location && !inPresentationMode &&
|
||||
!IGNORE_CURRENT_POSITION_ON_ZOOM) {
|
||||
page = this.location.pageNumber;
|
||||
dest = [null, { name: 'XYZ' }, this.location.left,
|
||||
this.location.top, null];
|
||||
}
|
||||
this.pages[page - 1].scrollIntoView(dest);
|
||||
}
|
||||
|
||||
var event = document.createEvent('UIEvents');
|
||||
event.initUIEvent('scalechange', true, true, window, 0);
|
||||
event.scale = newScale;
|
||||
if (preset) {
|
||||
event.presetValue = newValue;
|
||||
}
|
||||
this.container.dispatchEvent(event);
|
||||
},
|
||||
|
||||
_setScale: function pdfViewer_setScale(value, noScroll) {
|
||||
if (value === 'custom') {
|
||||
return;
|
||||
}
|
||||
var scale = parseFloat(value);
|
||||
|
||||
if (scale > 0) {
|
||||
this._setScaleUpdatePages(scale, value, noScroll, false);
|
||||
} else {
|
||||
var currentPage = this.pages[this._currentPageNumber - 1];
|
||||
if (!currentPage) {
|
||||
return;
|
||||
}
|
||||
var inPresentationMode =
|
||||
this.presentationModeState === PresentationModeState.FULLSCREEN;
|
||||
var hPadding = inPresentationMode ? 0 : SCROLLBAR_PADDING;
|
||||
var vPadding = inPresentationMode ? 0 : VERTICAL_PADDING;
|
||||
var pageWidthScale = (this.container.clientWidth - hPadding) /
|
||||
currentPage.width * currentPage.scale;
|
||||
var pageHeightScale = (this.container.clientHeight - vPadding) /
|
||||
currentPage.height * currentPage.scale;
|
||||
switch (value) {
|
||||
case 'page-actual':
|
||||
scale = 1;
|
||||
break;
|
||||
case 'page-width':
|
||||
scale = pageWidthScale;
|
||||
break;
|
||||
case 'page-height':
|
||||
scale = pageHeightScale;
|
||||
break;
|
||||
case 'page-fit':
|
||||
scale = Math.min(pageWidthScale, pageHeightScale);
|
||||
break;
|
||||
case 'auto':
|
||||
var isLandscape = (currentPage.width > currentPage.height);
|
||||
var horizontalScale = isLandscape ? pageHeightScale :
|
||||
pageWidthScale;
|
||||
scale = Math.min(MAX_AUTO_SCALE, horizontalScale);
|
||||
break;
|
||||
default:
|
||||
console.error('pdfViewSetScale: \'' + value +
|
||||
'\' is an unknown zoom value.');
|
||||
return;
|
||||
}
|
||||
this._setScaleUpdatePages(scale, value, noScroll, true);
|
||||
}
|
||||
},
|
||||
|
||||
_updateLocation: function (firstPage) {
|
||||
var currentScale = this._currentScale;
|
||||
var currentScaleValue = this._currentScaleValue;
|
||||
var normalizedScaleValue =
|
||||
parseFloat(currentScaleValue) === currentScale ?
|
||||
Math.round(currentScale * 10000) / 100 : currentScaleValue;
|
||||
|
||||
var pageNumber = firstPage.id;
|
||||
var pdfOpenParams = '#page=' + pageNumber;
|
||||
pdfOpenParams += '&zoom=' + normalizedScaleValue;
|
||||
var currentPageView = this.pages[pageNumber - 1];
|
||||
var container = this.container;
|
||||
var topLeft = currentPageView.getPagePoint(
|
||||
(container.scrollLeft - firstPage.x),
|
||||
(container.scrollTop - firstPage.y));
|
||||
var intLeft = Math.round(topLeft[0]);
|
||||
var intTop = Math.round(topLeft[1]);
|
||||
pdfOpenParams += ',' + intLeft + ',' + intTop;
|
||||
|
||||
this.location = {
|
||||
pageNumber: pageNumber,
|
||||
scale: normalizedScaleValue,
|
||||
top: intTop,
|
||||
left: intLeft,
|
||||
pdfOpenParams: pdfOpenParams
|
||||
};
|
||||
},
|
||||
|
||||
update: function () {
|
||||
var visible = this._getVisiblePages();
|
||||
var visiblePages = visible.views;
|
||||
if (visiblePages.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateInProgress = true;
|
||||
|
||||
var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE,
|
||||
2 * visiblePages.length + 1);
|
||||
this.cache.resize(suggestedCacheSize);
|
||||
|
||||
this.renderingQueue.renderHighestPriority(visible);
|
||||
|
||||
var currentId = this.currentPageNumber;
|
||||
var firstPage = visible.first;
|
||||
|
||||
for (var i = 0, ii = visiblePages.length, stillFullyVisible = false;
|
||||
i < ii; ++i) {
|
||||
var page = visiblePages[i];
|
||||
|
||||
if (page.percent < 100) {
|
||||
break;
|
||||
}
|
||||
if (page.id === currentId) {
|
||||
stillFullyVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stillFullyVisible) {
|
||||
currentId = visiblePages[0].id;
|
||||
}
|
||||
|
||||
if (this.presentationModeState !== PresentationModeState.FULLSCREEN) {
|
||||
this.currentPageNumber = currentId;
|
||||
}
|
||||
|
||||
this._updateLocation(firstPage);
|
||||
|
||||
this.updateInProgress = false;
|
||||
|
||||
var event = document.createEvent('UIEvents');
|
||||
event.initUIEvent('updateviewarea', true, true, window, 0);
|
||||
this.container.dispatchEvent(event);
|
||||
},
|
||||
|
||||
containsElement: function (element) {
|
||||
return this.container.contains(element);
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
this.container.focus();
|
||||
},
|
||||
|
||||
blur: function () {
|
||||
this.container.blur();
|
||||
},
|
||||
|
||||
get isHorizontalScrollbarEnabled() {
|
||||
return (this.presentationModeState === PresentationModeState.FULLSCREEN ?
|
||||
false : (this.container.scrollWidth > this.container.clientWidth));
|
||||
},
|
||||
|
||||
_getVisiblePages: function () {
|
||||
if (this.presentationModeState !== PresentationModeState.FULLSCREEN) {
|
||||
return getVisibleElements(this.container, this.pages, true);
|
||||
} else {
|
||||
// The algorithm in getVisibleElements doesn't work in all browsers and
|
||||
// configurations when presentation mode is active.
|
||||
var visible = [];
|
||||
var currentPage = this.pages[this._currentPageNumber - 1];
|
||||
visible.push({ id: currentPage.id, view: currentPage });
|
||||
return { first: currentPage, last: currentPage, views: visible };
|
||||
}
|
||||
},
|
||||
|
||||
cleanup: function () {
|
||||
for (var i = 0, ii = this.pages.length; i < ii; i++) {
|
||||
if (this.pages[i] &&
|
||||
this.pages[i].renderingState !== RenderingStates.FINISHED) {
|
||||
this.pages[i].reset();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
forceRendering: function (currentlyVisiblePages) {
|
||||
var visiblePages = currentlyVisiblePages || this._getVisiblePages();
|
||||
var pageView = this.renderingQueue.getHighestPriority(visiblePages,
|
||||
this.pages,
|
||||
this.scroll.down);
|
||||
if (pageView) {
|
||||
this.renderingQueue.renderView(pageView);
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
getPageTextContent: function (pageIndex) {
|
||||
return this.pdfDocument.getPage(pageIndex + 1).then(function (page) {
|
||||
return page.getTextContent();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param textLayerDiv {HTMLDivElement}
|
||||
* @param pageIndex {number}
|
||||
* @param viewport {PageViewport}
|
||||
* @returns {TextLayerBuilder}
|
||||
*/
|
||||
createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
|
||||
var isViewerInPresentationMode =
|
||||
this.presentationModeState === PresentationModeState.FULLSCREEN;
|
||||
return new TextLayerBuilder({
|
||||
textLayerDiv: textLayerDiv,
|
||||
pageIndex: pageIndex,
|
||||
viewport: viewport,
|
||||
lastScrollSource: this,
|
||||
isViewerInPresentationMode: isViewerInPresentationMode,
|
||||
findController: this.findController
|
||||
});
|
||||
},
|
||||
|
||||
setFindController: function (findController) {
|
||||
this.findController = findController;
|
||||
},
|
||||
};
|
||||
|
||||
return PDFViewer;
|
||||
})();
|
||||
|
||||
/**
|
||||
* PDFPage object source.
|
||||
* @class
|
||||
*/
|
||||
var PDFPageSource = (function PDFPageSourceClosure() {
|
||||
/**
|
||||
* @constructs
|
||||
* @param {PDFDocument} pdfDocument
|
||||
* @param {number} pageNumber
|
||||
* @constructor
|
||||
*/
|
||||
function PDFPageSource(pdfDocument, pageNumber) {
|
||||
this.pdfDocument = pdfDocument;
|
||||
this.pageNumber = pageNumber;
|
||||
}
|
||||
|
||||
PDFPageSource.prototype = /** @lends PDFPageSource.prototype */ {
|
||||
/**
|
||||
* @returns {Promise<PDFPage>}
|
||||
*/
|
||||
getPage: function () {
|
||||
return this.pdfDocument.getPage(this.pageNumber);
|
||||
}
|
||||
};
|
||||
|
||||
return PDFPageSource;
|
||||
})();
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFView, scrollIntoView, HandTool */
|
||||
/* globals scrollIntoView, HandTool, PDFViewerApplication */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -68,7 +68,7 @@ var PresentationMode = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize a timeout that is used to reset PDFView.currentPosition when the
|
||||
* Initialize a timeout that is used to specify switchInProgress when the
|
||||
* browser transitions to fullscreen mode. Since resize events are triggered
|
||||
* multiple times during the switch to fullscreen mode, this is necessary in
|
||||
* order to prevent the page from being scrolled partially, or completely,
|
||||
@ -81,9 +81,8 @@ var PresentationMode = {
|
||||
}
|
||||
this.switchInProgress = setTimeout(function switchInProgressTimeout() {
|
||||
delete this.switchInProgress;
|
||||
this._notifyStateChange();
|
||||
}.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
|
||||
|
||||
PDFView.currentPosition = null;
|
||||
},
|
||||
|
||||
_resetSwitchInProgress: function presentationMode_resetSwitchInProgress() {
|
||||
@ -94,11 +93,12 @@ var PresentationMode = {
|
||||
},
|
||||
|
||||
request: function presentationModeRequest() {
|
||||
if (!PDFView.supportsFullscreen || this.isFullscreen ||
|
||||
if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen ||
|
||||
!this.viewer.hasChildNodes()) {
|
||||
return false;
|
||||
}
|
||||
this._setSwitchInProgress();
|
||||
this._notifyStateChange();
|
||||
|
||||
if (this.container.requestFullscreen) {
|
||||
this.container.requestFullscreen();
|
||||
@ -113,23 +113,33 @@ var PresentationMode = {
|
||||
}
|
||||
|
||||
this.args = {
|
||||
page: PDFView.page,
|
||||
previousScale: PDFView.currentScaleValue
|
||||
page: PDFViewerApplication.page,
|
||||
previousScale: PDFViewerApplication.currentScaleValue
|
||||
};
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_notifyStateChange: function presentationModeNotifyStateChange() {
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('presentationmodechanged', true, true, {
|
||||
active: PresentationMode.active,
|
||||
switchInProgress: !!PresentationMode.switchInProgress
|
||||
});
|
||||
window.dispatchEvent(event);
|
||||
},
|
||||
|
||||
enter: function presentationModeEnter() {
|
||||
this.active = true;
|
||||
this._resetSwitchInProgress();
|
||||
this._notifyStateChange();
|
||||
|
||||
// Ensure that the correct page is scrolled into view when entering
|
||||
// Presentation Mode, by waiting until fullscreen mode in enabled.
|
||||
// Note: This is only necessary in non-Mozilla browsers.
|
||||
setTimeout(function enterPresentationModeTimeout() {
|
||||
PDFView.page = this.args.page;
|
||||
PDFView.setScale('page-fit', true);
|
||||
PDFViewerApplication.page = this.args.page;
|
||||
PDFViewerApplication.setScale('page-fit', true);
|
||||
}.bind(this), 0);
|
||||
|
||||
window.addEventListener('mousemove', this.mouseMove, false);
|
||||
@ -143,15 +153,17 @@ var PresentationMode = {
|
||||
},
|
||||
|
||||
exit: function presentationModeExit() {
|
||||
var page = PDFView.page;
|
||||
var page = PDFViewerApplication.page;
|
||||
|
||||
// Ensure that the correct page is scrolled into view when exiting
|
||||
// Presentation Mode, by waiting until fullscreen mode is disabled.
|
||||
// Note: This is only necessary in non-Mozilla browsers.
|
||||
setTimeout(function exitPresentationModeTimeout() {
|
||||
this.active = false;
|
||||
PDFView.setScale(this.args.previousScale);
|
||||
PDFView.page = page;
|
||||
this._notifyStateChange();
|
||||
|
||||
PDFViewerApplication.setScale(this.args.previousScale, true);
|
||||
PDFViewerApplication.page = page;
|
||||
this.args = null;
|
||||
}.bind(this), 0);
|
||||
|
||||
@ -160,7 +172,7 @@ var PresentationMode = {
|
||||
window.removeEventListener('contextmenu', this.contextMenu, false);
|
||||
|
||||
this.hideControls();
|
||||
PDFView.clearMouseScrollState();
|
||||
PDFViewerApplication.clearMouseScrollState();
|
||||
HandTool.exitPresentationMode();
|
||||
this.container.removeAttribute('contextmenu');
|
||||
this.contextMenuOpen = false;
|
||||
@ -224,7 +236,7 @@ var PresentationMode = {
|
||||
if (!isInternalLink) {
|
||||
// Unless an internal link was clicked, advance one page.
|
||||
evt.preventDefault();
|
||||
PDFView.page += (evt.shiftKey ? -1 : 1);
|
||||
PDFViewerApplication.page += (evt.shiftKey ? -1 : 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFView, SCROLLBAR_PADDING */
|
||||
/* globals PDFViewerApplication, SCROLLBAR_PADDING */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -87,7 +87,7 @@ var SecondaryToolbar = {
|
||||
},
|
||||
|
||||
downloadClick: function secondaryToolbarDownloadClick(evt) {
|
||||
PDFView.download();
|
||||
PDFViewerApplication.download();
|
||||
this.close();
|
||||
},
|
||||
|
||||
@ -96,23 +96,23 @@ var SecondaryToolbar = {
|
||||
},
|
||||
|
||||
firstPageClick: function secondaryToolbarFirstPageClick(evt) {
|
||||
PDFView.page = 1;
|
||||
PDFViewerApplication.page = 1;
|
||||
this.close();
|
||||
},
|
||||
|
||||
lastPageClick: function secondaryToolbarLastPageClick(evt) {
|
||||
if (PDFView.pdfDocument) {
|
||||
PDFView.page = PDFView.pdfDocument.numPages;
|
||||
if (PDFViewerApplication.pdfDocument) {
|
||||
PDFViewerApplication.page = PDFViewerApplication.pagesCount;
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
|
||||
pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) {
|
||||
PDFView.rotatePages(90);
|
||||
PDFViewerApplication.rotatePages(90);
|
||||
},
|
||||
|
||||
pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) {
|
||||
PDFView.rotatePages(-90);
|
||||
PDFViewerApplication.rotatePages(-90);
|
||||
},
|
||||
|
||||
documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) {
|
||||
|
@ -28,11 +28,23 @@ function isAllWhitespace(str) {
|
||||
return !NonWhitespaceRegexp.test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} TextLayerBuilderOptions
|
||||
* @property {HTMLDivElement} textLayerDiv - The text layer container.
|
||||
* @property {number} pageIndex - The page index.
|
||||
* @property {PageViewport} viewport - The viewport of the text layer.
|
||||
* @property {ILastScrollSource} lastScrollSource - The object that records when
|
||||
* last time scroll happened.
|
||||
* @property {boolean} isViewerInPresentationMode
|
||||
* @property {PDFFindController} findController
|
||||
*/
|
||||
|
||||
/**
|
||||
* TextLayerBuilder provides text-selection functionality for the PDF.
|
||||
* It does this by creating overlay divs over the PDF text. These divs
|
||||
* contain text that matches the PDF text they are overlaying. This object
|
||||
* also provides a way to highlight text that is being searched for.
|
||||
* @class
|
||||
*/
|
||||
var TextLayerBuilder = (function TextLayerBuilderClosure() {
|
||||
function TextLayerBuilder(options) {
|
||||
|
@ -14,16 +14,32 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* globals PDFView, mozL10n, RenderingStates */
|
||||
/* globals mozL10n, RenderingStates, Promise, scrollIntoView, PDFPageSource,
|
||||
watchScroll, getVisibleElements */
|
||||
|
||||
'use strict';
|
||||
|
||||
var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
var THUMBNAIL_SCROLL_MARGIN = -19;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param container
|
||||
* @param id
|
||||
* @param defaultViewport
|
||||
* @param linkService
|
||||
* @param renderingQueue
|
||||
* @param pageSource
|
||||
*
|
||||
* @implements {IRenderableView}
|
||||
*/
|
||||
var ThumbnailView = function thumbnailView(container, id, defaultViewport,
|
||||
linkService, renderingQueue,
|
||||
pageSource) {
|
||||
var anchor = document.createElement('a');
|
||||
anchor.href = PDFView.getAnchorUrl('#page=' + id);
|
||||
anchor.href = linkService.getAnchorUrl('#page=' + id);
|
||||
anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
|
||||
anchor.onclick = function stopNavigation() {
|
||||
PDFView.page = id;
|
||||
linkService.page = id;
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -36,6 +52,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
this.pageHeight = this.viewport.height;
|
||||
this.pageRatio = this.pageWidth / this.pageHeight;
|
||||
this.id = id;
|
||||
this.renderingId = 'thumbnail' + id;
|
||||
|
||||
this.canvasWidth = 98;
|
||||
this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
|
||||
@ -62,6 +79,8 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
|
||||
this.hasImage = false;
|
||||
this.renderingState = RenderingStates.INITIAL;
|
||||
this.renderingQueue = renderingQueue;
|
||||
this.pageSource = pageSource;
|
||||
|
||||
this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) {
|
||||
this.pdfPage = pdfPage;
|
||||
@ -125,7 +144,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
|
||||
this.draw = function thumbnailViewDraw(callback) {
|
||||
if (!this.pdfPage) {
|
||||
var promise = PDFView.getPage(this.id);
|
||||
var promise = this.pageSource.getPage(this.id);
|
||||
promise.then(function(pdfPage) {
|
||||
this.setPdfPage(pdfPage);
|
||||
this.draw(callback);
|
||||
@ -150,7 +169,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
canvasContext: ctx,
|
||||
viewport: drawViewport,
|
||||
continueCallback: function(cont) {
|
||||
if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) {
|
||||
if (!self.renderingQueue.isHighestPriority(self)) {
|
||||
self.renderingState = RenderingStates.PAUSED;
|
||||
self.resume = function() {
|
||||
self.renderingState = RenderingStates.RUNNING;
|
||||
@ -187,7 +206,7 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
|
||||
this.setImage = function thumbnailViewSetImage(img) {
|
||||
if (!this.pdfPage) {
|
||||
var promise = PDFView.getPage(this.id);
|
||||
var promise = this.pageSource.getPage();
|
||||
promise.then(function(pdfPage) {
|
||||
this.setPdfPage(pdfPage);
|
||||
this.setImage(img);
|
||||
@ -232,3 +251,134 @@ var ThumbnailView = function thumbnailView(container, id, defaultViewport) {
|
||||
};
|
||||
|
||||
ThumbnailView.tempImageCache = null;
|
||||
|
||||
/**
|
||||
* @typedef {Object} PDFThumbnailViewerOptions
|
||||
* @property {HTMLDivElement} container - The container for the thumbs elements.
|
||||
* @property {IPDFLinkService} linkService - The navigation/linking service.
|
||||
* @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple viewer control to display thumbs for pages.
|
||||
* @class
|
||||
*/
|
||||
var PDFThumbnailViewer = (function pdfThumbnailViewer() {
|
||||
/**
|
||||
* @constructs
|
||||
* @param {PDFThumbnailViewerOptions} options
|
||||
*/
|
||||
function PDFThumbnailViewer(options) {
|
||||
this.container = options.container;
|
||||
this.renderingQueue = options.renderingQueue;
|
||||
this.linkService = options.linkService;
|
||||
|
||||
this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this));
|
||||
this._resetView();
|
||||
}
|
||||
|
||||
PDFThumbnailViewer.prototype = {
|
||||
_scrollUpdated: function PDFThumbnailViewer_scrollUpdated() {
|
||||
this.renderingQueue.renderHighestPriority();
|
||||
},
|
||||
|
||||
getThumbnail: function PDFThumbnailViewer_getThumbnail(index) {
|
||||
return this.thumbnails[index];
|
||||
},
|
||||
|
||||
_getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() {
|
||||
return getVisibleElements(this.container, this.thumbnails);
|
||||
},
|
||||
|
||||
scrollThumbnailIntoView: function (page) {
|
||||
var selected = document.querySelector('.thumbnail.selected');
|
||||
if (selected) {
|
||||
selected.classList.remove('selected');
|
||||
}
|
||||
var thumbnail = document.getElementById('thumbnailContainer' + page);
|
||||
thumbnail.classList.add('selected');
|
||||
var visibleThumbs = this._getVisibleThumbs();
|
||||
var numVisibleThumbs = visibleThumbs.views.length;
|
||||
|
||||
// If the thumbnail isn't currently visible, scroll it into view.
|
||||
if (numVisibleThumbs > 0) {
|
||||
var first = visibleThumbs.first.id;
|
||||
// Account for only one thumbnail being visible.
|
||||
var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first);
|
||||
if (page <= first || page >= last) {
|
||||
scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get pagesRotation() {
|
||||
return this._pagesRotation;
|
||||
},
|
||||
|
||||
set pagesRotation(rotation) {
|
||||
this._pagesRotation = rotation;
|
||||
for (var i = 0, l = this.thumbnails.length; i < l; i++) {
|
||||
var thumb = this.thumbnails[i];
|
||||
thumb.update(rotation);
|
||||
}
|
||||
},
|
||||
|
||||
cleanup: function PDFThumbnailViewer_cleanup() {
|
||||
ThumbnailView.tempImageCache = null;
|
||||
},
|
||||
|
||||
_resetView: function () {
|
||||
this.thumbnails = [];
|
||||
this._pagesRotation = 0;
|
||||
},
|
||||
|
||||
setDocument: function (pdfDocument) {
|
||||
if (this.pdfDocument) {
|
||||
// cleanup of the elements and views
|
||||
var thumbsView = this.container;
|
||||
while (thumbsView.hasChildNodes()) {
|
||||
thumbsView.removeChild(thumbsView.lastChild);
|
||||
}
|
||||
this._resetView();
|
||||
}
|
||||
|
||||
this.pdfDocument = pdfDocument;
|
||||
if (!pdfDocument) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return pdfDocument.getPage(1).then(function (firstPage) {
|
||||
var pagesCount = pdfDocument.numPages;
|
||||
var viewport = firstPage.getViewport(1.0);
|
||||
for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
|
||||
var pageSource = new PDFPageSource(pdfDocument, pageNum);
|
||||
var thumbnail = new ThumbnailView(this.container, pageNum,
|
||||
viewport.clone(), this.linkService,
|
||||
this.renderingQueue, pageSource);
|
||||
this.thumbnails.push(thumbnail);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
ensureThumbnailVisible:
|
||||
function PDFThumbnailViewer_ensureThumbnailVisible(page) {
|
||||
// Ensure that the thumbnail of the current page is visible
|
||||
// when switching from another view.
|
||||
scrollIntoView(document.getElementById('thumbnailContainer' + page));
|
||||
},
|
||||
|
||||
forceRendering: function () {
|
||||
var visibleThumbs = this._getVisibleThumbs();
|
||||
var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs,
|
||||
this.thumbnails,
|
||||
this.scroll.down);
|
||||
if (thumbView) {
|
||||
this.renderingQueue.renderView(thumbView);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return PDFThumbnailViewer;
|
||||
})();
|
||||
|
@ -16,6 +16,14 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var CSS_UNITS = 96.0 / 72.0;
|
||||
var DEFAULT_SCALE = 'auto';
|
||||
var UNKNOWN_SCALE = 0;
|
||||
var MAX_AUTO_SCALE = 1.25;
|
||||
var SCROLLBAR_PADDING = 40;
|
||||
var VERTICAL_PADDING = 5;
|
||||
var DEFAULT_CACHE_SIZE = 10;
|
||||
|
||||
// optimised CSS custom property getter/setter
|
||||
var CustomStyle = (function CustomStyleClosure() {
|
||||
|
||||
@ -138,6 +146,91 @@ function scrollIntoView(element, spot) {
|
||||
parent.scrollTop = offsetY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to start monitoring the scroll event and converting them into
|
||||
* PDF.js friendly one: with scroll debounce and scroll direction.
|
||||
*/
|
||||
function watchScroll(viewAreaElement, callback) {
|
||||
var debounceScroll = function debounceScroll(evt) {
|
||||
if (rAF) {
|
||||
return;
|
||||
}
|
||||
// schedule an invocation of scroll for next animation frame.
|
||||
rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {
|
||||
rAF = null;
|
||||
|
||||
var currentY = viewAreaElement.scrollTop;
|
||||
var lastY = state.lastY;
|
||||
if (currentY > lastY) {
|
||||
state.down = true;
|
||||
} else if (currentY < lastY) {
|
||||
state.down = false;
|
||||
}
|
||||
state.lastY = currentY;
|
||||
// else do nothing and use previous value
|
||||
callback(state);
|
||||
});
|
||||
};
|
||||
|
||||
var state = {
|
||||
down: true,
|
||||
lastY: viewAreaElement.scrollTop,
|
||||
_eventHandler: debounceScroll
|
||||
};
|
||||
|
||||
var rAF = null;
|
||||
viewAreaElement.addEventListener('scroll', debounceScroll, true);
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic helper to find out what elements are visible within a scroll pane.
|
||||
*/
|
||||
function getVisibleElements(scrollEl, views, sortByVisibility) {
|
||||
var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
|
||||
var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
|
||||
|
||||
var visible = [], view;
|
||||
var currentHeight, viewHeight, hiddenHeight, percentHeight;
|
||||
var currentWidth, viewWidth;
|
||||
for (var i = 0, ii = views.length; i < ii; ++i) {
|
||||
view = views[i];
|
||||
currentHeight = view.el.offsetTop + view.el.clientTop;
|
||||
viewHeight = view.el.clientHeight;
|
||||
if ((currentHeight + viewHeight) < top) {
|
||||
continue;
|
||||
}
|
||||
if (currentHeight > bottom) {
|
||||
break;
|
||||
}
|
||||
currentWidth = view.el.offsetLeft + view.el.clientLeft;
|
||||
viewWidth = view.el.clientWidth;
|
||||
if ((currentWidth + viewWidth) < left || currentWidth > right) {
|
||||
continue;
|
||||
}
|
||||
hiddenHeight = Math.max(0, top - currentHeight) +
|
||||
Math.max(0, currentHeight + viewHeight - bottom);
|
||||
percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
|
||||
|
||||
visible.push({ id: view.id, x: currentWidth, y: currentHeight,
|
||||
view: view, percent: percentHeight });
|
||||
}
|
||||
|
||||
var first = visible[0];
|
||||
var last = visible[visible.length - 1];
|
||||
|
||||
if (sortByVisibility) {
|
||||
visible.sort(function(a, b) {
|
||||
var pc = a.percent - b.percent;
|
||||
if (Math.abs(pc) > 0.001) {
|
||||
return -pc;
|
||||
}
|
||||
return a.id - b.id; // ensure stability
|
||||
});
|
||||
}
|
||||
return {first: first, last: last, views: visible};
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler to suppress context menu.
|
||||
*/
|
||||
|
@ -68,9 +68,11 @@ http://sourceforge.net/adobe/cmap/wiki/License/
|
||||
<script src="preferences.js"></script>
|
||||
<script src="download_manager.js"></script>
|
||||
<script src="view_history.js"></script>
|
||||
<script src="pdf_rendering_queue.js"></script>
|
||||
<script src="page_view.js"></script>
|
||||
<script src="thumbnail_view.js"></script>
|
||||
<script src="text_layer_builder.js"></script>
|
||||
<script src="pdf_viewer.js"></script>
|
||||
<script src="thumbnail_view.js"></script>
|
||||
<script src="document_outline_view.js"></script>
|
||||
<script src="document_attachments_view.js"></script>
|
||||
<script src="pdf_find_bar.js"></script>
|
||||
|
1058
web/viewer.js
1058
web/viewer.js
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user