From 0ef6212b646427604b6968b8bc3cf2d6c048f012 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 27 Apr 2015 10:25:32 -0500 Subject: [PATCH] Refactors PDFLinkService. # Conflicts: # web/viewer.js --- web/interfaces.js | 6 + web/pdf_link_service.js | 293 ++++++++++++++++++++++++++++++++++ web/pdf_viewer.component.js | 4 +- web/pdf_viewer.js | 11 +- web/ui_utils.js | 15 ++ web/viewer.html | 1 + web/viewer.js | 305 ++++++++---------------------------- 7 files changed, 389 insertions(+), 246 deletions(-) create mode 100644 web/pdf_link_service.js diff --git a/web/interfaces.js b/web/interfaces.js index 37a7b19d0..d21e1f4c5 100644 --- a/web/interfaces.js +++ b/web/interfaces.js @@ -51,6 +51,12 @@ IPDFLinkService.prototype = { * @param {string} action */ executeNamedAction: function (action) {}, + + /** + * @param {number} pageNum - page number. + * @param {Object} pageRef - reference to the page. + */ + cachePageRef: function (pageNum, pageRef) {}, }; /** diff --git a/web/pdf_link_service.js b/web/pdf_link_service.js new file mode 100644 index 000000000..4e3213a17 --- /dev/null +++ b/web/pdf_link_service.js @@ -0,0 +1,293 @@ +/* -*- 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 + */ + function PDFLinkService() { + this.baseUrl = null; + this.pdfDocument = null; + this.pdfViewer = null; + this.pdfHistory = null; + + this._pagesRefCache = null; + } + + PDFLinkService.prototype = { + setDocument: function PDFLinkService_setDocument(pdfDocument, baseUrl) { + this.baseUrl = baseUrl; + this.pdfDocument = pdfDocument; + this._pagesRefCache = Object.create(null); + }, + + setViewer: function PDFLinkService_setViewer(pdfViewer) { + this.pdfViewer = pdfViewer; + }, + + setHistory: function PDFLinkService_setHistory(pdfHistory) { + this.pdfHistory = pdfHistory; + }, + + /** + * @returns {number} + */ + 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 PDFLinkService_navigateTo(dest) { + var destString = ''; + var self = this; + + var goToDestination = function(destRef) { + // dest array looks like that: + 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 PDFLinkService_getDestinationHash(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 . + * @param {String} anchor The anchor hash, including the #. + * @returns {string} The hyperlink to the PDF object. + */ + getAnchorUrl: function PDFLinkService_getAnchorUrl(anchor) { + return (this.baseUrl || '') + anchor; + }, + + /** + * @param {string} hash + */ + setHash: function PDFLinkService_setHash(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 PDFLinkService_executeNamedAction(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 PDFLinkService_cachePageRef(pageNum, pageRef) { + var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; + this._pagesRefCache[refStr] = pageNum; + } + }; + + return PDFLinkService; +})(); diff --git a/web/pdf_viewer.component.js b/web/pdf_viewer.component.js index 8c1223ab7..8fe7fe1c7 100644 --- a/web/pdf_viewer.component.js +++ b/web/pdf_viewer.component.js @@ -15,7 +15,7 @@ * limitations under the License. */ /*jshint globalstrict: false */ -/* globals PDFJS, PDFViewer, PDFPageView, TextLayerBuilder, +/* globals PDFJS, PDFViewer, PDFPageView, TextLayerBuilder, PDFLinkService, DefaultTextLayerFactory, AnnotationsLayerBuilder, DefaultAnnotationsLayerFactory */ @@ -28,10 +28,12 @@ if (typeof PDFJS === 'undefined') { 'use strict'; //#include ui_utils.js +//#include pdf_link_service.js //#include pdf_viewer.js PDFJS.PDFViewer = PDFViewer; PDFJS.PDFPageView = PDFPageView; + PDFJS.PDFLinkService = PDFLinkService; PDFJS.TextLayerBuilder = TextLayerBuilder; PDFJS.DefaultTextLayerFactory = DefaultTextLayerFactory; PDFJS.AnnotationsLayerBuilder = AnnotationsLayerBuilder; diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index d40023151..94e3f9fc7 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -215,7 +215,6 @@ var PDFViewer = (function pdfViewer() { } var pagesCount = pdfDocument.numPages; - var pagesRefMap = this.pagesRefMap = {}; var self = this; var resolvePagesPromise; @@ -280,6 +279,8 @@ var PDFViewer = (function pdfViewer() { this._pages.push(pageView); } + var linkService = this.linkService; + // Fetch all the pages since the viewport is needed before printing // starts to create the correct size canvas. Wait until one page is // rendered so we don't tie up too many resources early on. @@ -292,8 +293,7 @@ var PDFViewer = (function pdfViewer() { if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } - var refStr = pdfPage.ref.num + ' ' + pdfPage.ref.gen + ' R'; - pagesRefMap[refStr] = pageNum; + linkService.cachePageRef(pageNum, pdfPage.ref); getPagesLeft--; if (!getPagesLeft) { resolvePagesPromise(); @@ -780,6 +780,11 @@ var SimpleLinkService = (function SimpleLinkServiceClosure() { * @param {string} action */ executeNamedAction: function (action) {}, + /** + * @param {number} pageNum - page number. + * @param {Object} pageRef - reference to the page. + */ + cachePageRef: function (pageNum, pageRef) {} }; return SimpleLinkService; })(); diff --git a/web/ui_utils.js b/web/ui_utils.js index 7e798e342..b8128f212 100644 --- a/web/ui_utils.js +++ b/web/ui_utils.js @@ -179,6 +179,21 @@ function watchScroll(viewAreaElement, callback) { return state; } +/** + * Helper function to parse query string (e.g. ?param1=value&parm2=...). + */ +function parseQueryString(query) { + var parts = query.split('&'); + var params = {}; + for (var i = 0, ii = parts.length; i < ii; ++i) { + var param = parts[i].split('='); + var key = param[0].toLowerCase(); + var value = param.length > 1 ? param[1] : null; + params[decodeURIComponent(key)] = decodeURIComponent(value); + } + return params; +} + /** * Use binary search to find the index of the first item in a given array which * passes a given condition. The items are expected to be sorted in the sense diff --git a/web/viewer.html b/web/viewer.html index e7dad912b..cd6034ff9 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -68,6 +68,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/ + diff --git a/web/viewer.js b/web/viewer.js index 1e52a4170..499f4edab 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -18,11 +18,11 @@ DownloadManager, getFileName, getPDFFileNameFromURL, PDFHistory, Preferences, SidebarView, ViewHistory, Stats, PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar, - PasswordPrompt, PDFPresentationMode, HandTool, Promise, - PDFDocumentProperties, PDFOutlineView, PDFAttachmentView, + PasswordPrompt, PDFPresentationMode, PDFDocumentProperties, HandTool, + Promise, PDFLinkService, PDFOutlineView, PDFAttachmentView, OverlayManager, PDFFindController, PDFFindBar, getVisibleElements, watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState, - RenderingStates, DEFAULT_SCALE, UNKNOWN_SCALE, + parseQueryString, RenderingStates, DEFAULT_SCALE, UNKNOWN_SCALE, IGNORE_CURRENT_POSITION_ON_ZOOM: true */ 'use strict'; @@ -82,6 +82,7 @@ var mozL10n = document.mozL10n || document.webL10n; //#include view_history.js //#include pdf_find_bar.js //#include pdf_find_controller.js +//#include pdf_link_service.js //#include pdf_history.js //#include secondary_toolbar.js //#include pdf_presentation_mode.js @@ -111,6 +112,8 @@ var PDFViewerApplication = { pdfPresentationMode: null, /** @type {PDFDocumentProperties} */ pdfDocumentProperties: null, + /** @type {PDFLinkService} */ + pdfLinkService: null, pageRotation: 0, updateScaleControls: true, isInitialViewSet: false, @@ -128,21 +131,25 @@ var PDFViewerApplication = { pdfRenderingQueue.onIdle = this.cleanup.bind(this); this.pdfRenderingQueue = pdfRenderingQueue; + var pdfLinkService = new PDFLinkService(); + this.pdfLinkService = pdfLinkService; + var container = document.getElementById('viewerContainer'); var viewer = document.getElementById('viewer'); this.pdfViewer = new PDFViewer({ container: container, viewer: viewer, renderingQueue: pdfRenderingQueue, - linkService: this + linkService: pdfLinkService }); pdfRenderingQueue.setViewer(this.pdfViewer); + pdfLinkService.setViewer(this.pdfViewer); var thumbnailContainer = document.getElementById('thumbnailView'); this.pdfThumbnailViewer = new PDFThumbnailViewer({ container: thumbnailContainer, renderingQueue: pdfRenderingQueue, - linkService: this + linkService: pdfLinkService }); pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer); @@ -314,11 +321,11 @@ var PDFViewerApplication = { }, set page(val) { - this.pdfViewer.currentPageNumber = val; + this.pdfLinkService.page = val; }, - get page() { - return this.pdfViewer.currentPageNumber; + get page() { // TODO remove + return this.pdfLinkService.page; }, get supportsPrinting() { @@ -478,6 +485,7 @@ var PDFViewerApplication = { this.pdfThumbnailViewer.setDocument(null); this.pdfViewer.setDocument(null); + this.pdfLinkService.setDocument(null, null); if (typeof PDFBug !== 'undefined') { PDFBug.cleanup(); @@ -621,138 +629,6 @@ var PDFViewerApplication = { //#endif }, - navigateTo: function pdfViewNavigateTo(dest) { - var destString = ''; - var self = this; - - var goToDestination = function(destRef) { - self.pendingRefStr = null; - // dest array looks like that: - var pageNumber = destRef instanceof Object ? - self.pagesRefMap[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. - PDFHistory.push({ dest: dest, hash: destString, page: pageNumber }); - } else { - self.pdfDocument.getPageIndex(destRef).then(function (pageIndex) { - var pageNum = pageIndex + 1; - self.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] = 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]); - }); - }, - - executeNamedAction: function pdfViewExecuteNamedAction(action) { - // See PDF reference, table 8.45 - Named action - switch (action) { - case 'GoToPage': - document.getElementById('pageNumber').focus(); - break; - - case 'GoBack': - PDFHistory.back(); - break; - - case 'GoForward': - PDFHistory.forward(); - break; - - case 'Find': - if (!this.supportsIntegratedFind) { - this.findBar.toggle(); - } - 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 - } - }, - - getDestinationHash: function pdfViewGetDestinationHash(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.pagesRefMap[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.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 . - * @param {String} anchor The anchor hash, including the #. - */ - getAnchorUrl: function getAnchorUrl(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 - }, - /** * Show the error box. * @param {String} message A message that is human readable. @@ -876,6 +752,17 @@ var PDFViewerApplication = { var id = this.documentFingerprint = pdfDocument.fingerprint; var store = this.store = new ViewHistory(id); +//#if (GENERIC || B2G) + var baseDocumentUrl = null; +//#endif +//#if (FIREFOX || MOZCENTRAL) +// var baseDocumentUrl = this.url.split('#')[0]; +//#endif +//#if CHROME +// var baseDocumentUrl = location.href.split('#')[0]; +//#endif + this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl); + var pdfViewer = this.pdfViewer; pdfViewer.currentScale = scale; pdfViewer.setDocument(pdfDocument); @@ -885,7 +772,6 @@ var PDFViewerApplication = { this.pageRotation = 0; this.isInitialViewSet = false; - this.pagesRefMap = pdfViewer.pagesRefMap; this.pdfThumbnailViewer.setDocument(pdfDocument); @@ -904,7 +790,7 @@ var PDFViewerApplication = { if (!self.preferenceShowPreviousViewOnLoad && window.history.state) { window.history.replaceState(null, ''); } - PDFHistory.initialize(self.documentFingerprint, self); + PDFHistory.initialize(self.documentFingerprint, self.pdfLinkService); } store.initializedPromise.then(function resolved() { @@ -965,7 +851,7 @@ var PDFViewerApplication = { self.outline = new PDFOutlineView({ container: container, outline: outline, - linkService: self + linkService: self.pdfLinkService }); self.outline.render(); document.getElementById('viewOutline').disabled = !outline; @@ -1084,14 +970,14 @@ var PDFViewerApplication = { this.pdfViewer.currentPageNumber = 1; if (PDFHistory.initialDestination) { - this.navigateTo(PDFHistory.initialDestination); + this.pdfLinkService.navigateTo(PDFHistory.initialDestination); PDFHistory.initialDestination = null; } else if (this.initialBookmark) { - this.setHash(this.initialBookmark); + this.pdfLinkService.setHash(this.initialBookmark); PDFHistory.push({ hash: this.initialBookmark }, !!this.initialBookmark); this.initialBookmark = null; } else if (storedHash) { - this.setHash(storedHash); + this.pdfLinkService.setHash(storedHash); } else if (scale) { this.setScale(scale, true); this.page = 1; @@ -1116,84 +1002,6 @@ var PDFViewerApplication = { this.pdfRenderingQueue.renderHighestPriority(); }, - setHash: function pdfViewSetHash(hash) { - if (!this.isInitialViewSet) { - this.initialBookmark = hash; - return; - } - if (!hash) { - return; - } - - if (hash.indexOf('=') >= 0) { - var params = this.parseQueryString(hash); - // borrowing syntax from "Parameters for Opening PDF Files" - if ('nameddest' in params) { - 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 - PDFHistory.updateNextHashParam(unescape(hash)); - this.navigateTo(unescape(hash)); - } - }, - refreshThumbnailViewer: function pdfViewRefreshThumbnailViewer() { var pdfViewer = this.pdfViewer; var thumbnailViewer = this.pdfThumbnailViewer; @@ -1269,19 +1077,6 @@ var PDFViewerApplication = { } }, - // Helper function to parse query string (e.g. ?param1=value&parm2=...). - parseQueryString: function pdfViewParseQueryString(query) { - var parts = query.split('&'); - var params = {}; - for (var i = 0, ii = parts.length; i < ii; ++i) { - var param = parts[i].split('='); - var key = param[0].toLowerCase(); - var value = param.length > 1 ? param[1] : null; - params[decodeURIComponent(key)] = decodeURIComponent(value); - } - return params; - }, - beforePrint: function pdfViewSetupBeforePrint() { if (!this.supportsPrinting) { var printMessage = mozL10n.get('printing_not_supported', null, @@ -1430,7 +1225,7 @@ window.PDFView = PDFViewerApplication; // obsolete name, using it as an alias // // Run this code outside DOMContentLoaded to make sure that the URL // // is rewritten as soon as possible. // var queryString = document.location.search.slice(1); -// var params = PDFViewerApplication.parseQueryString(queryString); +// var params = parseQueryString(queryString); // DEFAULT_URL = params.file || ''; // // // Example: chrome-extension://.../http://example.com/file.pdf @@ -1449,7 +1244,7 @@ function webViewerLoad(evt) { function webViewerInitialized() { //#if (GENERIC || B2G) var queryString = document.location.search.substring(1); - var params = PDFViewerApplication.parseQueryString(queryString); + var params = parseQueryString(queryString); var file = 'file' in params ? params.file : DEFAULT_URL; //#endif //#if (FIREFOX || MOZCENTRAL) @@ -1489,7 +1284,7 @@ function webViewerInitialized() { //#endif // Special debugging flags in the hash section of the URL. var hash = document.location.hash.substring(1); - var hashParams = PDFViewerApplication.parseQueryString(hash); + var hashParams = parseQueryString(hash); if ('disableworker' in hashParams) { PDFJS.disableWorker = (hashParams['disableworker'] === 'true'); @@ -1785,6 +1580,23 @@ document.addEventListener('textlayerrendered', function (e) { //#endif }, true); +document.addEventListener('namedaction', function (e) { + // Processing couple of named actions that might be useful. + // See also PDFLinkService.executeNamedAction + var action = e.action; + switch (action) { + case 'GoToPage': + document.getElementById('pageNumber').focus(); + break; + + case 'Find': + if (!this.supportsIntegratedFind) { + this.findBar.toggle(); + } + break; + } +}, true); + window.addEventListener('presentationmodechanged', function (e) { var active = e.detail.active; var switchInProgress = e.detail.switchInProgress; @@ -1817,7 +1629,8 @@ window.addEventListener('updateviewarea', function (evt) { // unable to write to storage }); }); - var href = PDFViewerApplication.getAnchorUrl(location.pdfOpenParams); + var href = + PDFViewerApplication.pdfLinkService.getAnchorUrl(location.pdfOpenParams); document.getElementById('viewBookmark').href = href; document.getElementById('secondaryViewBookmark').href = href; @@ -1853,7 +1666,15 @@ window.addEventListener('resize', function webViewerResize(evt) { window.addEventListener('hashchange', function webViewerHashchange(evt) { if (PDFHistory.isHashChangeUnlocked) { - PDFViewerApplication.setHash(document.location.hash.substring(1)); + var hash = document.location.hash.substring(1); + if (!hash) { + return; + } + if (!PDFViewerApplication.isInitialViewSet) { + PDFViewerApplication.initialBookmark = hash; + } else { + PDFViewerApplication.pdfLinkService.setHash(hash); + } } });