diff --git a/extensions/b2g/viewer.html b/extensions/b2g/viewer.html index bee77f177..4240bbb20 100644 --- a/extensions/b2g/viewer.html +++ b/extensions/b2g/viewer.html @@ -202,21 +202,66 @@ limitations under the License. diff --git a/web/document_properties.js b/web/document_properties.js index 25fbc8e61..e0161fefe 100644 --- a/web/document_properties.js +++ b/web/document_properties.js @@ -14,15 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFView, Promise, mozL10n, getPDFFileNameFromURL */ +/* globals PDFView, Promise, mozL10n, getPDFFileNameFromURL, OverlayManager */ 'use strict'; var DocumentProperties = { - overlayContainer: null, + overlayName: null, fileName: '', fileSize: '', - visible: false, // Document property fields (in the viewer). fileNameField: null, @@ -39,7 +38,7 @@ var DocumentProperties = { pageCountField: null, initialize: function documentPropertiesInitialize(options) { - this.overlayContainer = options.overlayContainer; + this.overlayName = options.overlayName; // Set the document property fields. this.fileNameField = options.fileNameField; @@ -57,24 +56,18 @@ var DocumentProperties = { // Bind the event listener for the Close button. if (options.closeButton) { - options.closeButton.addEventListener('click', this.hide.bind(this)); + options.closeButton.addEventListener('click', this.close.bind(this)); } this.dataAvailablePromise = new Promise(function (resolve) { this.resolveDataAvailable = resolve; }.bind(this)); - // Bind the event listener for the Esc key (to close the dialog). - window.addEventListener('keydown', - function (e) { - if (e.keyCode === 27) { // Esc key - this.hide(); - } - }.bind(this)); + OverlayManager.register(this.overlayName, this.close.bind(this)); }, getProperties: function documentPropertiesGetProperties() { - if (!this.visible) { + if (!OverlayManager.active) { // If the dialog was closed before dataAvailablePromise was resolved, // don't bother updating the properties. return; @@ -136,26 +129,15 @@ var DocumentProperties = { } }, - show: function documentPropertiesShow() { - if (this.visible) { - return; - } - this.visible = true; - this.overlayContainer.classList.remove('hidden'); - this.overlayContainer.lastElementChild.classList.remove('hidden'); - - this.dataAvailablePromise.then(function () { + open: function documentPropertiesOpen() { + Promise.all([OverlayManager.open(this.overlayName), + this.dataAvailablePromise]).then(function () { this.getProperties(); }.bind(this)); }, - hide: function documentPropertiesClose() { - if (!this.visible) { - return; - } - this.visible = false; - this.overlayContainer.classList.add('hidden'); - this.overlayContainer.lastElementChild.classList.add('hidden'); + close: function documentPropertiesClose() { + OverlayManager.close(this.overlayName); }, parseDate: function documentPropertiesParseDate(inputDate) { diff --git a/web/overlay_manager.js b/web/overlay_manager.js new file mode 100644 index 000000000..2dadbf91a --- /dev/null +++ b/web/overlay_manager.js @@ -0,0 +1,145 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2014 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 Promise */ + +'use strict'; + +var OverlayManager = { + overlays: {}, + active: null, + + /** + * @param {string} name The name of the overlay that is registered. This must + * be the equal to the ID of the overlay's DOM element. + * @param {function} callerCloseMethod (optional) The method that, if present, + * will call OverlayManager.close from the Object + * registering the overlay. Access to this method is + * necessary in order to run cleanup code when e.g. + * the overlay is force closed. The default is null. + * @param {boolean} canForceClose (optional) Indicates if opening the overlay + * will close an active overlay. The default is false. + * @returns {Promise} A promise that is resolved when the overlay has been + * registered. + */ + register: function overlayManagerRegister(name, + callerCloseMethod, canForceClose) { + return new Promise(function (resolve) { + var element, container; + if (!name || !(element = document.getElementById(name)) || + !(container = element.parentNode)) { + throw new Error('Not enough parameters.'); + } else if (this.overlays[name]) { + throw new Error('The overlay is already registered.'); + } + this.overlays[name] = { element: element, + container: container, + callerCloseMethod: (callerCloseMethod || null), + canForceClose: (canForceClose || false) }; + resolve(); + }.bind(this)); + }, + + /** + * @param {string} name The name of the overlay that is unregistered. + * @returns {Promise} A promise that is resolved when the overlay has been + * unregistered. + */ + unregister: function overlayManagerUnregister(name) { + return new Promise(function (resolve) { + if (!this.overlays[name]) { + throw new Error('The overlay does not exist.'); + } else if (this.active === name) { + throw new Error('The overlay cannot be removed while it is active.'); + } + delete this.overlays[name]; + + resolve(); + }.bind(this)); + }, + + /** + * @param {string} name The name of the overlay that should be opened. + * @returns {Promise} A promise that is resolved when the overlay has been + * opened. + */ + open: function overlayManagerOpen(name) { + return new Promise(function (resolve) { + if (!this.overlays[name]) { + throw new Error('The overlay does not exist.'); + } else if (this.active) { + if (this.overlays[name].canForceClose) { + this._closeThroughCaller(); + } else if (this.active === name) { + throw new Error('The overlay is already active.'); + } else { + throw new Error('Another overlay is currently active.'); + } + } + this.active = name; + this.overlays[this.active].element.classList.remove('hidden'); + this.overlays[this.active].container.classList.remove('hidden'); + + window.addEventListener('keydown', this._keyDown); + resolve(); + }.bind(this)); + }, + + /** + * @param {string} name The name of the overlay that should be closed. + * @returns {Promise} A promise that is resolved when the overlay has been + * closed. + */ + close: function overlayManagerClose(name) { + return new Promise(function (resolve) { + if (!this.overlays[name]) { + throw new Error('The overlay does not exist.'); + } else if (!this.active) { + throw new Error('The overlay is currently not active.'); + } else if (this.active !== name) { + throw new Error('Another overlay is currently active.'); + } + this.overlays[this.active].container.classList.add('hidden'); + this.overlays[this.active].element.classList.add('hidden'); + this.active = null; + + window.removeEventListener('keydown', this._keyDown); + resolve(); + }.bind(this)); + }, + + /** + * @private + */ + _keyDown: function overlayManager_keyDown(evt) { + var self = OverlayManager; + if (self.active && evt.keyCode === 27) { // Esc key. + self._closeThroughCaller(); + } + }, + + /** + * @private + */ + _closeThroughCaller: function overlayManager_closeThroughCaller() { + if (this.overlays[this.active].callerCloseMethod) { + this.overlays[this.active].callerCloseMethod(); + } + if (this.active) { + this.close(this.active); + } + } +}; diff --git a/web/password_prompt.js b/web/password_prompt.js index 498fb2d7f..2717c8686 100644 --- a/web/password_prompt.js +++ b/web/password_prompt.js @@ -14,22 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals PDFJS, mozL10n */ +/* globals PDFJS, mozL10n, OverlayManager */ 'use strict'; var PasswordPrompt = { - visible: false, + overlayName: null, updatePassword: null, reason: null, - overlayContainer: null, passwordField: null, passwordText: null, passwordSubmit: null, passwordCancel: null, initialize: function secondaryToolbarInitialize(options) { - this.overlayContainer = options.overlayContainer; + this.overlayName = options.overlayName; this.passwordField = options.passwordField; this.passwordText = options.passwordText; this.passwordSubmit = options.passwordSubmit; @@ -39,57 +38,43 @@ var PasswordPrompt = { this.passwordSubmit.addEventListener('click', this.verifyPassword.bind(this)); - this.passwordCancel.addEventListener('click', this.hide.bind(this)); + this.passwordCancel.addEventListener('click', this.close.bind(this)); - this.passwordField.addEventListener('keydown', - function (e) { - if (e.keyCode === 13) { // Enter key - this.verifyPassword(); - } - }.bind(this)); + this.passwordField.addEventListener('keydown', function (e) { + if (e.keyCode === 13) { // Enter key + this.verifyPassword(); + } + }.bind(this)); - window.addEventListener('keydown', - function (e) { - if (e.keyCode === 27) { // Esc key - this.hide(); - } - }.bind(this)); + OverlayManager.register(this.overlayName, this.close.bind(this), true); }, - show: function passwordPromptShow() { - if (this.visible) { - return; - } - this.visible = true; - this.overlayContainer.classList.remove('hidden'); - this.overlayContainer.firstElementChild.classList.remove('hidden'); - this.passwordField.focus(); + open: function passwordPromptOpen() { + OverlayManager.open(this.overlayName).then(function () { + this.passwordField.focus(); - var promptString = mozL10n.get('password_label', null, - 'Enter the password to open this PDF file.'); + var promptString = mozL10n.get('password_label', null, + 'Enter the password to open this PDF file.'); - if (this.reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) { - promptString = mozL10n.get('password_invalid', null, - 'Invalid password. Please try again.'); - } + if (this.reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) { + promptString = mozL10n.get('password_invalid', null, + 'Invalid password. Please try again.'); + } - this.passwordText.textContent = promptString; + this.passwordText.textContent = promptString; + }.bind(this)); }, - hide: function passwordPromptClose() { - if (!this.visible) { - return; - } - this.visible = false; - this.passwordField.value = ''; - this.overlayContainer.classList.add('hidden'); - this.overlayContainer.firstElementChild.classList.add('hidden'); + close: function passwordPromptClose() { + OverlayManager.close(this.overlayName).then(function () { + this.passwordField.value = ''; + }.bind(this)); }, verifyPassword: function passwordPromptVerifyPassword() { var password = this.passwordField.value; if (password && password.length > 0) { - this.hide(); + this.close(); return this.updatePassword(password); } } diff --git a/web/secondary_toolbar.js b/web/secondary_toolbar.js index a3d7563ac..2775016d6 100644 --- a/web/secondary_toolbar.js +++ b/web/secondary_toolbar.js @@ -114,7 +114,7 @@ var SecondaryToolbar = { }, documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) { - this.documentProperties.show(); + this.documentProperties.open(); this.close(); }, diff --git a/web/viewer.html b/web/viewer.html index 39c05a220..00b303f9d 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -77,10 +77,11 @@ http://sourceforge.net/adobe/cmap/wiki/License/ - + + diff --git a/web/viewer.js b/web/viewer.js index 6d92ad048..04129cac4 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -20,7 +20,7 @@ Preferences, SidebarView, ViewHistory, PageView, ThumbnailView, URL, noContextMenuHandler, SecondaryToolbar, PasswordPrompt, PresentationMode, HandTool, Promise, DocumentProperties, - DocumentOutlineView, DocumentAttachmentsView */ + DocumentOutlineView, DocumentAttachmentsView, OverlayManager */ 'use strict'; @@ -100,9 +100,10 @@ var currentPageNumber = 1; //#include pdf_find_controller.js //#include pdf_history.js //#include secondary_toolbar.js -//#include password_prompt.js //#include presentation_mode.js //#include hand_tool.js +//#include overlay_manager.js +//#include password_prompt.js //#include document_properties.js var PDFView = { @@ -183,14 +184,6 @@ var PDFView = { documentPropertiesButton: document.getElementById('documentProperties') }); - PasswordPrompt.initialize({ - overlayContainer: document.getElementById('overlayContainer'), - passwordField: document.getElementById('password'), - passwordText: document.getElementById('passwordText'), - passwordSubmit: document.getElementById('passwordSubmit'), - passwordCancel: document.getElementById('passwordCancel') - }); - PresentationMode.initialize({ container: container, secondaryToolbar: SecondaryToolbar, @@ -200,8 +193,16 @@ var PDFView = { pageRotateCcw: document.getElementById('contextPageRotateCcw') }); + PasswordPrompt.initialize({ + overlayName: 'passwordOverlay', + passwordField: document.getElementById('password'), + passwordText: document.getElementById('passwordText'), + passwordSubmit: document.getElementById('passwordSubmit'), + passwordCancel: document.getElementById('passwordCancel') + }); + DocumentProperties.initialize({ - overlayContainer: document.getElementById('overlayContainer'), + overlayName: 'documentPropertiesOverlay', closeButton: document.getElementById('documentPropertiesClose'), fileNameField: document.getElementById('fileNameField'), fileSizeField: document.getElementById('fileSizeField'), @@ -626,7 +627,7 @@ var PDFView = { var passwordNeeded = function passwordNeeded(updatePassword, reason) { PasswordPrompt.updatePassword = updatePassword; PasswordPrompt.reason = reason; - PasswordPrompt.show(); + PasswordPrompt.open(); }; function getDocumentProgress(progressData) { @@ -2165,7 +2166,7 @@ window.addEventListener('click', function click(evt) { }, false); window.addEventListener('keydown', function keydown(evt) { - if (PasswordPrompt.visible) { + if (OverlayManager.active) { return; }