2015-03-15 04:07:17 +09:00
|
|
|
/* 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 PDFJS, Promise */
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
PDFJS.useOnlyCssZoom = true;
|
|
|
|
PDFJS.disableTextLayer = true;
|
|
|
|
PDFJS.maxImageSize = 1024 * 1024;
|
|
|
|
PDFJS.workerSrc = '../pdfjs-components/build/pdf.worker.js';
|
|
|
|
PDFJS.cMapUrl = '../pdfjs-components/cmaps/';
|
|
|
|
PDFJS.cMapPacked = true;
|
|
|
|
|
|
|
|
var DEFAULT_SCALE_DELTA = 1.1;
|
|
|
|
var MIN_SCALE = 0.25;
|
|
|
|
var MAX_SCALE = 10.0;
|
|
|
|
var DEFAULT_SCALE_VALUE = 'auto';
|
|
|
|
|
|
|
|
var PDFViewerApplication = {
|
|
|
|
pdfDocument: null,
|
|
|
|
pdfViewer: null,
|
|
|
|
pdfHistory: null,
|
|
|
|
pdfLinkService: null,
|
|
|
|
|
|
|
|
open: function (params) {
|
|
|
|
var url = params.url, originalUrl = params.originalUrl;
|
|
|
|
var self = this;
|
|
|
|
this.setTitleUsingUrl(originalUrl);
|
|
|
|
|
|
|
|
// Loading document.
|
|
|
|
var loadingTask = PDFJS.getDocument(url);
|
|
|
|
loadingTask.onProgress = function (progressData) {
|
|
|
|
self.progress(progressData.loaded / progressData.total);
|
|
|
|
};
|
|
|
|
loadingTask.then(function (pdfDocument) {
|
|
|
|
// Document loaded, specifying document for the viewer.
|
|
|
|
this.pdfDocument = pdfDocument;
|
|
|
|
this.pdfViewer.setDocument(pdfDocument);
|
|
|
|
this.pdfLinkService.setDocument(pdfDocument);
|
|
|
|
this.pdfHistory.initialize(pdfDocument.fingerprint);
|
|
|
|
|
|
|
|
this.loadingBar.hide();
|
|
|
|
this.setTitleUsingMetadata(pdfDocument);
|
|
|
|
}.bind(this), function (exception) {
|
|
|
|
var message = exception && exception.message;
|
|
|
|
var loadingErrorMessage = mozL10n.get('loading_error', null,
|
|
|
|
'An error occurred while loading the PDF.');
|
|
|
|
|
|
|
|
if (exception instanceof PDFJS.InvalidPDFException) {
|
|
|
|
// change error message also for other builds
|
|
|
|
loadingErrorMessage = mozL10n.get('invalid_file_error', null,
|
|
|
|
'Invalid or corrupted PDF file.');
|
|
|
|
} else if (exception instanceof PDFJS.MissingPDFException) {
|
|
|
|
// special message for missing PDFs
|
|
|
|
loadingErrorMessage = mozL10n.get('missing_file_error', null,
|
|
|
|
'Missing PDF file.');
|
|
|
|
} else if (exception instanceof PDFJS.UnexpectedResponseException) {
|
|
|
|
loadingErrorMessage = mozL10n.get('unexpected_response_error', null,
|
|
|
|
'Unexpected server response.');
|
|
|
|
}
|
|
|
|
|
|
|
|
var moreInfo = {
|
|
|
|
message: message
|
|
|
|
};
|
|
|
|
self.error(loadingErrorMessage, moreInfo);
|
|
|
|
self.loadingBar.hide();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
get loadingBar() {
|
|
|
|
var bar = new PDFJS.ProgressBar('#loadingBar', {});
|
|
|
|
|
|
|
|
return PDFJS.shadow(this, 'loadingBar', bar);
|
|
|
|
},
|
|
|
|
|
|
|
|
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
|
|
|
|
this.url = url;
|
2016-02-15 22:46:41 +09:00
|
|
|
var title = PDFJS.getFilenameFromUrl(url) || url;
|
2015-03-15 04:07:17 +09:00
|
|
|
try {
|
|
|
|
title = decodeURIComponent(title);
|
|
|
|
} catch (e) {
|
|
|
|
// decodeURIComponent may throw URIError,
|
|
|
|
// fall back to using the unprocessed url in that case
|
|
|
|
}
|
|
|
|
this.setTitle(title);
|
|
|
|
},
|
|
|
|
|
|
|
|
setTitleUsingMetadata: function (pdfDocument) {
|
|
|
|
var self = this;
|
|
|
|
pdfDocument.getMetadata().then(function(data) {
|
|
|
|
var info = data.info, metadata = data.metadata;
|
|
|
|
self.documentInfo = info;
|
|
|
|
self.metadata = metadata;
|
|
|
|
|
|
|
|
// Provides some basic debug information
|
|
|
|
console.log('PDF ' + pdfDocument.fingerprint + ' [' +
|
|
|
|
info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +
|
|
|
|
' / ' + (info.Creator || '-').trim() + ']' +
|
|
|
|
' (PDF.js: ' + (PDFJS.version || '-') +
|
|
|
|
(!PDFJS.disableWebGL ? ' [WebGL]' : '') + ')');
|
|
|
|
|
|
|
|
var pdfTitle;
|
|
|
|
if (metadata && metadata.has('dc:title')) {
|
|
|
|
var 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('activityTitle').textContent = title;
|
|
|
|
},
|
|
|
|
|
|
|
|
error: function pdfViewError(message, moreInfo) {
|
|
|
|
var moreInfoText = mozL10n.get('error_version_info',
|
|
|
|
{version: PDFJS.version || '?', build: PDFJS.build || '?'},
|
|
|
|
'PDF.js v{{version}} (build: {{build}})') + '\n';
|
|
|
|
|
|
|
|
if (moreInfo) {
|
|
|
|
moreInfoText +=
|
|
|
|
mozL10n.get('error_message', {message: moreInfo.message},
|
|
|
|
'Message: {{message}}');
|
|
|
|
if (moreInfo.stack) {
|
|
|
|
moreInfoText += '\n' +
|
|
|
|
mozL10n.get('error_stack', {stack: moreInfo.stack},
|
|
|
|
'Stack: {{stack}}');
|
|
|
|
} else {
|
|
|
|
if (moreInfo.filename) {
|
|
|
|
moreInfoText += '\n' +
|
|
|
|
mozL10n.get('error_file', {file: moreInfo.filename},
|
|
|
|
'File: {{file}}');
|
|
|
|
}
|
|
|
|
if (moreInfo.lineNumber) {
|
|
|
|
moreInfoText += '\n' +
|
|
|
|
mozL10n.get('error_line', {line: moreInfo.lineNumber},
|
|
|
|
'Line: {{line}}');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var errorWrapper = document.getElementById('errorWrapper');
|
|
|
|
errorWrapper.removeAttribute('hidden');
|
|
|
|
|
|
|
|
var errorMessage = document.getElementById('errorMessage');
|
|
|
|
errorMessage.textContent = message;
|
|
|
|
|
|
|
|
var closeButton = document.getElementById('errorClose');
|
|
|
|
closeButton.onclick = function() {
|
|
|
|
errorWrapper.setAttribute('hidden', 'true');
|
|
|
|
};
|
|
|
|
|
|
|
|
var errorMoreInfo = document.getElementById('errorMoreInfo');
|
|
|
|
var moreInfoButton = document.getElementById('errorShowMore');
|
|
|
|
var lessInfoButton = document.getElementById('errorShowLess');
|
|
|
|
moreInfoButton.onclick = function() {
|
|
|
|
errorMoreInfo.removeAttribute('hidden');
|
|
|
|
moreInfoButton.setAttribute('hidden', 'true');
|
|
|
|
lessInfoButton.removeAttribute('hidden');
|
|
|
|
errorMoreInfo.style.height = errorMoreInfo.scrollHeight + 'px';
|
|
|
|
};
|
|
|
|
lessInfoButton.onclick = function() {
|
|
|
|
errorMoreInfo.setAttribute('hidden', 'true');
|
|
|
|
moreInfoButton.removeAttribute('hidden');
|
|
|
|
lessInfoButton.setAttribute('hidden', 'true');
|
|
|
|
};
|
|
|
|
moreInfoButton.removeAttribute('hidden');
|
|
|
|
lessInfoButton.setAttribute('hidden', 'true');
|
|
|
|
errorMoreInfo.value = moreInfoText;
|
|
|
|
},
|
|
|
|
|
|
|
|
progress: function pdfViewProgress(level) {
|
|
|
|
var 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;
|
|
|
|
},
|
|
|
|
|
|
|
|
set page(val) {
|
|
|
|
this.pdfViewer.currentPageNumber = val;
|
|
|
|
},
|
|
|
|
|
|
|
|
get page() {
|
|
|
|
return this.pdfViewer.currentPageNumber;
|
|
|
|
},
|
|
|
|
|
|
|
|
zoomIn: function pdfViewZoomIn(ticks) {
|
|
|
|
var 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) {
|
|
|
|
var 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() {
|
|
|
|
var linkService = new PDFJS.PDFLinkService();
|
|
|
|
this.pdfLinkService = linkService;
|
|
|
|
|
|
|
|
var container = document.getElementById('viewerContainer');
|
|
|
|
var pdfViewer = new PDFJS.PDFViewer({
|
|
|
|
container: container,
|
|
|
|
linkService: linkService
|
|
|
|
});
|
|
|
|
this.pdfViewer = pdfViewer;
|
|
|
|
linkService.setViewer(pdfViewer);
|
|
|
|
|
|
|
|
this.pdfHistory = new PDFJS.PDFHistory({
|
|
|
|
linkService: 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() {
|
|
|
|
// Handle the user inputting a floating point number.
|
|
|
|
PDFViewerApplication.page = (this.value | 0);
|
|
|
|
|
|
|
|
if (this.value !== (this.value | 0).toString()) {
|
|
|
|
this.value = PDFViewerApplication.page;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
container.addEventListener('pagesinit', function () {
|
|
|
|
// We can use pdfViewer now, e.g. let's change default scale.
|
|
|
|
pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
|
|
|
|
});
|
|
|
|
|
|
|
|
container.addEventListener('pagechange', function (evt) {
|
|
|
|
var page = evt.pageNumber;
|
|
|
|
if (evt.previousPageNumber !== page) {
|
|
|
|
document.getElementById('pageNumber').value = page;
|
|
|
|
}
|
|
|
|
var numPages = PDFViewerApplication.pagesCount;
|
|
|
|
|
|
|
|
document.getElementById('previous').disabled = (page <= 1);
|
|
|
|
document.getElementById('next').disabled = (page >= numPages);
|
|
|
|
}, true);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
|
PDFViewerApplication.initUI();
|
|
|
|
}, true);
|
|
|
|
|
|
|
|
(function animationStartedClosure() {
|
|
|
|
// The offsetParent is not set until the PDF.js iframe or object is visible.
|
|
|
|
// Waiting for first animation.
|
|
|
|
PDFViewerApplication.animationStartedPromise = new Promise(
|
|
|
|
function (resolve) {
|
|
|
|
window.requestAnimationFrame(resolve);
|
|
|
|
});
|
|
|
|
})();
|
|
|
|
|
|
|
|
// Support of the new version of navigator.mozL10n -- in PDF.js older/custom
|
|
|
|
// version is used.
|
|
|
|
var mozL10n = {
|
|
|
|
get: function (id, args, fallback) {
|
|
|
|
var s = (navigator.mozL10n && navigator.mozL10n.get(id)) || fallback;
|
|
|
|
s = s.replace(/\{\{\s*(\w+)\s*\}\}/g, function (all, key) {
|
|
|
|
return args[key] || '';
|
|
|
|
});
|
|
|
|
return s;
|
|
|
|
},
|
|
|
|
|
|
|
|
translate: function (fragment) {
|
|
|
|
if (navigator.mozL10n) {
|
|
|
|
navigator.mozL10n.translateFragment(fragment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.navigator.mozSetMessageHandler('activity', function(activity) {
|
|
|
|
var blob = activity.source.data.blob;
|
|
|
|
var fileURL = activity.source.data.url ||
|
|
|
|
activity.source.data.filename ||
|
|
|
|
' '; // if no url or filename, use a non-empty string
|
|
|
|
|
|
|
|
var url = URL.createObjectURL(blob);
|
|
|
|
// We need to delay opening until all HTML is loaded.
|
|
|
|
PDFViewerApplication.animationStartedPromise.then(function () {
|
|
|
|
PDFViewerApplication.open({url: url, originalUrl: fileURL});
|
|
|
|
|
|
|
|
var header = document.getElementById('header');
|
|
|
|
header.addEventListener('action', function() {
|
|
|
|
activity.postResult('close');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|