Merge pull request #8381 from Snuffleupagus/document-properties-reset
Re-factor `PDFDocumentProperties` such that it's properly reset when a new PDF file is opened (issue 8371)
This commit is contained in:
commit
b3e4361d7b
@ -561,6 +561,7 @@ var PDFViewerApplication = {
|
|||||||
this.pdfThumbnailViewer.setDocument(null);
|
this.pdfThumbnailViewer.setDocument(null);
|
||||||
this.pdfViewer.setDocument(null);
|
this.pdfViewer.setDocument(null);
|
||||||
this.pdfLinkService.setDocument(null, null);
|
this.pdfLinkService.setDocument(null, null);
|
||||||
|
this.pdfDocumentProperties.setDocument(null, null);
|
||||||
}
|
}
|
||||||
this.store = null;
|
this.store = null;
|
||||||
this.isInitialViewSet = false;
|
this.isInitialViewSet = false;
|
||||||
@ -847,8 +848,6 @@ var PDFViewerApplication = {
|
|||||||
|
|
||||||
this.pdfDocument = pdfDocument;
|
this.pdfDocument = pdfDocument;
|
||||||
|
|
||||||
this.pdfDocumentProperties.setDocumentAndUrl(pdfDocument, this.url);
|
|
||||||
|
|
||||||
var downloadedPromise = pdfDocument.getDownloadInfo().then(function() {
|
var downloadedPromise = pdfDocument.getDownloadInfo().then(function() {
|
||||||
self.downloadComplete = true;
|
self.downloadComplete = true;
|
||||||
self.loadingBar.hide();
|
self.loadingBar.hide();
|
||||||
@ -869,6 +868,7 @@ var PDFViewerApplication = {
|
|||||||
baseDocumentUrl = location.href.split('#')[0];
|
baseDocumentUrl = location.href.split('#')[0];
|
||||||
}
|
}
|
||||||
this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl);
|
this.pdfLinkService.setDocument(pdfDocument, baseDocumentUrl);
|
||||||
|
this.pdfDocumentProperties.setDocument(pdfDocument, this.url);
|
||||||
|
|
||||||
var pdfViewer = this.pdfViewer;
|
var pdfViewer = this.pdfViewer;
|
||||||
pdfViewer.currentScale = scale;
|
pdfViewer.currentScale = scale;
|
||||||
|
@ -13,10 +13,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPDFFileNameFromURL, mozL10n } from './ui_utils';
|
import { cloneObj, getPDFFileNameFromURL, mozL10n } from './ui_utils';
|
||||||
import { createPromiseCapability } from './pdfjs';
|
import { createPromiseCapability } from './pdfjs';
|
||||||
import { OverlayManager } from './overlay_manager';
|
import { OverlayManager } from './overlay_manager';
|
||||||
|
|
||||||
|
const DEFAULT_FIELD_CONTENT = '-';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} PDFDocumentPropertiesOptions
|
* @typedef {Object} PDFDocumentPropertiesOptions
|
||||||
* @property {string} overlayName - Name/identifier for the overlay.
|
* @property {string} overlayName - Name/identifier for the overlay.
|
||||||
@ -29,21 +31,16 @@ class PDFDocumentProperties {
|
|||||||
/**
|
/**
|
||||||
* @param {PDFDocumentPropertiesOptions} options
|
* @param {PDFDocumentPropertiesOptions} options
|
||||||
*/
|
*/
|
||||||
constructor(options) {
|
constructor({ overlayName, fields, container, closeButton, }) {
|
||||||
this.overlayName = options.overlayName;
|
this.overlayName = overlayName;
|
||||||
this.fields = options.fields;
|
this.fields = fields;
|
||||||
this.container = options.container;
|
this.container = container;
|
||||||
|
|
||||||
this.rawFileSize = 0;
|
this._reset();
|
||||||
this.url = null;
|
|
||||||
this.pdfDocument = null;
|
|
||||||
|
|
||||||
// Bind the event listener for the Close button.
|
if (closeButton) { // Bind the event listener for the Close button.
|
||||||
if (options.closeButton) {
|
closeButton.addEventListener('click', this.close.bind(this));
|
||||||
options.closeButton.addEventListener('click', this.close.bind(this));
|
|
||||||
}
|
}
|
||||||
this._dataAvailableCapability = createPromiseCapability();
|
|
||||||
|
|
||||||
OverlayManager.register(this.overlayName, this.container,
|
OverlayManager.register(this.overlayName, this.container,
|
||||||
this.close.bind(this));
|
this.close.bind(this));
|
||||||
}
|
}
|
||||||
@ -52,9 +49,51 @@ class PDFDocumentProperties {
|
|||||||
* Open the document properties overlay.
|
* Open the document properties overlay.
|
||||||
*/
|
*/
|
||||||
open() {
|
open() {
|
||||||
|
let freezeFieldData = (data) => {
|
||||||
|
Object.defineProperty(this, 'fieldData', {
|
||||||
|
value: Object.freeze(data),
|
||||||
|
writable: false,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Promise.all([OverlayManager.open(this.overlayName),
|
Promise.all([OverlayManager.open(this.overlayName),
|
||||||
this._dataAvailableCapability.promise]).then(() => {
|
this._dataAvailableCapability.promise]).then(() => {
|
||||||
this._getProperties();
|
// If the document properties were previously fetched (for this PDF file),
|
||||||
|
// just update the dialog immediately to avoid redundant lookups.
|
||||||
|
if (this.fieldData) {
|
||||||
|
this._updateUI();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Get the document properties.
|
||||||
|
this.pdfDocument.getMetadata().then(({ info, metadata, }) => {
|
||||||
|
freezeFieldData({
|
||||||
|
'fileName': getPDFFileNameFromURL(this.url),
|
||||||
|
'fileSize': this._parseFileSize(this.maybeFileSize),
|
||||||
|
'title': info.Title,
|
||||||
|
'author': info.Author,
|
||||||
|
'subject': info.Subject,
|
||||||
|
'keywords': info.Keywords,
|
||||||
|
'creationDate': this._parseDate(info.CreationDate),
|
||||||
|
'modificationDate': this._parseDate(info.ModDate),
|
||||||
|
'creator': info.Creator,
|
||||||
|
'producer': info.Producer,
|
||||||
|
'version': info.PDFFormatVersion,
|
||||||
|
'pageCount': this.pdfDocument.numPages,
|
||||||
|
});
|
||||||
|
this._updateUI();
|
||||||
|
|
||||||
|
// Get the correct fileSize, since it may not have been set (if
|
||||||
|
// `this.setFileSize` wasn't called) or may be incorrectly set.
|
||||||
|
return this.pdfDocument.getDownloadInfo();
|
||||||
|
}).then(({ length, }) => {
|
||||||
|
let data = cloneObj(this.fieldData);
|
||||||
|
data['fileSize'] = this._parseFileSize(length);
|
||||||
|
|
||||||
|
freezeFieldData(data);
|
||||||
|
this._updateUI();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,19 +104,6 @@ class PDFDocumentProperties {
|
|||||||
OverlayManager.close(this.overlayName);
|
OverlayManager.close(this.overlayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the file size of the PDF document. This method is used to
|
|
||||||
* update the file size in the document properties overlay once it
|
|
||||||
* is known so we do not have to wait until the entire file is loaded.
|
|
||||||
*
|
|
||||||
* @param {number} fileSize - The file size of the PDF document.
|
|
||||||
*/
|
|
||||||
setFileSize(fileSize) {
|
|
||||||
if (fileSize > 0) {
|
|
||||||
this.rawFileSize = fileSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a reference to the PDF document and the URL in order
|
* Set a reference to the PDF document and the URL in order
|
||||||
* to populate the overlay fields with the document properties.
|
* to populate the overlay fields with the document properties.
|
||||||
@ -87,68 +113,75 @@ class PDFDocumentProperties {
|
|||||||
* @param {Object} pdfDocument - A reference to the PDF document.
|
* @param {Object} pdfDocument - A reference to the PDF document.
|
||||||
* @param {string} url - The URL of the document.
|
* @param {string} url - The URL of the document.
|
||||||
*/
|
*/
|
||||||
setDocumentAndUrl(pdfDocument, url) {
|
setDocument(pdfDocument, url) {
|
||||||
|
if (this.pdfDocument) {
|
||||||
|
this._reset();
|
||||||
|
this._updateUI(true);
|
||||||
|
}
|
||||||
|
if (!pdfDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.pdfDocument = pdfDocument;
|
this.pdfDocument = pdfDocument;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
|
||||||
this._dataAvailableCapability.resolve();
|
this._dataAvailableCapability.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the file size of the PDF document. This method is used to
|
||||||
|
* update the file size in the document properties overlay once it
|
||||||
|
* is known so we do not have to wait until the entire file is loaded.
|
||||||
|
*
|
||||||
|
* @param {number} fileSize - The file size of the PDF document.
|
||||||
|
*/
|
||||||
|
setFileSize(fileSize) {
|
||||||
|
if (typeof fileSize === 'number' && fileSize > 0) {
|
||||||
|
this.maybeFileSize = fileSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_getProperties() {
|
_reset() {
|
||||||
if (!OverlayManager.active) {
|
this.pdfDocument = null;
|
||||||
// If the dialog was closed before `_dataAvailableCapability` was
|
this.url = null;
|
||||||
// resolved, don't bother updating the properties.
|
|
||||||
|
this.maybeFileSize = 0;
|
||||||
|
delete this.fieldData;
|
||||||
|
this._dataAvailableCapability = createPromiseCapability();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Always updates all of the dialog fields, to prevent inconsistent UI state.
|
||||||
|
* NOTE: If the contents of a particular field is neither a non-empty string,
|
||||||
|
* nor a number, it will fall back to `DEFAULT_FIELD_CONTENT`.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_updateUI(reset = false) {
|
||||||
|
if (reset || !this.fieldData) {
|
||||||
|
for (let id in this.fields) {
|
||||||
|
this.fields[id].textContent = DEFAULT_FIELD_CONTENT;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get the file size (if it hasn't already been set).
|
if (OverlayManager.active !== this.overlayName) {
|
||||||
this.pdfDocument.getDownloadInfo().then((data) => {
|
// Don't bother updating the dialog if has already been closed,
|
||||||
if (data.length === this.rawFileSize) {
|
// since it will be updated the next time `this.open` is called.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setFileSize(data.length);
|
for (let id in this.fields) {
|
||||||
this._updateUI(this.fields['fileSize'], this._parseFileSize());
|
let content = this.fieldData[id];
|
||||||
});
|
this.fields[id].textContent = (content || content === 0) ?
|
||||||
|
content : DEFAULT_FIELD_CONTENT;
|
||||||
// Get the document properties.
|
|
||||||
this.pdfDocument.getMetadata().then((data) => {
|
|
||||||
var content = {
|
|
||||||
'fileName': getPDFFileNameFromURL(this.url),
|
|
||||||
'fileSize': this._parseFileSize(),
|
|
||||||
'title': data.info.Title,
|
|
||||||
'author': data.info.Author,
|
|
||||||
'subject': data.info.Subject,
|
|
||||||
'keywords': data.info.Keywords,
|
|
||||||
'creationDate': this._parseDate(data.info.CreationDate),
|
|
||||||
'modificationDate': this._parseDate(data.info.ModDate),
|
|
||||||
'creator': data.info.Creator,
|
|
||||||
'producer': data.info.Producer,
|
|
||||||
'version': data.info.PDFFormatVersion,
|
|
||||||
'pageCount': this.pdfDocument.numPages
|
|
||||||
};
|
|
||||||
|
|
||||||
// Show the properties in the dialog.
|
|
||||||
for (var identifier in content) {
|
|
||||||
this._updateUI(this.fields[identifier], content[identifier]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_updateUI(field, content) {
|
|
||||||
if (field && content !== undefined && content !== '') {
|
|
||||||
field.textContent = content;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_parseFileSize() {
|
_parseFileSize(fileSize = 0) {
|
||||||
var fileSize = this.rawFileSize, kb = fileSize / 1024;
|
let kb = fileSize / 1024;
|
||||||
if (!kb) {
|
if (!kb) {
|
||||||
return;
|
return;
|
||||||
} else if (kb < 1024) {
|
} else if (kb < 1024) {
|
||||||
@ -167,14 +200,14 @@ class PDFDocumentProperties {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_parseDate(inputDate) {
|
_parseDate(inputDate) {
|
||||||
|
if (!inputDate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// This is implemented according to the PDF specification, but note that
|
// This is implemented according to the PDF specification, but note that
|
||||||
// Adobe Reader doesn't handle changing the date to universal time
|
// Adobe Reader doesn't handle changing the date to universal time
|
||||||
// and doesn't use the user's time zone (they're effectively ignoring
|
// and doesn't use the user's time zone (they're effectively ignoring
|
||||||
// the HH' and mm' parts of the date string).
|
// the HH' and mm' parts of the date string).
|
||||||
var dateToParse = inputDate;
|
let dateToParse = inputDate;
|
||||||
if (dateToParse === undefined) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the D: prefix if it is available.
|
// Remove the D: prefix if it is available.
|
||||||
if (dateToParse.substring(0, 2) === 'D:') {
|
if (dateToParse.substring(0, 2) === 'D:') {
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { cloneObj } from './ui_utils';
|
||||||
|
|
||||||
var defaultPreferences = null;
|
var defaultPreferences = null;
|
||||||
function getDefaultPreferences() {
|
function getDefaultPreferences() {
|
||||||
if (!defaultPreferences) {
|
if (!defaultPreferences) {
|
||||||
@ -38,16 +40,6 @@ function getDefaultPreferences() {
|
|||||||
return defaultPreferences;
|
return defaultPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneObj(obj) {
|
|
||||||
var result = {};
|
|
||||||
for (var i in obj) {
|
|
||||||
if (Object.prototype.hasOwnProperty.call(obj, i)) {
|
|
||||||
result[i] = obj[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BasePreferences - Abstract base class for storing persistent settings.
|
* BasePreferences - Abstract base class for storing persistent settings.
|
||||||
* Used for settings that should be applied to all opened documents,
|
* Used for settings that should be applied to all opened documents,
|
||||||
|
@ -422,6 +422,16 @@ function normalizeWheelEventDelta(evt) {
|
|||||||
return delta;
|
return delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cloneObj(obj) {
|
||||||
|
var result = {};
|
||||||
|
for (var i in obj) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(obj, i)) {
|
||||||
|
result[i] = obj[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Promise that is resolved when DOM window becomes visible.
|
* Promise that is resolved when DOM window becomes visible.
|
||||||
*/
|
*/
|
||||||
@ -582,6 +592,7 @@ export {
|
|||||||
MAX_AUTO_SCALE,
|
MAX_AUTO_SCALE,
|
||||||
SCROLLBAR_PADDING,
|
SCROLLBAR_PADDING,
|
||||||
VERTICAL_PADDING,
|
VERTICAL_PADDING,
|
||||||
|
cloneObj,
|
||||||
RendererType,
|
RendererType,
|
||||||
mozL10n,
|
mozL10n,
|
||||||
EventBus,
|
EventBus,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user