Add support for PageLabels in the viewer
This patch implements the page label functionality in a similar way as Adobe Reader. For documents with page labels, if a non-existent page label is entered we'll try to fallback to the page number instead. The patch also includes a preference (`disablePageLabels`), to make it easy to opt-out of using page labels if the user/implementor so wishes. The way that `get/set currentPageLabel` is implemented in `PDFViewer`, is as wrappers for the corresponding `get/set currentPageNumber` functions, since that seemed like the cleanest solution. The page labels are purposely *only* added to the page controls in the viewer UI, and not stored in e.g. the `ViewHistory`. Since doing so would mean adding unnecessary code complexity, without any real added value, and would also mean delaying the inital loading of PDF documents. Note that this patch will ignore page labels if they are identical to standard page numbering, since in this case displaying the page labels adds no value (but only UI noise). The reason for handling this case specially, is that in practice a surprising number of PDF files include "pointless" page labels.
This commit is contained in:
parent
23ec02bb93
commit
f461fd64aa
@ -89,6 +89,10 @@
|
||||
],
|
||||
"default": 0
|
||||
},
|
||||
"disablePageLabels": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"disableTelemetry": {
|
||||
"title": "Disable telemetry",
|
||||
"type": "boolean",
|
||||
|
@ -20,9 +20,13 @@ next_label=Next
|
||||
|
||||
# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input.
|
||||
page.title=Page
|
||||
# LOCALIZATION NOTE (page_of): "{{pageCount}}" will be replaced by a number
|
||||
# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number
|
||||
# representing the total number of pages in the document.
|
||||
page_of=of {{pageCount}}
|
||||
of_pages=of {{pagesCount}}
|
||||
# LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}"
|
||||
# will be replaced by a number representing the currently visible page,
|
||||
# respectively a number representing the total number of pages in the document.
|
||||
+page_of_pages=({{pageNumber}} of {{pagesCount}})
|
||||
|
||||
zoom_out.title=Zoom Out
|
||||
zoom_out_label=Zoom Out
|
||||
|
@ -20,9 +20,13 @@ next_label=Nästa
|
||||
|
||||
# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input.
|
||||
page.title=Sida
|
||||
# LOCALIZATION NOTE (page_of): "{{pageCount}}" will be replaced by a number
|
||||
# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number
|
||||
# representing the total number of pages in the document.
|
||||
page_of=av {{pageCount}}
|
||||
of_pages=av {{pagesCount}}
|
||||
# LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}"
|
||||
# will be replaced by a number representing the currently active visible page,
|
||||
# respectively a number representing the total number of pages in the document.
|
||||
page_of_pages=({{pageNumber}} av {{pagesCount}})
|
||||
|
||||
zoom_out.title=Zooma ut
|
||||
zoom_out_label=Zooma ut
|
||||
|
64
web/app.js
64
web/app.js
@ -178,10 +178,12 @@ var PDFViewerApplication = {
|
||||
preferencePdfBugEnabled: false,
|
||||
preferenceShowPreviousViewOnLoad: true,
|
||||
preferenceDefaultZoomValue: '',
|
||||
preferenceDisablePageLabels: false,
|
||||
isViewerEmbedded: (window.parent !== window),
|
||||
url: '',
|
||||
baseUrl: '',
|
||||
externalServices: DefaultExernalServices,
|
||||
hasPageLabels: false,
|
||||
|
||||
// called once when the document is loaded
|
||||
initialize: function pdfViewInitialize(appConfig) {
|
||||
@ -380,6 +382,9 @@ var PDFViewerApplication = {
|
||||
// before the various viewer components are initialized.
|
||||
self.pdfViewer.renderInteractiveForms = value;
|
||||
}),
|
||||
Preferences.get('disablePageLabels').then(function resolved(value) {
|
||||
self.preferenceDisablePageLabels = value;
|
||||
}),
|
||||
// TODO move more preferences and other async stuff here
|
||||
]).catch(function (reason) { });
|
||||
|
||||
@ -567,6 +572,7 @@ var PDFViewerApplication = {
|
||||
}
|
||||
this.store = null;
|
||||
this.isInitialViewSet = false;
|
||||
this.hasPageLabels = false;
|
||||
|
||||
this.pdfSidebar.reset();
|
||||
this.pdfOutlineViewer.reset();
|
||||
@ -879,7 +885,8 @@ var PDFViewerApplication = {
|
||||
|
||||
this.pageRotation = 0;
|
||||
|
||||
this.pdfThumbnailViewer.setDocument(pdfDocument);
|
||||
var pdfThumbnailViewer = this.pdfThumbnailViewer;
|
||||
pdfThumbnailViewer.setDocument(pdfDocument);
|
||||
|
||||
firstPagePromise.then(function(pdfPage) {
|
||||
downloadedPromise.then(function () {
|
||||
@ -959,6 +966,33 @@ var PDFViewerApplication = {
|
||||
});
|
||||
});
|
||||
|
||||
pdfDocument.getPageLabels().then(function (labels) {
|
||||
if (!labels || self.preferenceDisablePageLabels) {
|
||||
return;
|
||||
}
|
||||
var i = 0, numLabels = labels.length;
|
||||
if (numLabels !== self.pagesCount) {
|
||||
console.error('The number of Page Labels does not match ' +
|
||||
'the number of pages in the document.');
|
||||
return;
|
||||
}
|
||||
// Ignore page labels that correspond to standard page numbering.
|
||||
while (i < numLabels && labels[i] === (i + 1).toString()) {
|
||||
i++;
|
||||
}
|
||||
if (i === numLabels) {
|
||||
return;
|
||||
}
|
||||
|
||||
pdfViewer.setPageLabels(labels);
|
||||
pdfThumbnailViewer.setPageLabels(labels);
|
||||
|
||||
self.hasPageLabels = true;
|
||||
self._updateUIToolbar({
|
||||
resetNumPages: true,
|
||||
});
|
||||
});
|
||||
|
||||
pagesPromise.then(function() {
|
||||
if (self.supportsPrinting) {
|
||||
pdfDocument.getJavaScript().then(function(javaScript) {
|
||||
@ -1186,6 +1220,7 @@ var PDFViewerApplication = {
|
||||
/**
|
||||
* @typedef UpdateUIToolbarParameters
|
||||
* @property {number} pageNumber
|
||||
* @property {string} pageLabel
|
||||
* @property {string} scaleValue
|
||||
* @property {number} scale
|
||||
* @property {boolean} resetNumPages
|
||||
@ -1226,11 +1261,25 @@ var PDFViewerApplication = {
|
||||
var pagesCount = this.pagesCount;
|
||||
|
||||
if (resetNumPages) {
|
||||
toolbarConfig.numPages.textContent =
|
||||
mozL10n.get('page_of', { pageCount: pagesCount }, 'of {{pageCount}}');
|
||||
if (this.hasPageLabels) {
|
||||
toolbarConfig.pageNumber.type = 'text';
|
||||
} else {
|
||||
toolbarConfig.pageNumber.type = 'number';
|
||||
toolbarConfig.numPages.textContent = mozL10n.get('of_pages',
|
||||
{ pagesCount: pagesCount }, 'of {{pagesCount}}');
|
||||
}
|
||||
toolbarConfig.pageNumber.max = pagesCount;
|
||||
}
|
||||
toolbarConfig.pageNumber.value = pageNumber;
|
||||
|
||||
if (this.hasPageLabels) {
|
||||
toolbarConfig.pageNumber.value = params.pageLabel ||
|
||||
this.pdfViewer.currentPageLabel;
|
||||
toolbarConfig.numPages.textContent = mozL10n.get('page_of_pages',
|
||||
{ pageNumber: pageNumber, pagesCount: pagesCount },
|
||||
'({{pageNumber}} of {{pagesCount}})');
|
||||
} else {
|
||||
toolbarConfig.pageNumber.value = pageNumber;
|
||||
}
|
||||
|
||||
toolbarConfig.previous.disabled = (pageNumber <= 1);
|
||||
toolbarConfig.next.disabled = (pageNumber >= pagesCount);
|
||||
@ -1495,11 +1544,13 @@ function webViewerInitialized() {
|
||||
});
|
||||
|
||||
appConfig.toolbar.pageNumber.addEventListener('change', function() {
|
||||
PDFViewerApplication.page = (this.value | 0);
|
||||
var pdfViewer = PDFViewerApplication.pdfViewer;
|
||||
pdfViewer.currentPageLabel = this.value;
|
||||
|
||||
// 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()) {
|
||||
if (this.value !== pdfViewer.currentPageNumber.toString() &&
|
||||
this.value !== pdfViewer.currentPageLabel) {
|
||||
PDFViewerApplication._updateUIToolbar({});
|
||||
}
|
||||
});
|
||||
@ -1930,6 +1981,7 @@ function webViewerPageChanging(e) {
|
||||
|
||||
PDFViewerApplication._updateUIToolbar({
|
||||
pageNumber: page,
|
||||
pageLabel: e.pageLabel,
|
||||
});
|
||||
|
||||
if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
|
||||
|
@ -13,5 +13,6 @@
|
||||
"useOnlyCssZoom": false,
|
||||
"externalLinkTarget": 0,
|
||||
"enhanceTextSelection": false,
|
||||
"renderInteractiveForms": false
|
||||
"renderInteractiveForms": false,
|
||||
"disablePageLabels": false
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() {
|
||||
*/
|
||||
_resetView: function PDFThumbnailViewer_resetView() {
|
||||
this.thumbnails = [];
|
||||
this._pageLabels = null;
|
||||
this._pagesRotation = 0;
|
||||
this._pagesRequests = [];
|
||||
|
||||
@ -179,6 +180,24 @@ var PDFThumbnailViewer = (function PDFThumbnailViewerClosure() {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Array|null} labels
|
||||
*/
|
||||
setPageLabels: function PDFThumbnailViewer_setPageLabels(labels) {
|
||||
if (!this.pdfDocument) {
|
||||
return;
|
||||
}
|
||||
if (!labels) {
|
||||
this._pageLabels = null;
|
||||
} else if (!(labels instanceof Array &&
|
||||
this.pdfDocument.numPages === labels.length)) {
|
||||
this._pageLabels = null;
|
||||
console.error('PDFThumbnailViewer_setPageLabels: Invalid page labels.');
|
||||
} else {
|
||||
this._pageLabels = labels;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {PDFThumbnailView} thumbView
|
||||
* @returns {PDFPage}
|
||||
|
@ -211,6 +211,7 @@ var PDFViewer = (function pdfViewer() {
|
||||
var arg = {
|
||||
source: this,
|
||||
pageNumber: val,
|
||||
pageLabel: this._pageLabels && this._pageLabels[val - 1],
|
||||
};
|
||||
this._currentPageNumber = val;
|
||||
this.eventBus.dispatch('pagechanging', arg);
|
||||
@ -221,6 +222,28 @@ var PDFViewer = (function pdfViewer() {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {string|null} Returns the current page label,
|
||||
* or `null` if no page labels exist.
|
||||
*/
|
||||
get currentPageLabel() {
|
||||
return this._pageLabels && this._pageLabels[this._currentPageNumber - 1];
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} val - The page label.
|
||||
*/
|
||||
set currentPageLabel(val) {
|
||||
var pageNumber = val | 0; // Fallback page number.
|
||||
if (this._pageLabels) {
|
||||
var i = this._pageLabels.indexOf(val);
|
||||
if (i >= 0) {
|
||||
pageNumber = i + 1;
|
||||
}
|
||||
}
|
||||
this.currentPageNumber = pageNumber;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
@ -414,11 +437,30 @@ var PDFViewer = (function pdfViewer() {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Array|null} labels
|
||||
*/
|
||||
setPageLabels: function PDFViewer_setPageLabels(labels) {
|
||||
if (!this.pdfDocument) {
|
||||
return;
|
||||
}
|
||||
if (!labels) {
|
||||
this._pageLabels = null;
|
||||
} else if (!(labels instanceof Array &&
|
||||
this.pdfDocument.numPages === labels.length)) {
|
||||
this._pageLabels = null;
|
||||
console.error('PDFViewer_setPageLabels: Invalid page labels.');
|
||||
} else {
|
||||
this._pageLabels = labels;
|
||||
}
|
||||
},
|
||||
|
||||
_resetView: function () {
|
||||
this._pages = [];
|
||||
this._currentPageNumber = 1;
|
||||
this._currentScale = UNKNOWN_SCALE;
|
||||
this._currentScaleValue = null;
|
||||
this._pageLabels = null;
|
||||
this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
|
||||
this._location = null;
|
||||
this._pagesRotation = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user