Merge pull request #6945 from Snuffleupagus/page-labels-viewer

Add support for PageLabels in the viewer (issue 6902, bug 793632)
This commit is contained in:
Tim van der Meij 2016-10-31 22:59:56 +01:00 committed by GitHub
commit e9c63a2b32
11 changed files with 201 additions and 25 deletions

View File

@ -89,6 +89,10 @@
],
"default": 0
},
"disablePageLabels": {
"type": "boolean",
"default": false
},
"disableTelemetry": {
"title": "Disable telemetry",
"type": "boolean",

View File

@ -18,12 +18,15 @@ previous_label=Previous
next.title=Next Page
next_label=Next
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
page_label=Page:
page_of=of {{pageCount}}
# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input.
page.title=Page
# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number
# representing the total number of pages in the document.
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

View File

@ -18,12 +18,15 @@ previous_label=Föregående
next.title=Nästa sida
next_label=Nästa
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
page_label=Sida:
page_of=av {{pageCount}}
# LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input.
page.title=Sida
# LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number
# representing the total number of pages in the document.
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

View File

@ -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) {

View File

@ -13,5 +13,6 @@
"useOnlyCssZoom": false,
"externalLinkTarget": 0,
"enhanceTextSelection": false,
"renderInteractiveForms": false
"renderInteractiveForms": false,
"disablePageLabels": false
}

View File

@ -78,6 +78,7 @@ var PDFPageView = (function PDFPageViewClosure() {
this.id = id;
this.renderingId = 'page' + id;
this.pageLabel = null;
this.rotation = 0;
this.scale = scale || DEFAULT_SCALE;
@ -554,6 +555,19 @@ var PDFPageView = (function PDFPageViewClosure() {
}
return promise;
},
/**
* @param {string|null} label
*/
setPageLabel: function PDFView_setPageLabel(label) {
this.pageLabel = (typeof label === 'string' ? label : null);
if (this.pageLabel !== null) {
this.div.setAttribute('data-page-label', this.pageLabel);
} else {
this.div.removeAttribute('data-page-label');
}
},
};
return PDFPageView;

View File

@ -91,6 +91,7 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
this.id = id;
this.renderingId = 'thumbnail' + id;
this.pageLabel = null;
this.pdfPage = null;
this.rotation = 0;
@ -120,6 +121,7 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
linkService.page = id;
return false;
};
this.anchor = anchor;
var div = document.createElement('div');
div.id = 'thumbnailContainer' + id;
@ -247,7 +249,7 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
}
var id = this.renderingId;
var className = 'thumbnailImage';
var ariaLabel = mozL10n.get('thumb_page_canvas', { page: this.id },
var ariaLabel = mozL10n.get('thumb_page_canvas', { page: this.pageId },
'Thumbnail of Page {{page}}');
if (this.disableCanvasToImageConversion) {
@ -395,7 +397,32 @@ var PDFThumbnailView = (function PDFThumbnailViewClosure() {
ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
0, 0, canvas.width, canvas.height);
this._convertCanvasToImage();
}
},
get pageId() {
return (this.pageLabel !== null ? this.pageLabel : this.id);
},
/**
* @param {string|null} label
*/
setPageLabel: function PDFThumbnailView_setPageLabel(label) {
this.pageLabel = (typeof label === 'string' ? label : null);
this.anchor.title = mozL10n.get('thumb_page_title', { page: this.pageId },
'Page {{page}}');
if (this.renderingState !== RenderingStates.FINISHED) {
return;
}
var ariaLabel = mozL10n.get('thumb_page_canvas', { page: this.pageId },
'Thumbnail of Page {{page}}');
if (this.image) {
this.image.setAttribute('aria-label', ariaLabel);
} else if (this.disableCanvasToImageConversion && this.canvas) {
this.canvas.setAttribute('aria-label', ariaLabel);
}
},
};
return PDFThumbnailView;

View File

@ -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,30 @@ 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;
}
// Update all the `PDFThumbnailView` instances.
for (var i = 0, ii = this.thumbnails.length; i < ii; i++) {
var thumbnailView = this.thumbnails[i];
var label = this._pageLabels && this._pageLabels[i];
thumbnailView.setPageLabel(label);
}
},
/**
* @param {PDFThumbnailView} thumbView
* @returns {PDFPage}

View File

@ -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,36 @@ 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;
}
// Update all the `PDFPageView` instances.
for (var i = 0, ii = this._pages.length; i < ii; i++) {
var pageView = this._pages[i];
var label = this._pageLabels && this._pageLabels[i];
pageView.setPageLabel(label);
}
},
_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;

View File

@ -1939,7 +1939,7 @@ html[dir='rtl'] #documentPropertiesOverlay .row > * {
}
@media all and (max-width: 510px) {
#scaleSelectContainer, #pageNumberLabel {
#scaleSelectContainer {
display: none;
}
}

View File

@ -194,8 +194,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<span data-l10n-id="next_label">Next</span>
</button>
</div>
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: </label>
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1" tabindex="15">
<input type="number" id="pageNumber" class="toolbarField pageNumber" title="Page" value="1" size="4" min="1" tabindex="15" data-l10n-id="page">
<span id="numPages" class="toolbarLabel"></span>
</div>
<div id="toolbarViewerRight">
@ -236,7 +235,7 @@ See https://github.com/adobe-type-tools/cmap-resources
</button>
</div>
<span id="scaleSelectContainer" class="dropdownToolbarButton">
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
<option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
<option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Fit Page</option>