Merge pull request #7789 from yurydelendik/toolbar

Refactor toolbar.
This commit is contained in:
Yury Delendik 2016-11-18 12:53:51 -06:00 committed by GitHub
commit f6a8d9c4dd
7 changed files with 457 additions and 231 deletions

View File

@ -5,6 +5,7 @@
(function(window) { (function(window) {
var gLanguage = ''; var gLanguage = '';
var gExternalLocalizerServices = null; var gExternalLocalizerServices = null;
var gReadyState = 'loading';
// fetch an l10n objects // fetch an l10n objects
function getL10nData(key) { function getL10nData(key) {
@ -99,6 +100,8 @@
translateFragment(); translateFragment();
gReadyState = 'complete';
// fire a 'localized' DOM event // fire a 'localized' DOM event
var evtObject = document.createEvent('Event'); var evtObject = document.createEvent('Event');
evtObject.initEvent('localized', false, false); evtObject.initEvent('localized', false, false);
@ -135,6 +138,8 @@
return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr'; return (rtlList.indexOf(shortCode) >= 0) ? 'rtl' : 'ltr';
}, },
getReadyState: function() { return gReadyState; },
setExternalLocalizerServices: function (externalLocalizerServices) { setExternalLocalizerServices: function (externalLocalizerServices) {
gExternalLocalizerServices = externalLocalizerServices; gExternalLocalizerServices = externalLocalizerServices;

View File

@ -101,9 +101,7 @@ document.webL10n = (function(window, document, undefined) {
function xhrLoadText(url, onSuccess, onFailure) { function xhrLoadText(url, onSuccess, onFailure) {
onSuccess = onSuccess || function _onSuccess(data) {}; onSuccess = onSuccess || function _onSuccess(data) {};
onFailure = onFailure || function _onFailure() { onFailure = onFailure || function _onFailure() {};
console.warn(url + ' not found.');
};
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', url, gAsyncResourceLoading); xhr.open('GET', url, gAsyncResourceLoading);
@ -244,7 +242,10 @@ document.webL10n = (function(window, document, undefined) {
function loadImport(url, callback) { function loadImport(url, callback) {
xhrLoadText(url, function(content) { xhrLoadText(url, function(content) {
parseRawLines(content, false, callback); // don't allow recursive imports parseRawLines(content, false, callback); // don't allow recursive imports
}, null); }, function () {
console.warn(url + ' not found.');
callback();
});
} }
// fill the dictionary // fill the dictionary

View File

@ -22,20 +22,22 @@
'pdfjs-web/download_manager', 'pdfjs-web/pdf_history', 'pdfjs-web/download_manager', 'pdfjs-web/pdf_history',
'pdfjs-web/preferences', 'pdfjs-web/pdf_sidebar', 'pdfjs-web/preferences', 'pdfjs-web/pdf_sidebar',
'pdfjs-web/view_history', 'pdfjs-web/pdf_thumbnail_viewer', 'pdfjs-web/view_history', 'pdfjs-web/pdf_thumbnail_viewer',
'pdfjs-web/secondary_toolbar', 'pdfjs-web/password_prompt', 'pdfjs-web/toolbar', 'pdfjs-web/secondary_toolbar',
'pdfjs-web/pdf_presentation_mode', 'pdfjs-web/pdf_document_properties', 'pdfjs-web/password_prompt', 'pdfjs-web/pdf_presentation_mode',
'pdfjs-web/hand_tool', 'pdfjs-web/pdf_viewer', 'pdfjs-web/pdf_document_properties', 'pdfjs-web/hand_tool',
'pdfjs-web/pdf_rendering_queue', 'pdfjs-web/pdf_link_service', 'pdfjs-web/pdf_viewer', 'pdfjs-web/pdf_rendering_queue',
'pdfjs-web/pdf_outline_viewer', 'pdfjs-web/overlay_manager', 'pdfjs-web/pdf_link_service', 'pdfjs-web/pdf_outline_viewer',
'pdfjs-web/pdf_attachment_viewer', 'pdfjs-web/pdf_find_controller', 'pdfjs-web/overlay_manager', 'pdfjs-web/pdf_attachment_viewer',
'pdfjs-web/pdf_find_bar', 'pdfjs-web/dom_events', 'pdfjs-web/pdfjs'], 'pdfjs-web/pdf_find_controller', 'pdfjs-web/pdf_find_bar',
'pdfjs-web/dom_events', 'pdfjs-web/pdfjs'],
factory); factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'), require('./download_manager.js'), factory(exports, require('./ui_utils.js'), require('./download_manager.js'),
require('./pdf_history.js'), require('./preferences.js'), require('./pdf_history.js'), require('./preferences.js'),
require('./pdf_sidebar.js'), require('./view_history.js'), require('./pdf_sidebar.js'), require('./view_history.js'),
require('./pdf_thumbnail_viewer.js'), require('./secondary_toolbar.js'), require('./pdf_thumbnail_viewer.js'), require('./toolbar.js'),
require('./password_prompt.js'), require('./pdf_presentation_mode.js'), require('./secondary_toolbar.js'), require('./password_prompt.js'),
require('./pdf_presentation_mode.js'),
require('./pdf_document_properties.js'), require('./hand_tool.js'), require('./pdf_document_properties.js'), require('./hand_tool.js'),
require('./pdf_viewer.js'), require('./pdf_rendering_queue.js'), require('./pdf_viewer.js'), require('./pdf_rendering_queue.js'),
require('./pdf_link_service.js'), require('./pdf_outline_viewer.js'), require('./pdf_link_service.js'), require('./pdf_outline_viewer.js'),
@ -47,25 +49,28 @@
root.pdfjsWebDownloadManager, root.pdfjsWebPDFHistory, root.pdfjsWebDownloadManager, root.pdfjsWebPDFHistory,
root.pdfjsWebPreferences, root.pdfjsWebPDFSidebar, root.pdfjsWebPreferences, root.pdfjsWebPDFSidebar,
root.pdfjsWebViewHistory, root.pdfjsWebPDFThumbnailViewer, root.pdfjsWebViewHistory, root.pdfjsWebPDFThumbnailViewer,
root.pdfjsWebSecondaryToolbar, root.pdfjsWebPasswordPrompt, root.pdfjsWebToolbar, root.pdfjsWebSecondaryToolbar,
root.pdfjsWebPDFPresentationMode, root.pdfjsWebPDFDocumentProperties, root.pdfjsWebPasswordPrompt, root.pdfjsWebPDFPresentationMode,
root.pdfjsWebHandTool, root.pdfjsWebPDFViewer, root.pdfjsWebPDFDocumentProperties, root.pdfjsWebHandTool,
root.pdfjsWebPDFRenderingQueue, root.pdfjsWebPDFLinkService, root.pdfjsWebPDFViewer, root.pdfjsWebPDFRenderingQueue,
root.pdfjsWebPDFOutlineViewer, root.pdfjsWebOverlayManager, root.pdfjsWebPDFLinkService, root.pdfjsWebPDFOutlineViewer,
root.pdfjsWebPDFAttachmentViewer, root.pdfjsWebPDFFindController, root.pdfjsWebOverlayManager, root.pdfjsWebPDFAttachmentViewer,
root.pdfjsWebPDFFindBar, root.pdfjsWebDOMEvents, root.pdfjsWebPDFJS); root.pdfjsWebPDFFindController, root.pdfjsWebPDFFindBar,
root.pdfjsWebDOMEvents, root.pdfjsWebPDFJS);
} }
}(this, function (exports, uiUtilsLib, downloadManagerLib, pdfHistoryLib, }(this, function (exports, uiUtilsLib, downloadManagerLib, pdfHistoryLib,
preferencesLib, pdfSidebarLib, viewHistoryLib, preferencesLib, pdfSidebarLib, viewHistoryLib,
pdfThumbnailViewerLib, secondaryToolbarLib, passwordPromptLib, pdfThumbnailViewerLib, toolbarLib, secondaryToolbarLib,
pdfPresentationModeLib, pdfDocumentPropertiesLib, handToolLib, passwordPromptLib, pdfPresentationModeLib,
pdfViewerLib, pdfRenderingQueueLib, pdfLinkServiceLib, pdfDocumentPropertiesLib, handToolLib, pdfViewerLib,
pdfOutlineViewerLib, overlayManagerLib, pdfRenderingQueueLib, pdfLinkServiceLib, pdfOutlineViewerLib,
pdfAttachmentViewerLib, pdfFindControllerLib, pdfFindBarLib, overlayManagerLib, pdfAttachmentViewerLib,
domEventsLib, pdfjsLib) { pdfFindControllerLib, pdfFindBarLib, domEventsLib, pdfjsLib) {
var UNKNOWN_SCALE = uiUtilsLib.UNKNOWN_SCALE; var UNKNOWN_SCALE = uiUtilsLib.UNKNOWN_SCALE;
var DEFAULT_SCALE_VALUE = uiUtilsLib.DEFAULT_SCALE_VALUE; var DEFAULT_SCALE_VALUE = uiUtilsLib.DEFAULT_SCALE_VALUE;
var MIN_SCALE = uiUtilsLib.MIN_SCALE;
var MAX_SCALE = uiUtilsLib.MAX_SCALE;
var ProgressBar = uiUtilsLib.ProgressBar; var ProgressBar = uiUtilsLib.ProgressBar;
var getPDFFileNameFromURL = uiUtilsLib.getPDFFileNameFromURL; var getPDFFileNameFromURL = uiUtilsLib.getPDFFileNameFromURL;
var noContextMenuHandler = uiUtilsLib.noContextMenuHandler; var noContextMenuHandler = uiUtilsLib.noContextMenuHandler;
@ -77,6 +82,7 @@ var SidebarView = pdfSidebarLib.SidebarView;
var PDFSidebar = pdfSidebarLib.PDFSidebar; var PDFSidebar = pdfSidebarLib.PDFSidebar;
var ViewHistory = viewHistoryLib.ViewHistory; var ViewHistory = viewHistoryLib.ViewHistory;
var PDFThumbnailViewer = pdfThumbnailViewerLib.PDFThumbnailViewer; var PDFThumbnailViewer = pdfThumbnailViewerLib.PDFThumbnailViewer;
var Toolbar = toolbarLib.Toolbar;
var SecondaryToolbar = secondaryToolbarLib.SecondaryToolbar; var SecondaryToolbar = secondaryToolbarLib.SecondaryToolbar;
var PasswordPrompt = passwordPromptLib.PasswordPrompt; var PasswordPrompt = passwordPromptLib.PasswordPrompt;
var PDFPresentationMode = pdfPresentationModeLib.PDFPresentationMode; var PDFPresentationMode = pdfPresentationModeLib.PDFPresentationMode;
@ -94,13 +100,10 @@ var PDFFindController = pdfFindControllerLib.PDFFindController;
var PDFFindBar = pdfFindBarLib.PDFFindBar; var PDFFindBar = pdfFindBarLib.PDFFindBar;
var getGlobalEventBus = domEventsLib.getGlobalEventBus; var getGlobalEventBus = domEventsLib.getGlobalEventBus;
var normalizeWheelEventDelta = uiUtilsLib.normalizeWheelEventDelta; var normalizeWheelEventDelta = uiUtilsLib.normalizeWheelEventDelta;
var animationStarted = uiUtilsLib.animationStarted;
var localized = uiUtilsLib.localized;
var DEFAULT_SCALE_DELTA = 1.1; var DEFAULT_SCALE_DELTA = 1.1;
var MIN_SCALE = 0.25;
var MAX_SCALE = 10.0;
var SCALE_SELECT_CONTAINER_PADDING = 8;
var SCALE_SELECT_PADDING = 22;
var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000;
function configure(PDFJS) { function configure(PDFJS) {
@ -169,11 +172,14 @@ var PDFViewerApplication = {
store: null, store: null,
/** @type {DownloadManager} */ /** @type {DownloadManager} */
downloadManager: null, downloadManager: null,
/** @type {Toolbar} */
toolbar: null,
/** @type {SecondaryToolbar} */
secondaryToolbar: null,
/** @type {EventBus} */ /** @type {EventBus} */
eventBus: null, eventBus: null,
pageRotation: 0, pageRotation: 0,
isInitialViewSet: false, isInitialViewSet: false,
animationStartedPromise: null,
preferenceSidebarViewOnLoad: SidebarView.NONE, preferenceSidebarViewOnLoad: SidebarView.NONE,
preferencePdfBugEnabled: false, preferencePdfBugEnabled: false,
preferenceShowPreviousViewOnLoad: true, preferenceShowPreviousViewOnLoad: true,
@ -183,7 +189,6 @@ var PDFViewerApplication = {
url: '', url: '',
baseUrl: '', baseUrl: '',
externalServices: DefaultExernalServices, externalServices: DefaultExernalServices,
hasPageLabels: false,
// called once when the document is loaded // called once when the document is loaded
initialize: function pdfViewInitialize(appConfig) { initialize: function pdfViewInitialize(appConfig) {
@ -274,6 +279,8 @@ var PDFViewerApplication = {
this.pdfDocumentProperties = this.pdfDocumentProperties =
new PDFDocumentProperties(appConfig.documentProperties); new PDFDocumentProperties(appConfig.documentProperties);
this.toolbar = new Toolbar(appConfig.toolbar, container, eventBus);
this.secondaryToolbar = this.secondaryToolbar =
new SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus); new SecondaryToolbar(appConfig.secondaryToolbar, container, eventBus);
@ -572,7 +579,6 @@ var PDFViewerApplication = {
} }
this.store = null; this.store = null;
this.isInitialViewSet = false; this.isInitialViewSet = false;
this.hasPageLabels = false;
this.pdfSidebar.reset(); this.pdfSidebar.reset();
this.pdfOutlineViewer.reset(); this.pdfOutlineViewer.reset();
@ -580,6 +586,8 @@ var PDFViewerApplication = {
this.findController.reset(); this.findController.reset();
this.findBar.reset(); this.findBar.reset();
this.toolbar.reset();
this.secondaryToolbar.reset();
if (typeof PDFBug !== 'undefined') { if (typeof PDFBug !== 'undefined') {
PDFBug.cleanup(); PDFBug.cleanup();
@ -859,9 +867,8 @@ var PDFViewerApplication = {
self.loadingBar.hide(); self.loadingBar.hide();
}); });
this._updateUIToolbar({ this.toolbar.setPagesCount(pdfDocument.numPages, false);
resetNumPages: true, this.secondaryToolbar.setPagesCount(pdfDocument.numPages);
});
var id = this.documentFingerprint = pdfDocument.fingerprint; var id = this.documentFingerprint = pdfDocument.fingerprint;
var store = this.store = new ViewHistory(id); var store = this.store = new ViewHistory(id);
@ -987,10 +994,11 @@ var PDFViewerApplication = {
pdfViewer.setPageLabels(labels); pdfViewer.setPageLabels(labels);
pdfThumbnailViewer.setPageLabels(labels); pdfThumbnailViewer.setPageLabels(labels);
self.hasPageLabels = true; // Changing toolbar page display to use labels and we need to set
self._updateUIToolbar({ // the label of the current page.
resetNumPages: true, self.toolbar.setPagesCount(pdfDocument.numPages, true);
}); self.toolbar.setPageNumber(pdfViewer.currentPageNumber,
pdfViewer.currentPageLabel);
}); });
pagesPromise.then(function() { pagesPromise.then(function() {
@ -1015,8 +1023,7 @@ var PDFViewerApplication = {
} }
}); });
Promise.all([onePageRendered, this.animationStartedPromise]).then( Promise.all([onePageRendered, animationStarted]).then(function() {
function() {
pdfDocument.getOutline().then(function(outline) { pdfDocument.getOutline().then(function(outline) {
self.pdfOutlineViewer.render({ outline: outline }); self.pdfOutlineViewer.render({ outline: outline });
}); });
@ -1114,6 +1121,12 @@ var PDFViewerApplication = {
this.page = 1; this.page = 1;
} }
// Ensure that the correct page number is displayed in the UI,
// even if the active page didn't change during document load.
this.toolbar.setPageNumber(this.pdfViewer.currentPageNumber,
this.pdfViewer.currentPageLabel);
this.secondaryToolbar.setPageNumber(this.pdfViewer.currentPageNumber);
if (!this.pdfViewer.currentScaleValue) { if (!this.pdfViewer.currentScaleValue) {
// Scale was not initialized: invalid bookmark or scale was not specified. // Scale was not initialized: invalid bookmark or scale was not specified.
// Setting the default one. // Setting the default one.
@ -1217,87 +1230,10 @@ var PDFViewerApplication = {
this.pdfPresentationMode.request(); this.pdfPresentationMode.request();
}, },
/**
* @typedef UpdateUIToolbarParameters
* @property {number} pageNumber
* @property {string} pageLabel
* @property {string} scaleValue
* @property {number} scale
* @property {boolean} resetNumPages
*/
/**
* @param {Object} UpdateUIToolbarParameters
* @private
*/
_updateUIToolbar: function (params) {
function selectScaleOption(value, scale) {
var options = toolbarConfig.scaleSelect.options;
var predefinedValueFound = false;
for (var i = 0, ii = options.length; i < ii; i++) {
var option = options[i];
if (option.value !== value) {
option.selected = false;
continue;
}
option.selected = true;
predefinedValueFound = true;
}
if (!predefinedValueFound) {
var customScale = Math.round(scale * 10000) / 100;
toolbarConfig.customScaleOption.textContent =
mozL10n.get('page_scale_percent', {scale: customScale}, '{{scale}}%');
toolbarConfig.customScaleOption.selected = true;
}
}
var pageNumber = params.pageNumber || this.pdfViewer.currentPageNumber;
var scaleValue = (params.scaleValue || params.scale ||
this.pdfViewer.currentScaleValue || DEFAULT_SCALE_VALUE).toString();
var scale = params.scale || this.pdfViewer.currentScale;
var resetNumPages = params.resetNumPages || false;
var toolbarConfig = this.appConfig.toolbar;
var pagesCount = this.pagesCount;
if (resetNumPages) {
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;
}
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);
toolbarConfig.firstPage.disabled = (pageNumber <= 1);
toolbarConfig.lastPage.disabled = (pageNumber >= pagesCount);
toolbarConfig.zoomOut.disabled = (scale <= MIN_SCALE);
toolbarConfig.zoomIn.disabled = (scale >= MAX_SCALE);
selectScaleOption(scaleValue, scale);
},
bindEvents: function pdfViewBindEvents() { bindEvents: function pdfViewBindEvents() {
var eventBus = this.eventBus; var eventBus = this.eventBus;
eventBus.on('resize', webViewerResize); eventBus.on('resize', webViewerResize);
eventBus.on('localized', webViewerLocalized);
eventBus.on('hashchange', webViewerHashchange); eventBus.on('hashchange', webViewerHashchange);
eventBus.on('beforeprint', this.beforePrint.bind(this)); eventBus.on('beforeprint', this.beforePrint.bind(this));
eventBus.on('afterprint', this.afterPrint.bind(this)); eventBus.on('afterprint', this.afterPrint.bind(this));
@ -1316,6 +1252,12 @@ var PDFViewerApplication = {
eventBus.on('download', webViewerDownload); eventBus.on('download', webViewerDownload);
eventBus.on('firstpage', webViewerFirstPage); eventBus.on('firstpage', webViewerFirstPage);
eventBus.on('lastpage', webViewerLastPage); eventBus.on('lastpage', webViewerLastPage);
eventBus.on('nextpage', webViewerNextPage);
eventBus.on('previouspage', webViewerPreviousPage);
eventBus.on('zoomin', webViewerZoomIn);
eventBus.on('zoomout', webViewerZoomOut);
eventBus.on('pagenumberchanged', webViewerPageNumberChanged);
eventBus.on('scalechanged', webViewerScaleChanged);
eventBus.on('rotatecw', webViewerRotateCw); eventBus.on('rotatecw', webViewerRotateCw);
eventBus.on('rotateccw', webViewerRotateCcw); eventBus.on('rotateccw', webViewerRotateCcw);
eventBus.on('documentproperties', webViewerDocumentProperties); eventBus.on('documentproperties', webViewerDocumentProperties);
@ -1509,9 +1451,6 @@ function webViewerInitialized() {
appConfig.toolbar.viewFind.classList.add('hidden'); appConfig.toolbar.viewFind.classList.add('hidden');
} }
// Suppress context menus for some controls
appConfig.toolbar.scaleSelect.oncontextmenu = noContextMenuHandler;
appConfig.sidebar.mainContainer.addEventListener('transitionend', appConfig.sidebar.mainContainer.addEventListener('transitionend',
function(e) { function(e) {
if (e.target === /* mainContainer */ this) { if (e.target === /* mainContainer */ this) {
@ -1523,63 +1462,6 @@ function webViewerInitialized() {
PDFViewerApplication.pdfSidebar.toggle(); PDFViewerApplication.pdfSidebar.toggle();
}); });
appConfig.toolbar.previous.addEventListener('click', function() {
PDFViewerApplication.page--;
});
appConfig.toolbar.next.addEventListener('click', function() {
PDFViewerApplication.page++;
});
appConfig.toolbar.zoomIn.addEventListener('click', function() {
PDFViewerApplication.zoomIn();
});
appConfig.toolbar.zoomOut.addEventListener('click', function() {
PDFViewerApplication.zoomOut();
});
appConfig.toolbar.pageNumber.addEventListener('click', function() {
this.select();
});
appConfig.toolbar.pageNumber.addEventListener('change', function() {
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 !== pdfViewer.currentPageNumber.toString() &&
this.value !== pdfViewer.currentPageLabel) {
PDFViewerApplication._updateUIToolbar({});
}
});
appConfig.toolbar.scaleSelect.addEventListener('change', function() {
if (this.value === 'custom') {
return;
}
PDFViewerApplication.pdfViewer.currentScaleValue = this.value;
});
appConfig.toolbar.presentationModeButton.addEventListener('click',
function (e) {
PDFViewerApplication.eventBus.dispatch('presentationmode');
});
appConfig.toolbar.openFile.addEventListener('click', function (e) {
PDFViewerApplication.eventBus.dispatch('openfile');
});
appConfig.toolbar.print.addEventListener('click', function (e) {
PDFViewerApplication.eventBus.dispatch('print');
});
appConfig.toolbar.download.addEventListener('click', function (e) {
PDFViewerApplication.eventBus.dispatch('download');
});
Promise.all(waitForBeforeOpening).then(function () { Promise.all(waitForBeforeOpening).then(function () {
webViewerOpenFileViaURL(file); webViewerOpenFileViaURL(file);
}).catch(function (reason) { }).catch(function (reason) {
@ -1636,8 +1518,7 @@ function webViewerPageRendered(e) {
// If the page is still visible when it has finished rendering, // If the page is still visible when it has finished rendering,
// ensure that the page number input loading indicator is hidden. // ensure that the page number input loading indicator is hidden.
if (pageNumber === PDFViewerApplication.page) { if (pageNumber === PDFViewerApplication.page) {
var pageNumberInput = PDFViewerApplication.appConfig.toolbar.pageNumber; PDFViewerApplication.toolbar.updateLoadingIndicatorState(false);
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
} }
// Prevent errors in the edge-case where the PDF document is removed *before* // Prevent errors in the edge-case where the PDF document is removed *before*
@ -1789,15 +1670,10 @@ function webViewerUpdateViewarea(e) {
location.pageNumber); location.pageNumber);
// Show/hide the loading indicator in the page number input element. // Show/hide the loading indicator in the page number input element.
var pageNumberInput = PDFViewerApplication.appConfig.toolbar.pageNumber;
var currentPage = var currentPage =
PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1); PDFViewerApplication.pdfViewer.getPageView(PDFViewerApplication.page - 1);
var loading = currentPage.renderingState !== RenderingStates.FINISHED;
if (currentPage.renderingState === RenderingStates.FINISHED) { PDFViewerApplication.toolbar.updateLoadingIndicatorState(loading);
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
} else {
pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);
}
} }
window.addEventListener('resize', function webViewerResize(evt) { window.addEventListener('resize', function webViewerResize(evt) {
@ -1884,31 +1760,9 @@ if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
}; };
} }
window.addEventListener('localized', function localized(evt) {
PDFViewerApplication.eventBus.dispatch('localized');
});
function webViewerLocalized() { function webViewerLocalized() {
document.getElementsByTagName('html')[0].dir = mozL10n.getDirection(); document.getElementsByTagName('html')[0].dir = mozL10n.getDirection();
PDFViewerApplication.eventBus.dispatch('localized');
PDFViewerApplication.animationStartedPromise.then(function() {
// Adjust the width of the zoom box to fit the content.
// Note: If the window is narrow enough that the zoom box is not visible,
// we temporarily show it to be able to adjust its width.
var container = PDFViewerApplication.appConfig.toolbar.scaleSelectContainer;
if (container.clientWidth === 0) {
container.setAttribute('style', 'display: inherit;');
}
if (container.clientWidth > 0) {
var select = PDFViewerApplication.appConfig.toolbar.scaleSelect;
select.setAttribute('style', 'min-width: inherit;');
var width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;
select.setAttribute('style', 'min-width: ' +
(width + SCALE_SELECT_PADDING) + 'px;');
container.setAttribute('style', 'min-width: ' + width + 'px; ' +
'max-width: ' + width + 'px;');
}
});
} }
function webViewerPresentationMode() { function webViewerPresentationMode() {
@ -1934,6 +1788,33 @@ function webViewerLastPage() {
PDFViewerApplication.page = PDFViewerApplication.pagesCount; PDFViewerApplication.page = PDFViewerApplication.pagesCount;
} }
} }
function webViewerNextPage() {
PDFViewerApplication.page++;
}
function webViewerPreviousPage() {
PDFViewerApplication.page--;
}
function webViewerZoomIn() {
PDFViewerApplication.zoomIn();
}
function webViewerZoomOut() {
PDFViewerApplication.zoomOut();
}
function webViewerPageNumberChanged(e) {
var pdfViewer = PDFViewerApplication.pdfViewer;
pdfViewer.currentPageLabel = e.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 (e.value !== pdfViewer.currentPageNumber.toString() &&
e.value !== pdfViewer.currentPageLabel) {
PDFViewerApplication.toolbar.setPageNumber(
pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);
}
}
function webViewerScaleChanged(e) {
PDFViewerApplication.pdfViewer.currentScaleValue = e.value;
}
function webViewerRotateCw() { function webViewerRotateCw() {
PDFViewerApplication.rotatePages(90); PDFViewerApplication.rotatePages(90);
} }
@ -1965,10 +1846,7 @@ function webViewerFindFromUrlHash(e) {
} }
function webViewerScaleChanging(e) { function webViewerScaleChanging(e) {
PDFViewerApplication._updateUIToolbar({ PDFViewerApplication.toolbar.setPageScale(e.presetValue, e.scale);
scaleValue: e.presetValue,
scale: e.scale,
});
if (!PDFViewerApplication.initialized) { if (!PDFViewerApplication.initialized) {
return; return;
@ -1979,10 +1857,8 @@ function webViewerScaleChanging(e) {
function webViewerPageChanging(e) { function webViewerPageChanging(e) {
var page = e.pageNumber; var page = e.pageNumber;
PDFViewerApplication._updateUIToolbar({ PDFViewerApplication.toolbar.setPageNumber(page, e.pageLabel || null);
pageNumber: page, PDFViewerApplication.secondaryToolbar.setPageNumber(page);
pageLabel: e.pageLabel,
});
if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page); PDFViewerApplication.pdfThumbnailViewer.scrollThumbnailIntoView(page);
@ -2332,14 +2208,7 @@ window.addEventListener('afterprint', function afterPrint(evt) {
PDFViewerApplication.eventBus.dispatch('afterprint'); PDFViewerApplication.eventBus.dispatch('afterprint');
}); });
(function animationStartedClosure() { localized.then(webViewerLocalized);
// 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);
});
})();
/* Abstract factory for the print service. */ /* Abstract factory for the print service. */
var PDFPrintServiceFactory = { var PDFPrintServiceFactory = {

View File

@ -91,6 +91,12 @@ var SecondaryToolbar = (function SecondaryToolbarClosure() {
{ element: options.documentPropertiesButton, { element: options.documentPropertiesButton,
eventName: 'documentproperties', close: true } eventName: 'documentproperties', close: true }
]; ];
this.items = {
firstPage: options.firstPageButton,
lastPage: options.lastPageButton,
pageRotateCw: options.pageRotateCwButton,
pageRotateCcw: options.pageRotateCcwButton,
};
this.mainContainer = mainContainer; this.mainContainer = mainContainer;
this.eventBus = eventBus; this.eventBus = eventBus;
@ -99,6 +105,8 @@ var SecondaryToolbar = (function SecondaryToolbarClosure() {
this.containerHeight = null; this.containerHeight = null;
this.previousContainerHeight = null; this.previousContainerHeight = null;
this.reset();
// Bind the event listeners for click and hand tool actions. // Bind the event listeners for click and hand tool actions.
this._bindClickListeners(); this._bindClickListeners();
this._bindHandToolListener(options.toggleHandToolButton); this._bindHandToolListener(options.toggleHandToolButton);
@ -115,6 +123,31 @@ var SecondaryToolbar = (function SecondaryToolbarClosure() {
return this.opened; return this.opened;
}, },
setPageNumber: function SecondaryToolbar_setPageNumber(pageNumber) {
this.pageNumber = pageNumber;
this._updateUIState();
},
setPagesCount: function SecondaryToolbar_setPagesCount(pagesCount) {
this.pagesCount = pagesCount;
this._updateUIState();
},
reset: function SecondaryToolbar_reset() {
this.pageNumber = 0;
this.pagesCount = 0;
this._updateUIState();
},
_updateUIState: function SecondaryToolbar_updateUIState() {
var items = this.items;
items.firstPage.disabled = (this.pageNumber <= 1);
items.lastPage.disabled = (this.pageNumber >= this.pagesCount);
items.pageRotateCw.disabled = this.pagesCount === 0;
items.pageRotateCcw.disabled = this.pagesCount === 0;
},
_bindClickListeners: function SecondaryToolbar_bindClickListeners() { _bindClickListeners: function SecondaryToolbar_bindClickListeners() {
// Button to toggle the visibility of the secondary toolbar. // Button to toggle the visibility of the secondary toolbar.
this.toggleButton.addEventListener('click', this.toggle.bind(this)); this.toggleButton.addEventListener('click', this.toggle.bind(this));

290
web/toolbar.js Normal file
View File

@ -0,0 +1,290 @@
/* Copyright 2016 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.
*/
'use strict';
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define('pdfjs-web/toolbar', ['exports', 'pdfjs-web/ui_utils'],
factory);
} else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'));
} else {
factory((root.pdfjsWebToolbar = {}), root.pdfjsWebUIUtils);
}
}(this, function (exports, uiUtils) {
var mozL10n = uiUtils.mozL10n;
var noContextMenuHandler = uiUtils.noContextMenuHandler;
var animationStarted = uiUtils.animationStarted;
var localized = uiUtils.localized;
var DEFAULT_SCALE_VALUE = uiUtils.DEFAULT_SCALE_VALUE;
var DEFAULT_SCALE = uiUtils.DEFAULT_SCALE;
var MIN_SCALE = uiUtils.MIN_SCALE;
var MAX_SCALE = uiUtils.MAX_SCALE;
var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
var SCALE_SELECT_CONTAINER_PADDING = 8;
var SCALE_SELECT_PADDING = 22;
/**
* @typedef {Object} ToolbarOptions
* @property {HTMLDivElement} container - Container for the secondary toolbar.
* @property {HTMLSpanElement} numPages - Label that contains number of pages.
* @property {HTMLInputElement} pageNumber - Control for display and user input
* of the current page number.
* @property {HTMLSpanElement} scaleSelectContainer - Container where scale
* controls are placed. The width is adjusted on UI initialization.
* @property {HTMLSelectElement} scaleSelect - Scale selection control.
* @property {HTMLOptionElement} customScaleOption - The item used to display
* a non-predefined scale.
* @property {HTMLButtonElement} previous - Button to go to the previous page.
* @property {HTMLButtonElement} next - Button to go to the next page.
* @property {HTMLButtonElement} zoomIn - Button to zoom in the pages.
* @property {HTMLButtonElement} zoomOut - Button to zoom out the pages.
* @property {HTMLButtonElement} viewFind - Button to open find bar.
* @property {HTMLButtonElement} openFile - Button to open a new document.
* @property {HTMLButtonElement} presentationModeButton - Button to switch to
* presentation mode.
* @property {HTMLButtonElement} download - Button to download the document.
* @property {HTMLAElement} viewBookmark - Element to link current url of
* the page view.
*/
/**
* @class
*/
var Toolbar = (function ToolbarClosure() {
/**
* @constructs Toolbar
* @param {ToolbarOptions} options
* @param {HTMLDivElement} mainContainer
* @param {EventBus} eventBus
*/
function Toolbar(options, mainContainer, eventBus) {
this.toolbar = options.container;
this.mainContainer = mainContainer;
this.eventBus = eventBus;
this.items = options;
this._wasLocalized = false;
this.reset();
// Bind the event listeners for click and hand tool actions.
this._bindListeners();
}
Toolbar.prototype = {
setPageNumber: function (pageNumber, pageLabel) {
this.pageNumber = pageNumber;
this.pageLabel = pageLabel;
this._updateUIState(false);
},
setPagesCount: function (pagesCount, hasPageLabels) {
this.pagesCount = pagesCount;
this.hasPageLabels = hasPageLabels;
this._updateUIState(true);
},
setPageScale: function (pageScaleValue, pageScale) {
this.pageScaleValue = pageScaleValue;
this.pageScale = pageScale;
this._updateUIState(false);
},
reset: function () {
this.pageNumber = 0;
this.pageLabel = null;
this.hasPageLabels = false;
this.pagesCount = 0;
this.pageScaleValue = DEFAULT_SCALE_VALUE;
this.pageScale = DEFAULT_SCALE;
this._updateUIState(true);
},
_bindListeners: function Toolbar_bindClickListeners() {
var eventBus = this.eventBus;
var self = this;
var items = this.items;
items.previous.addEventListener('click', function() {
eventBus.dispatch('previouspage');
});
items.next.addEventListener('click', function() {
eventBus.dispatch('nextpage');
});
items.zoomIn.addEventListener('click', function() {
eventBus.dispatch('zoomin');
});
items.zoomOut.addEventListener('click', function() {
eventBus.dispatch('zoomout');
});
items.pageNumber.addEventListener('click', function() {
this.select();
});
items.pageNumber.addEventListener('change', function() {
eventBus.dispatch('pagenumberchanged', {
source: self,
value: this.value
});
});
items.scaleSelect.addEventListener('change', function() {
if (this.value === 'custom') {
return;
}
eventBus.dispatch('scalechanged', {
source: self,
value: this.value
});
});
items.presentationModeButton.addEventListener('click',
function (e) {
eventBus.dispatch('presentationmode');
});
items.openFile.addEventListener('click', function (e) {
eventBus.dispatch('openfile');
});
items.print.addEventListener('click', function (e) {
eventBus.dispatch('print');
});
items.download.addEventListener('click', function (e) {
eventBus.dispatch('download');
});
// Suppress context menus for some controls
items.scaleSelect.oncontextmenu = noContextMenuHandler;
localized.then(this._localized.bind(this));
},
_localized: function Toolbar_localized() {
this._wasLocalized = true;
this._adjustScaleWidth();
this._updateUIState(true);
},
_updateUIState: function Toolbar_updateUIState(resetNumPages) {
function selectScaleOption(value, scale) {
var options = items.scaleSelect.options;
var predefinedValueFound = false;
for (var i = 0, ii = options.length; i < ii; i++) {
var option = options[i];
if (option.value !== value) {
option.selected = false;
continue;
}
option.selected = true;
predefinedValueFound = true;
}
if (!predefinedValueFound) {
var customScale = Math.round(scale * 10000) / 100;
items.customScaleOption.textContent =
mozL10n.get('page_scale_percent', {scale: customScale},
'{{scale}}%');
items.customScaleOption.selected = true;
}
}
if (!this._wasLocalized) {
// Don't update UI state until we will localize the toolbar.
return;
}
var pageNumber = this.pageNumber;
var scaleValue = (this.pageScaleValue || this.pageScale).toString();
var scale = this.pageScale;
var items = this.items;
var pagesCount = this.pagesCount;
if (resetNumPages) {
if (this.hasPageLabels) {
items.pageNumber.type = 'text';
} else {
items.pageNumber.type = 'number';
items.numPages.textContent = mozL10n.get('of_pages',
{ pagesCount: pagesCount }, 'of {{pagesCount}}');
}
items.pageNumber.max = pagesCount;
}
if (this.hasPageLabels) {
items.pageNumber.value = this.pageLabel;
items.numPages.textContent = mozL10n.get('page_of_pages',
{ pageNumber: pageNumber, pagesCount: pagesCount },
'({{pageNumber}} of {{pagesCount}})');
} else {
items.pageNumber.value = pageNumber;
}
items.previous.disabled = (pageNumber <= 1);
items.next.disabled = (pageNumber >= pagesCount);
items.zoomOut.disabled = (scale <= MIN_SCALE);
items.zoomIn.disabled = (scale >= MAX_SCALE);
selectScaleOption(scaleValue, scale);
},
updateLoadingIndicatorState:
function Toolbar_updateLoadingIndicatorState(loading) {
var pageNumberInput = this.items.pageNumber;
if (loading) {
pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);
} else {
pageNumberInput.classList.remove(PAGE_NUMBER_LOADING_INDICATOR);
}
},
_adjustScaleWidth: function Toolbar_adjustScaleWidth() {
var container = this.items.scaleSelectContainer;
var select = this.items.scaleSelect;
animationStarted.then(function() {
// Adjust the width of the zoom box to fit the content.
// Note: If the window is narrow enough that the zoom box is not
// visible, we temporarily show it to be able to adjust its width.
if (container.clientWidth === 0) {
container.setAttribute('style', 'display: inherit;');
}
if (container.clientWidth > 0) {
select.setAttribute('style', 'min-width: inherit;');
var width = select.clientWidth + SCALE_SELECT_CONTAINER_PADDING;
select.setAttribute('style', 'min-width: ' +
(width + SCALE_SELECT_PADDING) + 'px;');
container.setAttribute('style', 'min-width: ' + width + 'px; ' +
'max-width: ' + width + 'px;');
}
});
},
};
return Toolbar;
})();
exports.Toolbar = Toolbar;
}));

View File

@ -28,6 +28,8 @@
var CSS_UNITS = 96.0 / 72.0; var CSS_UNITS = 96.0 / 72.0;
var DEFAULT_SCALE_VALUE = 'auto'; var DEFAULT_SCALE_VALUE = 'auto';
var DEFAULT_SCALE = 1.0; var DEFAULT_SCALE = 1.0;
var MIN_SCALE = 0.25;
var MAX_SCALE = 10.0;
var UNKNOWN_SCALE = 0; var UNKNOWN_SCALE = 0;
var MAX_AUTO_SCALE = 1.25; var MAX_AUTO_SCALE = 1.25;
var SCROLLBAR_PADDING = 40; var SCROLLBAR_PADDING = 40;
@ -122,7 +124,7 @@ function getOutputScale(ctx) {
function scrollIntoView(element, spot, skipOverflowHiddenElements) { function scrollIntoView(element, spot, skipOverflowHiddenElements) {
// Assuming offsetParent is available (it's not available when viewer is in // Assuming offsetParent is available (it's not available when viewer is in
// hidden iframe or object). We have to scroll: if the offsetParent is not set // hidden iframe or object). We have to scroll: if the offsetParent is not set
// producing the error. See also animationStartedClosure. // producing the error. See also animationStarted.
var parent = element.offsetParent; var parent = element.offsetParent;
if (!parent) { if (!parent) {
console.error('offsetParent is not set -- cannot scroll'); console.error('offsetParent is not set -- cannot scroll');
@ -408,6 +410,30 @@ function normalizeWheelEventDelta(evt) {
return delta; return delta;
} }
/**
* Promise that is resolved when DOM window becomes visible.
*/
var animationStarted = new Promise(function (resolve) {
window.requestAnimationFrame(resolve);
});
/**
* Promise that is resolved when UI localization is finished.
*/
var localized = new Promise(function (resolve, reject) {
if (!mozL10n) {
reject(new Error('mozL10n service is not available.'));
return;
}
if (mozL10n.getReadyState() !== 'loading') {
resolve();
return;
}
window.addEventListener('localized', function localized(evt) {
resolve();
});
});
/** /**
* Simple event bus for an application. Listeners are attached using the * Simple event bus for an application. Listeners are attached using the
* `on` and `off` methods. To raise an event, the `dispatch` method shall be * `on` and `off` methods. To raise an event, the `dispatch` method shall be
@ -536,6 +562,8 @@ var ProgressBar = (function ProgressBarClosure() {
exports.CSS_UNITS = CSS_UNITS; exports.CSS_UNITS = CSS_UNITS;
exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE; exports.DEFAULT_SCALE_VALUE = DEFAULT_SCALE_VALUE;
exports.DEFAULT_SCALE = DEFAULT_SCALE; exports.DEFAULT_SCALE = DEFAULT_SCALE;
exports.MIN_SCALE = MIN_SCALE;
exports.MAX_SCALE = MAX_SCALE;
exports.UNKNOWN_SCALE = UNKNOWN_SCALE; exports.UNKNOWN_SCALE = UNKNOWN_SCALE;
exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE; exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE;
exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING;
@ -554,4 +582,6 @@ exports.scrollIntoView = scrollIntoView;
exports.watchScroll = watchScroll; exports.watchScroll = watchScroll;
exports.binarySearchFirstItem = binarySearchFirstItem; exports.binarySearchFirstItem = binarySearchFirstItem;
exports.normalizeWheelEventDelta = normalizeWheelEventDelta; exports.normalizeWheelEventDelta = normalizeWheelEventDelta;
exports.animationStarted = animationStarted;
exports.localized = localized;
})); }));

View File

@ -65,8 +65,6 @@ function getViewerConfiguration() {
customScaleOption: document.getElementById('customScaleOption'), customScaleOption: document.getElementById('customScaleOption'),
previous: document.getElementById('previous'), previous: document.getElementById('previous'),
next: document.getElementById('next'), next: document.getElementById('next'),
firstPage: document.getElementById('firstPage'),
lastPage: document.getElementById('lastPage'),
zoomIn: document.getElementById('zoomIn'), zoomIn: document.getElementById('zoomIn'),
zoomOut: document.getElementById('zoomOut'), zoomOut: document.getElementById('zoomOut'),
viewFind: document.getElementById('viewFind'), viewFind: document.getElementById('viewFind'),