TimeTrex/interface/html5/components/pdf_viewer/ttpdfviewer.js

149 lines
6.2 KiB
JavaScript

/*
* For future reference, quite a lot of this code is based on the following, and potentially more, but these are the links I remember:
* https://github.com/mozilla/pdf.js/tree/master/examples/components
* https://github.com/mozilla/pdf.js/tree/master/examples/acroforms
* https://github.com/mozilla/pdfjs-dist/tree/master/web
* https://github.com/mozilla/pdf.js/tree/master/web
*
* JSFiddle examples: https://jsfiddle.net/redfox05/btaqyse6/ , https://jsfiddle.net/redfox05/xvpzwLc2/ , https://jsfiddle.net/redfox05/rdyzef3o/
*/
import * as pdfjsLib from 'pdfjs-dist';
import * as pdfjsViewer from 'pdfjs-dist/web/pdf_viewer';
import 'pdfjs-dist/web/pdf_viewer.css';
// window.pdfjsLib = pdfjsLib;
// window.pdfjsViewer = pdfjsViewer;
export class TTPDFViewer {
constructor( options ) {
this.pdf_count = 0;
this.url_array = [];
this.target = null;
return this.initPDFViewer( options.urls, options.target );
}
initPDFViewer( url_array, target ) {
this.url_array = url_array; // needed as a global for the eventBus to trigger the next document load.
this.target = target; // Also needed for the eventBus next doc loading.
if( !Array.isArray( url_array )) {
url_array = [ url_array ];
}
if( url_array.length > 1 ) {
$('.resume-label .label' ).text( $.i18n._( 'Resume' ) + ' (' + url_array.length + ' ' + $.i18n._( 'documents' ) + ')');
}
this.loadMultiplePDF( url_array, target );
}
loadMultiplePDF( url_array, target ) {
// Load first PDF via initPDFViewer, and loads the rest in callbacks.
if( Array.isArray( url_array ) && url_array.length > 0 ) {
var current_url = url_array.pop();
// If not the first page, then add a divider between multiple PDF documents.
if( this.pdf_count !== 0 ) {
var document_divider = document.createElement( 'hr' );
target.appendChild( document_divider );
}
// Start to cycle through each pdf, loading the first one
var container = document.createElement( 'div' );
container.className = 'pdfContainer';
container.setAttribute('data-document-index', this.pdf_count);
target.appendChild( container );
this.loadPDF( current_url, container, this.pdf_count );
this.pdf_count++;
}
}
loadPDF( pdf_url, container, pdf_id ) {
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
}
// The workerSrc property shall be specified.
// pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.js";
pdfjsLib.GlobalWorkerOptions.workerSrc = "dist/pdf.worker.js";
// Some PDFs need external cmaps.
// var CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
var CMAP_URL = "dist/pdfjs-cmaps/"; // This cmap directory is automatically copied by webpack config from from node_modules into dist at build.
var CMAP_PACKED = true;
// var DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
var DEFAULT_URL = pdf_url;
var DEFAULT_SCALE = 1.0;
var CSS_UNITS = 96/72; // Fixed scale calculations by taking into account CSS units. https://github.com/mozilla/pdf.js/issues/5628#issuecomment-367399215
// Already passed into the function.
// var container = document.getElementById("pageContainer");
var eventBus = new pdfjsViewer.EventBus();
// AlternativeLoadNextPDFDocument - In case the current logic does not work out. See code at bottom of loadingTask.
// eventBus.on("pagesloaded", () => {
// console.log('pagesloaded');
// this.loadMultiplePDF( this.url_array, this.target );
// });
// Loading document.
var loadingTask = pdfjsLib.getDocument({
url: DEFAULT_URL,
cMapUrl: CMAP_URL,
cMapPacked: CMAP_PACKED,
});
// Most of this logic is taken from the pdfjs acroforms example at https://github.com/mozilla/pdf.js/blob/master/examples/acroforms/acroforms.js
loadingTask.promise.then((pdfDocument) => {
// Use a promise to fetch and render the next page.
var promise = Promise.resolve();
for (var i = 1; i <= pdfDocument.numPages; i++) {
promise = promise.then(function( pageNum ) {
// Document loaded, retrieving the page.
return pdfDocument.getPage( pageNum ).then(function (pdfPage) {
var available_space = container.clientWidth;
var desired_width = available_space - 10 - 5 - 20;// 10px: margin on row, 5px: margin-right on column. The extra 20px was trial and error, likely the scrollbar, which will vary on browser.
var viewport = pdfPage.getViewport({ scale: DEFAULT_SCALE });
var scaled_scale = desired_width / (viewport.width * CSS_UNITS); // Fixed scale calculations by taking into account CSS units. https://github.com/mozilla/pdf.js/issues/5628#issuecomment-367399215
// var scaled_viewport = pdfPage.getViewport({ scale: scaled_scale });
// Creating the page view with default parameters.
var pdfPageView = new pdfjsViewer.PDFPageView({
container: container,
id: pageNum,
// scale: SCALE,
scale: scaled_scale,
defaultViewport: pdfPage.getViewport({ scale: scaled_scale }),
eventBus: eventBus,
// We can enable text/annotations layers, if needed
textLayerFactory: new pdfjsViewer.DefaultTextLayerFactory(),
annotationLayerFactory: new pdfjsViewer.DefaultAnnotationLayerFactory(),
renderInteractiveForms: true, // inspired from the acroforms example at https://github.com/mozilla/pdf.js/tree/master/examples/acroforms - a quick one-line win, so might as well enable it.
});
// Associates the actual page with the view, and drawing it
pdfPageView.setPdfPage(pdfPage);
return pdfPageView.draw().then(() => {
$('.pdfContainer a').attr('target', '_blank'); // #2662 and #2819 Needed to open PDF links in a new window, rather than active. PDFJS documentation is lacking on how to do this properly. So this will change the link target to _blank for all the PDF docs on the page. For future attemps, I looked into LinkService, externalLinkTarget, and newWindow, but examples did not work for our solution.
});
});
}.bind(null, i) );
}
// Either load the next file here, or use the eventBus code, which is commented out further up. See AlternativeLoadNextPDFDocument
this.loadMultiplePDF( this.url_array, this.target );
});
}
}
window.TTPDFViewer = TTPDFViewer;