Append the contents of FileAttachment annotations to the attachments view of the sidebar, for easier access to the embedded files

Other PDF viewers, e.g. Adobe Reader, seem to append `FileAttachment`s to their attachments views.
One obvious difference in PDF.js is that we cannot append all the annotations on document load, since that would require parsing *every* page. Despite that, it still seems like a good idea to add `FileAttachment`s, since it's thus possible to access all the various types of attachments from a single place.

*Note:* With the previous patch we display a notification when a `FileAttachment` is added to the sidebar, which thus makes appending the contents of these annotations to the sidebar slightly more visible/useful.
This commit is contained in:
Jonas Jenwald 2017-01-15 18:12:24 +01:00
parent 616e5fadff
commit c102232275
6 changed files with 91 additions and 12 deletions

View File

@ -29,6 +29,7 @@
var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType;
var AnnotationType = sharedUtil.AnnotationType;
var stringToPDFString = sharedUtil.stringToPDFString;
var Util = sharedUtil.Util;
var addLinkAttributes = displayDOMUtils.addLinkAttributes;
var LinkTarget = displayDOMUtils.LinkTarget;
@ -1007,8 +1008,15 @@ var FileAttachmentAnnotationElement = (
function FileAttachmentAnnotationElement(parameters) {
AnnotationElement.call(this, parameters, true);
this.filename = getFilenameFromUrl(parameters.data.file.filename);
this.content = parameters.data.file.content;
var file = this.data.file;
this.filename = getFilenameFromUrl(file.filename);
this.content = file.content;
this.linkService.onFileAttachmentAnnotation({
id: stringToPDFString(file.filename),
filename: file.filename,
content: file.content,
});
}
Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, {
@ -1086,8 +1094,7 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
if (!data) {
continue;
}
var properties = {
var element = annotationElementFactory.create({
data: data,
layer: parameters.div,
page: parameters.page,
@ -1097,8 +1104,7 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
imageResourcesPath: parameters.imageResourcesPath ||
getDefaultSetting('imageResourcesPath'),
renderInteractiveForms: parameters.renderInteractiveForms || false,
};
var element = annotationElementFactory.create(properties);
});
if (element.isRenderable) {
parameters.div.appendChild(element.render());
}

View File

@ -48,6 +48,7 @@
exports.renderTextLayer = displayTextLayer.renderTextLayer;
exports.AnnotationLayer = displayAnnotationLayer.AnnotationLayer;
exports.CustomStyle = displayDOMUtils.CustomStyle;
exports.createPromiseCapability = sharedUtil.createPromiseCapability;
exports.PasswordResponses = sharedUtil.PasswordResponses;
exports.InvalidPDFException = sharedUtil.InvalidPDFException;
exports.MissingPDFException = sharedUtil.MissingPDFException;

View File

@ -55,6 +55,8 @@
exports.AnnotationLayer =
pdfjsLibs.pdfjsDisplayAnnotationLayer.AnnotationLayer;
exports.CustomStyle = pdfjsLibs.pdfjsDisplayDOMUtils.CustomStyle;
exports.createPromiseCapability =
pdfjsLibs.pdfjsSharedUtil.createPromiseCapability;
exports.PasswordResponses = pdfjsLibs.pdfjsSharedUtil.PasswordResponses;
exports.InvalidPDFException = pdfjsLibs.pdfjsSharedUtil.InvalidPDFException;
exports.MissingPDFException = pdfjsLibs.pdfjsSharedUtil.MissingPDFException;

View File

@ -26,6 +26,12 @@ var LinkServiceMock = (function LinkServiceMockClosure() {
function LinkServiceMock() {}
LinkServiceMock.prototype = {
get page() {
return 0;
},
set page(value) {},
navigateTo: function (dest) {},
getDestinationHash: function (dest) {
@ -36,7 +42,13 @@ var LinkServiceMock = (function LinkServiceMockClosure() {
return '#';
},
executeNamedAction: function (action) {}
setHash: function (hash) {},
executeNamedAction: function (action) {},
onFileAttachmentAnnotation: function (params) {},
cachePageRef: function (pageNum, pageRef) {},
};
return LinkServiceMock;

View File

@ -51,16 +51,26 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
this.container = options.container;
this.eventBus = options.eventBus;
this.downloadManager = options.downloadManager;
this._renderedCapability = pdfjsLib.createPromiseCapability();
this.eventBus.on('fileattachmentannotation',
this._appendAttachment.bind(this));
}
PDFAttachmentViewer.prototype = {
reset: function PDFAttachmentViewer_reset() {
reset: function PDFAttachmentViewer_reset(keepRenderedCapability) {
this.attachments = null;
var container = this.container;
while (container.firstChild) {
container.removeChild(container.firstChild);
}
if (!keepRenderedCapability) {
// NOTE: The *only* situation in which the `_renderedCapability` should
// not be replaced is when appending file attachment annotations.
this._renderedCapability = pdfjsLib.createPromiseCapability();
}
},
/**
@ -70,8 +80,10 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
function PDFAttachmentViewer_dispatchEvent(attachmentsCount) {
this.eventBus.dispatch('attachmentsloaded', {
source: this,
attachmentsCount: attachmentsCount
attachmentsCount: attachmentsCount,
});
this._renderedCapability.resolve();
},
/**
@ -89,11 +101,13 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
* @param {PDFAttachmentViewerRenderParameters} params
*/
render: function PDFAttachmentViewer_render(params) {
var attachments = (params && params.attachments) || null;
params = params || {};
var attachments = params.attachments || null;
var attachmentsCount = 0;
if (this.attachments) {
this.reset();
var keepRenderedCapability = params.keepRenderedCapability === true;
this.reset(keepRenderedCapability);
}
this.attachments = attachments;
@ -120,7 +134,35 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
}
this._dispatchEvent(attachmentsCount);
}
},
/**
* Used to append FileAttachment annotations to the sidebar.
* @private
*/
_appendAttachment: function PDFAttachmentViewer_appendAttachment(item) {
this._renderedCapability.promise.then(function (id, filename, content) {
var attachments = this.attachments;
if (!attachments) {
attachments = Object.create(null);
} else {
for (var name in attachments) {
if (id === name) {
return; // Ignore the new attachment if it already exists.
}
}
}
attachments[id] = {
filename: filename,
content: content,
};
this.render({
attachments: attachments,
keepRenderedCapability: true,
});
}.bind(this, item.id, item.filename, item.content));
},
};
return PDFAttachmentViewer;

View File

@ -350,6 +350,18 @@ var PDFLinkService = (function PDFLinkServiceClosure() {
});
},
/**
* @param {Object} params
*/
onFileAttachmentAnnotation: function (params) {
this.eventBus.dispatch('fileattachmentannotation', {
source: this,
id: params.id,
filename: params.filename,
content: params.content,
});
},
/**
* @param {number} pageNum - page number.
* @param {Object} pageRef - reference to the page.
@ -462,6 +474,10 @@ var SimpleLinkService = (function SimpleLinkServiceClosure() {
* @param {string} action
*/
executeNamedAction: function (action) {},
/**
* @param {Object} params
*/
onFileAttachmentAnnotation: function (params) {},
/**
* @param {number} pageNum - page number.
* @param {Object} pageRef - reference to the page.