-
Notifications
You must be signed in to change notification settings - Fork 10.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e9f7f55
commit b2a57c9
Showing
7 changed files
with
377 additions
and
234 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,298 @@ | ||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ | ||
/* Copyright 2015 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 PDFViewer, PDFHistory, Promise, parseQueryString */ | ||
|
||
'use strict'; | ||
|
||
/** | ||
* Performs navigation functions inside PDF, such as opening specified page, | ||
* or destination. | ||
* @class | ||
* @implements {IPDFLinkService} | ||
*/ | ||
var PDFLinkService = (function () { | ||
/** | ||
* @constructs PDFLinkService | ||
* @param {PDFLinkServiceOptions} options | ||
*/ | ||
function PDFLinkService() { | ||
this.pdfDocument = null; | ||
this.pdfViewer = null; | ||
this.pdfHistory = null; | ||
|
||
this._pagesRefCache = null; | ||
} | ||
|
||
PDFLinkService.prototype = { | ||
setDocument: function (pdfDocument) { | ||
this.pdfDocument = pdfDocument; | ||
this._pagesRefCache = Object.create(null); | ||
}, | ||
|
||
setViewer: function (pdfViewer) { | ||
this.pdfViewer = pdfViewer; | ||
}, | ||
|
||
setHistory: function (pdfHistory) { | ||
this.pdfHistory = pdfHistory; | ||
}, | ||
|
||
get pagesCount() { | ||
return this.pdfDocument.numPages; | ||
}, | ||
|
||
/** | ||
* @returns {number} | ||
*/ | ||
get page() { | ||
return this.pdfViewer.currentPageNumber; | ||
}, | ||
/** | ||
* @param {number} value | ||
*/ | ||
set page(value) { | ||
this.pdfViewer.currentPageNumber = value; | ||
}, | ||
/** | ||
* @param dest - The PDF destination object. | ||
*/ | ||
navigateTo: function (dest) { | ||
var destString = ''; | ||
var self = this; | ||
|
||
var goToDestination = function(destRef) { | ||
// dest array looks like that: <page-ref> </XYZ|FitXXX> <args..> | ||
var pageNumber = destRef instanceof Object ? | ||
self._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] : | ||
(destRef + 1); | ||
if (pageNumber) { | ||
if (pageNumber > self.pagesCount) { | ||
pageNumber = self.pagesCount; | ||
} | ||
self.pdfViewer.scrollPageIntoView(pageNumber, dest); | ||
|
||
// Update the browsing history. | ||
self.pdfHistory.push({ | ||
dest: dest, | ||
hash: destString, | ||
page: pageNumber | ||
}); | ||
} else { | ||
self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) { | ||
var pageNum = pageIndex + 1; | ||
var cacheKey = destRef.num + ' ' + destRef.gen + ' R'; | ||
self._pagesRefCache[cacheKey] = pageNum; | ||
goToDestination(destRef); | ||
}); | ||
} | ||
}; | ||
|
||
var destinationPromise; | ||
if (typeof dest === 'string') { | ||
destString = dest; | ||
destinationPromise = this.pdfDocument.getDestination(dest); | ||
} else { | ||
destinationPromise = Promise.resolve(dest); | ||
} | ||
destinationPromise.then(function(destination) { | ||
dest = destination; | ||
if (!(destination instanceof Array)) { | ||
return; // invalid destination | ||
} | ||
goToDestination(destination[0]); | ||
}); | ||
}, | ||
|
||
/** | ||
* @param dest - The PDF destination object. | ||
* @returns {string} The hyperlink to the PDF object. | ||
*/ | ||
getDestinationHash: function (dest) { | ||
if (typeof dest === 'string') { | ||
return this.getAnchorUrl('#' + escape(dest)); | ||
} | ||
if (dest instanceof Array) { | ||
var destRef = dest[0]; // see navigateTo method for dest format | ||
var pageNumber = destRef instanceof Object ? | ||
this._pagesRefCache[destRef.num + ' ' + destRef.gen + ' R'] : | ||
(destRef + 1); | ||
if (pageNumber) { | ||
var pdfOpenParams = this.getAnchorUrl('#page=' + pageNumber); | ||
var destKind = dest[1]; | ||
if (typeof destKind === 'object' && 'name' in destKind && | ||
destKind.name === 'XYZ') { | ||
var scale = (dest[4] || this.pdfViewer.currentScaleValue); | ||
var scaleNumber = parseFloat(scale); | ||
if (scaleNumber) { | ||
scale = scaleNumber * 100; | ||
} | ||
pdfOpenParams += '&zoom=' + scale; | ||
if (dest[2] || dest[3]) { | ||
pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0); | ||
} | ||
} | ||
return pdfOpenParams; | ||
} | ||
} | ||
return ''; | ||
}, | ||
|
||
/** | ||
* Prefix the full url on anchor links to make sure that links are resolved | ||
* relative to the current URL instead of the one defined in <base href>. | ||
* @param {String} anchor The anchor hash, including the #. | ||
* @returns {string} The hyperlink to the PDF object. | ||
*/ | ||
getAnchorUrl: function (anchor) { | ||
//#if (GENERIC || B2G) | ||
return anchor; | ||
//#endif | ||
//#if (FIREFOX || MOZCENTRAL) | ||
// return this.url.split('#')[0] + anchor; | ||
//#endif | ||
//#if CHROME | ||
// return location.href.split('#')[0] + anchor; | ||
//#endif | ||
}, | ||
|
||
/** | ||
* @param {string} hash | ||
*/ | ||
setHash: function (hash) { | ||
if (hash.indexOf('=') >= 0) { | ||
var params = parseQueryString(hash); | ||
// borrowing syntax from "Parameters for Opening PDF Files" | ||
if ('nameddest' in params) { | ||
this.pdfHistory.updateNextHashParam(params.nameddest); | ||
this.navigateTo(params.nameddest); | ||
return; | ||
} | ||
var pageNumber, dest; | ||
if ('page' in params) { | ||
pageNumber = (params.page | 0) || 1; | ||
} | ||
if ('zoom' in params) { | ||
// Build the destination array. | ||
var zoomArgs = params.zoom.split(','); // scale,left,top | ||
var zoomArg = zoomArgs[0]; | ||
var zoomArgNumber = parseFloat(zoomArg); | ||
|
||
if (zoomArg.indexOf('Fit') === -1) { | ||
// If the zoomArg is a number, it has to get divided by 100. If it's | ||
// a string, it should stay as it is. | ||
dest = [null, { name: 'XYZ' }, | ||
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null, | ||
zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null, | ||
(zoomArgNumber ? zoomArgNumber / 100 : zoomArg)]; | ||
} else { | ||
if (zoomArg === 'Fit' || zoomArg === 'FitB') { | ||
dest = [null, { name: zoomArg }]; | ||
} else if ((zoomArg === 'FitH' || zoomArg === 'FitBH') || | ||
(zoomArg === 'FitV' || zoomArg === 'FitBV')) { | ||
dest = [null, { name: zoomArg }, | ||
zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null]; | ||
} else if (zoomArg === 'FitR') { | ||
if (zoomArgs.length !== 5) { | ||
console.error('pdfViewSetHash: ' + | ||
'Not enough parameters for \'FitR\'.'); | ||
} else { | ||
dest = [null, { name: zoomArg }, | ||
(zoomArgs[1] | 0), (zoomArgs[2] | 0), | ||
(zoomArgs[3] | 0), (zoomArgs[4] | 0)]; | ||
} | ||
} else { | ||
console.error('pdfViewSetHash: \'' + zoomArg + | ||
'\' is not a valid zoom value.'); | ||
} | ||
} | ||
} | ||
if (dest) { | ||
this.pdfViewer.scrollPageIntoView(pageNumber || this.page, dest); | ||
} else if (pageNumber) { | ||
this.page = pageNumber; // simple page | ||
} | ||
if ('pagemode' in params) { | ||
if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks' || | ||
params.pagemode === 'attachments') { | ||
this.switchSidebarView((params.pagemode === 'bookmarks' ? | ||
'outline' : params.pagemode), true); | ||
} else if (params.pagemode === 'none' && this.sidebarOpen) { | ||
document.getElementById('sidebarToggle').click(); | ||
} | ||
} | ||
} else if (/^\d+$/.test(hash)) { // page number | ||
this.page = hash; | ||
} else { // named destination | ||
this.pdfHistory.updateNextHashParam(unescape(hash)); | ||
this.navigateTo(unescape(hash)); | ||
} | ||
}, | ||
|
||
/** | ||
* @param {string} action | ||
*/ | ||
executeNamedAction: function (action) { | ||
// See PDF reference, table 8.45 - Named action | ||
switch (action) { | ||
case 'GoBack': | ||
this.pdfHistory.back(); | ||
break; | ||
|
||
case 'GoForward': | ||
this.pdfHistory.forward(); | ||
break; | ||
|
||
case 'NextPage': | ||
this.page++; | ||
break; | ||
|
||
case 'PrevPage': | ||
this.page--; | ||
break; | ||
|
||
case 'LastPage': | ||
this.page = this.pagesCount; | ||
break; | ||
|
||
case 'FirstPage': | ||
this.page = 1; | ||
break; | ||
|
||
default: | ||
break; // No action according to spec | ||
} | ||
|
||
var event = document.createEvent('CustomEvent'); | ||
event.initCustomEvent('namedaction', true, true, { | ||
action: action | ||
}); | ||
this.pdfViewer.container.dispatchEvent(event); | ||
|
||
}, | ||
|
||
/** | ||
* @param {number} pageNum - page number. | ||
* @param {Object} pageRef - reference to the page. | ||
*/ | ||
cachePageRef: function (pageNum, pageRef) { | ||
var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; | ||
this._pagesRefCache[refStr] = pageNum; | ||
} | ||
}; | ||
|
||
return PDFLinkService; | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.