123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /* Copyright 2016 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";
- if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
- // eslint-disable-next-line no-alert
- alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
- }
- const USE_ONLY_CSS_ZOOM = true;
- const TEXT_LAYER_MODE = 0; // DISABLE
- const MAX_IMAGE_SIZE = 1024 * 1024;
- const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
- const CMAP_PACKED = true;
- pdfjsLib.GlobalWorkerOptions.workerSrc =
- "../../node_modules/pdfjs-dist/build/pdf.worker.js";
- const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
- const DEFAULT_SCALE_DELTA = 1.1;
- const MIN_SCALE = 0.25;
- const MAX_SCALE = 10.0;
- const DEFAULT_SCALE_VALUE = "auto";
- const PDFViewerApplication = {
- pdfLoadingTask: null,
- pdfDocument: null,
- pdfViewer: null,
- pdfHistory: null,
- pdfLinkService: null,
- eventBus: null,
- /**
- * Opens PDF document specified by URL.
- * @returns {Promise} - Returns the promise, which is resolved when document
- * is opened.
- */
- open(params) {
- if (this.pdfLoadingTask) {
- // We need to destroy already opened document
- return this.close().then(
- function () {
- // ... and repeat the open() call.
- return this.open(params);
- }.bind(this)
- );
- }
- const url = params.url;
- const self = this;
- this.setTitleUsingUrl(url);
- // Loading document.
- const loadingTask = pdfjsLib.getDocument({
- url,
- maxImageSize: MAX_IMAGE_SIZE,
- cMapUrl: CMAP_URL,
- cMapPacked: CMAP_PACKED,
- });
- this.pdfLoadingTask = loadingTask;
- loadingTask.onProgress = function (progressData) {
- self.progress(progressData.loaded / progressData.total);
- };
- return loadingTask.promise.then(
- function (pdfDocument) {
- // Document loaded, specifying document for the viewer.
- self.pdfDocument = pdfDocument;
- self.pdfViewer.setDocument(pdfDocument);
- self.pdfLinkService.setDocument(pdfDocument);
- self.pdfHistory.initialize({
- fingerprint: pdfDocument.fingerprints[0],
- });
- self.loadingBar.hide();
- self.setTitleUsingMetadata(pdfDocument);
- },
- function (exception) {
- const message = exception && exception.message;
- const l10n = self.l10n;
- let loadingErrorMessage;
- if (exception instanceof pdfjsLib.InvalidPDFException) {
- // change error message also for other builds
- loadingErrorMessage = l10n.get(
- "invalid_file_error",
- null,
- "Invalid or corrupted PDF file."
- );
- } else if (exception instanceof pdfjsLib.MissingPDFException) {
- // special message for missing PDFs
- loadingErrorMessage = l10n.get(
- "missing_file_error",
- null,
- "Missing PDF file."
- );
- } else if (exception instanceof pdfjsLib.UnexpectedResponseException) {
- loadingErrorMessage = l10n.get(
- "unexpected_response_error",
- null,
- "Unexpected server response."
- );
- } else {
- loadingErrorMessage = l10n.get(
- "loading_error",
- null,
- "An error occurred while loading the PDF."
- );
- }
- loadingErrorMessage.then(function (msg) {
- self.error(msg, { message });
- });
- self.loadingBar.hide();
- }
- );
- },
- /**
- * Closes opened PDF document.
- * @returns {Promise} - Returns the promise, which is resolved when all
- * destruction is completed.
- */
- close() {
- const errorWrapper = document.getElementById("errorWrapper");
- errorWrapper.hidden = true;
- if (!this.pdfLoadingTask) {
- return Promise.resolve();
- }
- const promise = this.pdfLoadingTask.destroy();
- this.pdfLoadingTask = null;
- if (this.pdfDocument) {
- this.pdfDocument = null;
- this.pdfViewer.setDocument(null);
- this.pdfLinkService.setDocument(null, null);
- if (this.pdfHistory) {
- this.pdfHistory.reset();
- }
- }
- return promise;
- },
- get loadingBar() {
- const bar = document.getElementById("loadingBar");
- return pdfjsLib.shadow(
- this,
- "loadingBar",
- new pdfjsViewer.ProgressBar(bar)
- );
- },
- setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
- this.url = url;
- let title = pdfjsLib.getFilenameFromUrl(url) || url;
- try {
- title = decodeURIComponent(title);
- } catch (e) {
- // decodeURIComponent may throw URIError,
- // fall back to using the unprocessed url in that case
- }
- this.setTitle(title);
- },
- setTitleUsingMetadata(pdfDocument) {
- const self = this;
- pdfDocument.getMetadata().then(function (data) {
- const info = data.info,
- metadata = data.metadata;
- self.documentInfo = info;
- self.metadata = metadata;
- // Provides some basic debug information
- console.log(
- "PDF " +
- pdfDocument.fingerprints[0] +
- " [" +
- info.PDFFormatVersion +
- " " +
- (info.Producer || "-").trim() +
- " / " +
- (info.Creator || "-").trim() +
- "]" +
- " (PDF.js: " +
- (pdfjsLib.version || "-") +
- ")"
- );
- let pdfTitle;
- if (metadata && metadata.has("dc:title")) {
- const title = metadata.get("dc:title");
- // Ghostscript sometimes returns 'Untitled', so prevent setting the
- // title to 'Untitled.
- if (title !== "Untitled") {
- pdfTitle = title;
- }
- }
- if (!pdfTitle && info && info.Title) {
- pdfTitle = info.Title;
- }
- if (pdfTitle) {
- self.setTitle(pdfTitle + " - " + document.title);
- }
- });
- },
- setTitle: function pdfViewSetTitle(title) {
- document.title = title;
- document.getElementById("title").textContent = title;
- },
- error: function pdfViewError(message, moreInfo) {
- const l10n = this.l10n;
- const moreInfoText = [
- l10n.get(
- "error_version_info",
- { version: pdfjsLib.version || "?", build: pdfjsLib.build || "?" },
- "PDF.js v{{version}} (build: {{build}})"
- ),
- ];
- if (moreInfo) {
- moreInfoText.push(
- l10n.get(
- "error_message",
- { message: moreInfo.message },
- "Message: {{message}}"
- )
- );
- if (moreInfo.stack) {
- moreInfoText.push(
- l10n.get("error_stack", { stack: moreInfo.stack }, "Stack: {{stack}}")
- );
- } else {
- if (moreInfo.filename) {
- moreInfoText.push(
- l10n.get(
- "error_file",
- { file: moreInfo.filename },
- "File: {{file}}"
- )
- );
- }
- if (moreInfo.lineNumber) {
- moreInfoText.push(
- l10n.get(
- "error_line",
- { line: moreInfo.lineNumber },
- "Line: {{line}}"
- )
- );
- }
- }
- }
- const errorWrapper = document.getElementById("errorWrapper");
- errorWrapper.hidden = false;
- const errorMessage = document.getElementById("errorMessage");
- errorMessage.textContent = message;
- const closeButton = document.getElementById("errorClose");
- closeButton.onclick = function () {
- errorWrapper.hidden = true;
- };
- const errorMoreInfo = document.getElementById("errorMoreInfo");
- const moreInfoButton = document.getElementById("errorShowMore");
- const lessInfoButton = document.getElementById("errorShowLess");
- moreInfoButton.onclick = function () {
- errorMoreInfo.hidden = false;
- moreInfoButton.hidden = true;
- lessInfoButton.hidden = false;
- errorMoreInfo.style.height = errorMoreInfo.scrollHeight + "px";
- };
- lessInfoButton.onclick = function () {
- errorMoreInfo.hidden = true;
- moreInfoButton.hidden = false;
- lessInfoButton.hidden = true;
- };
- moreInfoButton.hidden = false;
- lessInfoButton.hidden = true;
- Promise.all(moreInfoText).then(function (parts) {
- errorMoreInfo.value = parts.join("\n");
- });
- },
- progress: function pdfViewProgress(level) {
- const percent = Math.round(level * 100);
- // Updating the bar if value increases.
- if (percent > this.loadingBar.percent || isNaN(percent)) {
- this.loadingBar.percent = percent;
- }
- },
- get pagesCount() {
- return this.pdfDocument.numPages;
- },
- get page() {
- return this.pdfViewer.currentPageNumber;
- },
- set page(val) {
- this.pdfViewer.currentPageNumber = val;
- },
- zoomIn: function pdfViewZoomIn(ticks) {
- let newScale = this.pdfViewer.currentScale;
- do {
- newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);
- newScale = Math.ceil(newScale * 10) / 10;
- newScale = Math.min(MAX_SCALE, newScale);
- } while (--ticks && newScale < MAX_SCALE);
- this.pdfViewer.currentScaleValue = newScale;
- },
- zoomOut: function pdfViewZoomOut(ticks) {
- let newScale = this.pdfViewer.currentScale;
- do {
- newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);
- newScale = Math.floor(newScale * 10) / 10;
- newScale = Math.max(MIN_SCALE, newScale);
- } while (--ticks && newScale > MIN_SCALE);
- this.pdfViewer.currentScaleValue = newScale;
- },
- initUI: function pdfViewInitUI() {
- const eventBus = new pdfjsViewer.EventBus();
- this.eventBus = eventBus;
- const linkService = new pdfjsViewer.PDFLinkService({
- eventBus,
- });
- this.pdfLinkService = linkService;
- this.l10n = pdfjsViewer.NullL10n;
- const container = document.getElementById("viewerContainer");
- const pdfViewer = new pdfjsViewer.PDFViewer({
- container,
- eventBus,
- linkService,
- l10n: this.l10n,
- useOnlyCssZoom: USE_ONLY_CSS_ZOOM,
- textLayerMode: TEXT_LAYER_MODE,
- });
- this.pdfViewer = pdfViewer;
- linkService.setViewer(pdfViewer);
- this.pdfHistory = new pdfjsViewer.PDFHistory({
- eventBus,
- linkService,
- });
- linkService.setHistory(this.pdfHistory);
- document.getElementById("previous").addEventListener("click", function () {
- PDFViewerApplication.page--;
- });
- document.getElementById("next").addEventListener("click", function () {
- PDFViewerApplication.page++;
- });
- document.getElementById("zoomIn").addEventListener("click", function () {
- PDFViewerApplication.zoomIn();
- });
- document.getElementById("zoomOut").addEventListener("click", function () {
- PDFViewerApplication.zoomOut();
- });
- document
- .getElementById("pageNumber")
- .addEventListener("click", function () {
- this.select();
- });
- document
- .getElementById("pageNumber")
- .addEventListener("change", function () {
- PDFViewerApplication.page = this.value | 0;
- // Ensure that the page number input displays the correct value,
- // even if the value entered by the user was invalid
- // (e.g. a floating point number).
- if (this.value !== PDFViewerApplication.page.toString()) {
- this.value = PDFViewerApplication.page;
- }
- });
- eventBus.on("pagesinit", function () {
- // We can use pdfViewer now, e.g. let's change default scale.
- pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
- });
- eventBus.on(
- "pagechanging",
- function (evt) {
- const page = evt.pageNumber;
- const numPages = PDFViewerApplication.pagesCount;
- document.getElementById("pageNumber").value = page;
- document.getElementById("previous").disabled = page <= 1;
- document.getElementById("next").disabled = page >= numPages;
- },
- true
- );
- },
- };
- window.PDFViewerApplication = PDFViewerApplication;
- document.addEventListener(
- "DOMContentLoaded",
- function () {
- PDFViewerApplication.initUI();
- },
- true
- );
- // The offsetParent is not set until the PDF.js iframe or object is visible;
- // waiting for first animation.
- const animationStarted = new Promise(function (resolve) {
- window.requestAnimationFrame(resolve);
- });
- // We need to delay opening until all HTML is loaded.
- animationStarted.then(function () {
- PDFViewerApplication.open({
- url: DEFAULT_URL,
- });
- });
|