Implement support for FileAttachment annotations

This commit is contained in:
Tim van der Meij 2016-02-14 20:44:00 +01:00
parent e9a1a47d28
commit 6a33dfd13a
10 changed files with 127 additions and 9 deletions

View File

@ -337,7 +337,7 @@ ChromeActions.prototype = {
try {
// contentDisposition/contentDispositionFilename is readonly before FF18
channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT;
if (self.contentDispositionFilename) {
if (self.contentDispositionFilename && !data.isAttachment) {
channel.contentDispositionFilename = self.contentDispositionFilename;
} else {
channel.contentDispositionFilename = filename;

View File

@ -50,6 +50,7 @@ var isName = corePrimitives.isName;
var Stream = coreStream.Stream;
var ColorSpace = coreColorSpace.ColorSpace;
var ObjectLoader = coreObj.ObjectLoader;
var FileSpec = coreObj.FileSpec;
var OperatorList = coreEvaluator.OperatorList;
/**
@ -75,6 +76,7 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
// Return the right annotation object based on the subtype and field type.
var parameters = {
xref: xref,
dict: dict,
ref: ref
};
@ -108,6 +110,9 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
case 'StrikeOut':
return new StrikeOutAnnotation(parameters);
case 'FileAttachment':
return new FileAttachmentAnnotation(parameters);
default:
warn('Unimplemented annotation type "' + subtype + '", ' +
'falling back to base annotation');
@ -852,6 +857,31 @@ var StrikeOutAnnotation = (function StrikeOutAnnotationClosure() {
return StrikeOutAnnotation;
})();
var FileAttachmentAnnotation = (function FileAttachmentAnnotationClosure() {
function FileAttachmentAnnotation(parameters) {
Annotation.call(this, parameters);
var dict = parameters.dict;
var file = new FileSpec(dict.get('FS'), parameters.xref);
this.data.annotationType = AnnotationType.FILEATTACHMENT;
this.data.file = file.serializable;
if (!dict.has('C')) {
// Fall back to the default background color.
this.data.color = null;
}
this.data.hasPopup = dict.has('Popup');
this.data.title = stringToPDFString(dict.get('T') || '');
this.data.contents = stringToPDFString(dict.get('Contents') || '');
}
Util.inherit(FileAttachmentAnnotation, Annotation, {});
return FileAttachmentAnnotation;
})();
exports.Annotation = Annotation;
exports.AnnotationBorderStyle = AnnotationBorderStyle;
exports.AnnotationFactory = AnnotationFactory;

View File

@ -1591,4 +1591,5 @@ var ObjectLoader = (function() {
exports.Catalog = Catalog;
exports.ObjectLoader = ObjectLoader;
exports.XRef = XRef;
exports.FileSpec = FileSpec;
}));

View File

@ -42,6 +42,7 @@ var CustomStyle = displayDOMUtils.CustomStyle;
* @property {PDFPage} page
* @property {PageViewport} viewport
* @property {IPDFLinkService} linkService
* @property {DownloadManager} downloadManager
*/
/**
@ -83,6 +84,9 @@ AnnotationElementFactory.prototype =
case AnnotationType.STRIKEOUT:
return new StrikeOutAnnotationElement(parameters);
case AnnotationType.FILEATTACHMENT:
return new FileAttachmentAnnotationElement(parameters);
default:
return new AnnotationElement(parameters);
}
@ -101,6 +105,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
this.page = parameters.page;
this.viewport = parameters.viewport;
this.linkService = parameters.linkService;
this.downloadManager = parameters.downloadManager;
if (isRenderable) {
this.container = this._createContainer();
@ -717,6 +722,76 @@ var StrikeOutAnnotationElement = (
return StrikeOutAnnotationElement;
})();
/**
* @class
* @alias FileAttachmentAnnotationElement
*/
var FileAttachmentAnnotationElement = (
function FileAttachmentAnnotationElementClosure() {
function FileAttachmentAnnotationElement(parameters) {
AnnotationElement.call(this, parameters, true);
this.filename = parameters.data.file.filename;
this.content = parameters.data.file.content;
}
Util.inherit(FileAttachmentAnnotationElement, AnnotationElement, {
/**
* Render the file attachment annotation's HTML element in the empty
* container.
*
* @public
* @memberof FileAttachmentAnnotationElement
* @returns {HTMLSectionElement}
*/
render: function FileAttachmentAnnotationElement_render() {
this.container.className = 'fileAttachmentAnnotation';
var trigger = document.createElement('div');
trigger.style.height = this.container.style.height;
trigger.style.width = this.container.style.width;
trigger.addEventListener('dblclick', this._download.bind(this));
if (!this.data.hasPopup && (this.data.title || this.data.contents)) {
var popupElement = new PopupElement({
container: this.container,
trigger: trigger,
color: this.data.color,
title: this.data.title,
contents: this.data.contents,
hideWrapper: true
});
var popup = popupElement.render();
// Position the popup next to the FileAttachment annotation's
// container.
popup.style.left = this.container.style.width;
this.container.appendChild(popup);
}
this.container.appendChild(trigger);
return this.container;
},
/**
* Download the file attachment associated with this annotation.
*
* @private
* @memberof FileAttachmentAnnotationElement
*/
_download: function FileAttachmentAnnotationElement_download() {
if (!this.downloadManager) {
warn('Download cannot be started due to unavailable download manager');
return;
}
this.downloadManager.downloadData(this.content, this.filename, '');
}
});
return FileAttachmentAnnotationElement;
})();
/**
* @typedef {Object} AnnotationLayerParameters
* @property {PageViewport} viewport
@ -753,7 +828,8 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
layer: parameters.div,
page: parameters.page,
viewport: parameters.viewport,
linkService: parameters.linkService
linkService: parameters.linkService,
downloadManager: parameters.downloadManager
};
var element = annotationElementFactory.create(properties);
if (element.isRenderable) {

View File

@ -72,6 +72,7 @@
.annotationLayer .highlightAnnotation,
.annotationLayer .underlineAnnotation,
.annotationLayer .squigglyAnnotation,
.annotationLayer .strikeoutAnnotation {
.annotationLayer .strikeoutAnnotation,
.annotationLayer .fileAttachmentAnnotation {
cursor: pointer;
}

View File

@ -21,6 +21,7 @@
* @property {HTMLDivElement} pageDiv
* @property {PDFPage} pdfPage
* @property {IPDFLinkService} linkService
* @property {DownloadManager} downloadManager
*/
/**
@ -35,6 +36,7 @@ var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() {
this.pageDiv = options.pageDiv;
this.pdfPage = options.pdfPage;
this.linkService = options.linkService;
this.downloadManager = options.downloadManager;
this.div = null;
}
@ -59,7 +61,8 @@ var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() {
div: self.div,
annotations: annotations,
page: self.pdfPage,
linkService: self.linkService
linkService: self.linkService,
downloadManager: self.downloadManager
};
if (self.div) {

View File

@ -13,8 +13,7 @@
* limitations under the License.
*/
/* globals RenderingStates, PDFJS, DEFAULT_SCALE, CSS_UNITS, getOutputScale,
TextLayerBuilder, AnnotationLayerBuilder, Promise,
approximateFraction, roundToDivide */
TextLayerBuilder, Promise, approximateFraction, roundToDivide */
'use strict';

View File

@ -15,7 +15,8 @@
/*jshint globalstrict: false */
/* globals PDFJS, PDFViewer, PDFPageView, TextLayerBuilder, PDFLinkService,
DefaultTextLayerFactory, AnnotationLayerBuilder, PDFHistory,
DefaultAnnotationLayerFactory, getFileName, ProgressBar */
DefaultAnnotationLayerFactory, getFileName, DownloadManager,
ProgressBar */
// Initializing PDFJS global object (if still undefined)
if (typeof PDFJS === 'undefined') {
@ -29,6 +30,7 @@ if (typeof PDFJS === 'undefined') {
//#include pdf_link_service.js
//#include pdf_viewer.js
//#include pdf_history.js
//#include download_manager.js
PDFJS.PDFViewer = PDFViewer;
PDFJS.PDFPageView = PDFPageView;
@ -40,5 +42,6 @@ if (typeof PDFJS === 'undefined') {
PDFJS.PDFHistory = PDFHistory;
PDFJS.getFileName = getFileName;
PDFJS.DownloadManager = DownloadManager;
PDFJS.ProgressBar = ProgressBar;
}).call((typeof window === 'undefined') ? this : window);

View File

@ -40,6 +40,8 @@ var DEFAULT_CACHE_SIZE = 10;
* @property {HTMLDivElement} container - The container for the viewer element.
* @property {HTMLDivElement} viewer - (optional) The viewer element.
* @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {DownloadManager} downloadManager - (optional) The download
* manager component.
* @property {PDFRenderingQueue} renderingQueue - (optional) The rendering
* queue object.
* @property {boolean} removePageBorders - (optional) Removes the border shadow
@ -92,6 +94,7 @@ var PDFViewer = (function pdfViewer() {
this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild;
this.linkService = options.linkService || new SimpleLinkService();
this.downloadManager = options.downloadManager || null;
this.removePageBorders = options.removePageBorders || false;
this.defaultRenderingQueue = !options.renderingQueue;
@ -757,7 +760,8 @@ var PDFViewer = (function pdfViewer() {
return new AnnotationLayerBuilder({
pageDiv: pageDiv,
pdfPage: pdfPage,
linkService: this.linkService
linkService: this.linkService,
downloadManager: this.downloadManager
});
},

View File

@ -134,7 +134,8 @@ var PDFViewerApplication = {
container: container,
viewer: viewer,
renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService
linkService: pdfLinkService,
downloadManager: new DownloadManager()
});
pdfRenderingQueue.setViewer(this.pdfViewer);
pdfLinkService.setViewer(this.pdfViewer);