Some checks failed
		
		
	
	Types tests / Test (lts/*) (push) Has been cancelled
				
			Lint / Lint (lts/*) (push) Has been cancelled
				
			CodeQL / Analyze (javascript) (push) Has been cancelled
				
			CI / Test (20) (push) Has been cancelled
				
			CI / Test (22) (push) Has been cancelled
				
			CI / Test (24) (push) Has been cancelled
				
			
		
			
				
	
	
		
			372 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			372 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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.
 | 
						|
 */
 | 
						|
 | 
						|
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
 | 
						|
  // eslint-disable-next-line no-alert
 | 
						|
  alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
 | 
						|
}
 | 
						|
 | 
						|
const MAX_CANVAS_PIXELS = 0; // CSS-only zooming.
 | 
						|
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.mjs";
 | 
						|
 | 
						|
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 (reason) {
 | 
						|
        let key = "pdfjs-loading-error";
 | 
						|
        if (reason instanceof pdfjsLib.InvalidPDFException) {
 | 
						|
          key = "pdfjs-invalid-file-error";
 | 
						|
        } else if (reason instanceof pdfjsLib.ResponseException) {
 | 
						|
          key = reason.missing
 | 
						|
            ? "pdfjs-missing-file-error"
 | 
						|
            : "pdfjs-unexpected-response-error";
 | 
						|
        }
 | 
						|
        self.l10n.get(key).then(msg => {
 | 
						|
          self.error(msg, { message: reason?.message });
 | 
						|
        });
 | 
						|
        self.loadingBar.hide();
 | 
						|
      }
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Closes opened PDF document.
 | 
						|
   * @returns {Promise} - Returns the promise, which is resolved when all
 | 
						|
   *                      destruction is completed.
 | 
						|
   */
 | 
						|
  close() {
 | 
						|
    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 {
 | 
						|
      // 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 moreInfoText = [
 | 
						|
      `PDF.js v${pdfjsLib.version || "?"} (build: ${pdfjsLib.build || "?"})`,
 | 
						|
    ];
 | 
						|
    if (moreInfo) {
 | 
						|
      moreInfoText.push(`Message: ${moreInfo.message}`);
 | 
						|
 | 
						|
      if (moreInfo.stack) {
 | 
						|
        moreInfoText.push(`Stack: ${moreInfo.stack}`);
 | 
						|
      } else {
 | 
						|
        if (moreInfo.filename) {
 | 
						|
          moreInfoText.push(`File: ${moreInfo.filename}`);
 | 
						|
        }
 | 
						|
        if (moreInfo.lineNumber) {
 | 
						|
          moreInfoText.push(`Line: ${moreInfo.lineNumber}`);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    console.error(`${message}\n\n${moreInfoText.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 = new pdfjsViewer.GenericL10n();
 | 
						|
 | 
						|
    const container = document.getElementById("viewerContainer");
 | 
						|
    const pdfViewer = new pdfjsViewer.PDFViewer({
 | 
						|
      container,
 | 
						|
      eventBus,
 | 
						|
      linkService,
 | 
						|
      l10n: this.l10n,
 | 
						|
      maxCanvasPixels: MAX_CANVAS_PIXELS,
 | 
						|
      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,
 | 
						|
  });
 | 
						|
});
 |