You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
907 lines
27 KiB
907 lines
27 KiB
/* 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. |
|
*/ |
|
|
|
'use strict'; |
|
|
|
(function (root, factory) { |
|
if (typeof define === 'function' && define.amd) { |
|
define('pdfjs/display/annotation_layer', ['exports', 'pdfjs/shared/util', |
|
'pdfjs/display/dom_utils'], factory); |
|
} else if (typeof exports !== 'undefined') { |
|
factory(exports, require('../shared/util.js'), require('./dom_utils.js')); |
|
} else { |
|
factory((root.pdfjsDisplayAnnotationLayer = {}), root.pdfjsSharedUtil, |
|
root.pdfjsDisplayDOMUtils); |
|
} |
|
}(this, function (exports, sharedUtil, displayDOMUtils) { |
|
|
|
var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType; |
|
var AnnotationType = sharedUtil.AnnotationType; |
|
var Util = sharedUtil.Util; |
|
var addLinkAttributes = displayDOMUtils.addLinkAttributes; |
|
var getFilenameFromUrl = displayDOMUtils.getFilenameFromUrl; |
|
var warn = sharedUtil.warn; |
|
var CustomStyle = displayDOMUtils.CustomStyle; |
|
var getDefaultSetting = displayDOMUtils.getDefaultSetting; |
|
|
|
/** |
|
* @typedef {Object} AnnotationElementParameters |
|
* @property {Object} data |
|
* @property {HTMLDivElement} layer |
|
* @property {PDFPage} page |
|
* @property {PageViewport} viewport |
|
* @property {IPDFLinkService} linkService |
|
* @property {DownloadManager} downloadManager |
|
*/ |
|
|
|
/** |
|
* @class |
|
* @alias AnnotationElementFactory |
|
*/ |
|
function AnnotationElementFactory() {} |
|
AnnotationElementFactory.prototype = |
|
/** @lends AnnotationElementFactory.prototype */ { |
|
/** |
|
* @param {AnnotationElementParameters} parameters |
|
* @returns {AnnotationElement} |
|
*/ |
|
create: function AnnotationElementFactory_create(parameters) { |
|
var subtype = parameters.data.annotationType; |
|
|
|
switch (subtype) { |
|
case AnnotationType.LINK: |
|
return new LinkAnnotationElement(parameters); |
|
|
|
case AnnotationType.TEXT: |
|
return new TextAnnotationElement(parameters); |
|
|
|
case AnnotationType.WIDGET: |
|
return new WidgetAnnotationElement(parameters); |
|
|
|
case AnnotationType.POPUP: |
|
return new PopupAnnotationElement(parameters); |
|
|
|
case AnnotationType.HIGHLIGHT: |
|
return new HighlightAnnotationElement(parameters); |
|
|
|
case AnnotationType.UNDERLINE: |
|
return new UnderlineAnnotationElement(parameters); |
|
|
|
case AnnotationType.SQUIGGLY: |
|
return new SquigglyAnnotationElement(parameters); |
|
|
|
case AnnotationType.STRIKEOUT: |
|
return new StrikeOutAnnotationElement(parameters); |
|
|
|
case AnnotationType.FILEATTACHMENT: |
|
return new FileAttachmentAnnotationElement(parameters); |
|
|
|
default: |
|
return new AnnotationElement(parameters); |
|
} |
|
} |
|
}; |
|
|
|
/** |
|
* @class |
|
* @alias AnnotationElement |
|
*/ |
|
var AnnotationElement = (function AnnotationElementClosure() { |
|
function AnnotationElement(parameters, isRenderable) { |
|
this.isRenderable = isRenderable || false; |
|
this.data = parameters.data; |
|
this.layer = parameters.layer; |
|
this.page = parameters.page; |
|
this.viewport = parameters.viewport; |
|
this.linkService = parameters.linkService; |
|
this.downloadManager = parameters.downloadManager; |
|
this.imageResourcesPath = parameters.imageResourcesPath; |
|
|
|
if (isRenderable) { |
|
this.container = this._createContainer(); |
|
} |
|
} |
|
|
|
AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ { |
|
/** |
|
* Create an empty container for the annotation's HTML element. |
|
* |
|
* @private |
|
* @memberof AnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
_createContainer: function AnnotationElement_createContainer() { |
|
var data = this.data, page = this.page, viewport = this.viewport; |
|
var container = document.createElement('section'); |
|
var width = data.rect[2] - data.rect[0]; |
|
var height = data.rect[3] - data.rect[1]; |
|
|
|
container.setAttribute('data-annotation-id', data.id); |
|
|
|
// Do *not* modify `data.rect`, since that will corrupt the annotation |
|
// position on subsequent calls to `_createContainer` (see issue 6804). |
|
var rect = Util.normalizeRect([ |
|
data.rect[0], |
|
page.view[3] - data.rect[1] + page.view[1], |
|
data.rect[2], |
|
page.view[3] - data.rect[3] + page.view[1] |
|
]); |
|
|
|
CustomStyle.setProp('transform', container, |
|
'matrix(' + viewport.transform.join(',') + ')'); |
|
CustomStyle.setProp('transformOrigin', container, |
|
-rect[0] + 'px ' + -rect[1] + 'px'); |
|
|
|
if (data.borderStyle.width > 0) { |
|
container.style.borderWidth = data.borderStyle.width + 'px'; |
|
if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) { |
|
// Underline styles only have a bottom border, so we do not need |
|
// to adjust for all borders. This yields a similar result as |
|
// Adobe Acrobat/Reader. |
|
width = width - 2 * data.borderStyle.width; |
|
height = height - 2 * data.borderStyle.width; |
|
} |
|
|
|
var horizontalRadius = data.borderStyle.horizontalCornerRadius; |
|
var verticalRadius = data.borderStyle.verticalCornerRadius; |
|
if (horizontalRadius > 0 || verticalRadius > 0) { |
|
var radius = horizontalRadius + 'px / ' + verticalRadius + 'px'; |
|
CustomStyle.setProp('borderRadius', container, radius); |
|
} |
|
|
|
switch (data.borderStyle.style) { |
|
case AnnotationBorderStyleType.SOLID: |
|
container.style.borderStyle = 'solid'; |
|
break; |
|
|
|
case AnnotationBorderStyleType.DASHED: |
|
container.style.borderStyle = 'dashed'; |
|
break; |
|
|
|
case AnnotationBorderStyleType.BEVELED: |
|
warn('Unimplemented border style: beveled'); |
|
break; |
|
|
|
case AnnotationBorderStyleType.INSET: |
|
warn('Unimplemented border style: inset'); |
|
break; |
|
|
|
case AnnotationBorderStyleType.UNDERLINE: |
|
container.style.borderBottomStyle = 'solid'; |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
if (data.color) { |
|
container.style.borderColor = |
|
Util.makeCssRgb(data.color[0] | 0, |
|
data.color[1] | 0, |
|
data.color[2] | 0); |
|
} else { |
|
// Transparent (invisible) border, so do not draw it at all. |
|
container.style.borderWidth = 0; |
|
} |
|
} |
|
|
|
container.style.left = rect[0] + 'px'; |
|
container.style.top = rect[1] + 'px'; |
|
|
|
container.style.width = width + 'px'; |
|
container.style.height = height + 'px'; |
|
|
|
return container; |
|
}, |
|
|
|
/** |
|
* Create a popup for the annotation's HTML element. This is used for |
|
* annotations that do not have a Popup entry in the dictionary, but |
|
* are of a type that works with popups (such as Highlight annotations). |
|
* |
|
* @private |
|
* @param {HTMLSectionElement} container |
|
* @param {HTMLDivElement|HTMLImageElement|null} trigger |
|
* @param {Object} data |
|
* @memberof AnnotationElement |
|
*/ |
|
_createPopup: |
|
function AnnotationElement_createPopup(container, trigger, data) { |
|
// If no trigger element is specified, create it. |
|
if (!trigger) { |
|
trigger = document.createElement('div'); |
|
trigger.style.height = container.style.height; |
|
trigger.style.width = container.style.width; |
|
container.appendChild(trigger); |
|
} |
|
|
|
var popupElement = new PopupElement({ |
|
container: container, |
|
trigger: trigger, |
|
color: data.color, |
|
title: data.title, |
|
contents: data.contents, |
|
hideWrapper: true |
|
}); |
|
var popup = popupElement.render(); |
|
|
|
// Position the popup next to the annotation's container. |
|
popup.style.left = container.style.width; |
|
|
|
container.appendChild(popup); |
|
}, |
|
|
|
/** |
|
* Render the annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof AnnotationElement |
|
*/ |
|
render: function AnnotationElement_render() { |
|
throw new Error('Abstract method AnnotationElement.render called'); |
|
} |
|
}; |
|
|
|
return AnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias LinkAnnotationElement |
|
*/ |
|
var LinkAnnotationElement = (function LinkAnnotationElementClosure() { |
|
function LinkAnnotationElement(parameters) { |
|
AnnotationElement.call(this, parameters, true); |
|
} |
|
|
|
Util.inherit(LinkAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the link annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof LinkAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function LinkAnnotationElement_render() { |
|
this.container.className = 'linkAnnotation'; |
|
|
|
var link = document.createElement('a'); |
|
addLinkAttributes(link, { url: this.data.url }); |
|
|
|
if (!this.data.url) { |
|
if (this.data.action) { |
|
this._bindNamedAction(link, this.data.action); |
|
} else { |
|
this._bindLink(link, ('dest' in this.data) ? this.data.dest : null); |
|
} |
|
} |
|
|
|
this.container.appendChild(link); |
|
return this.container; |
|
}, |
|
|
|
/** |
|
* Bind internal links to the link element. |
|
* |
|
* @private |
|
* @param {Object} link |
|
* @param {Object} destination |
|
* @memberof LinkAnnotationElement |
|
*/ |
|
_bindLink: function LinkAnnotationElement_bindLink(link, destination) { |
|
var self = this; |
|
|
|
link.href = this.linkService.getDestinationHash(destination); |
|
link.onclick = function() { |
|
if (destination) { |
|
self.linkService.navigateTo(destination); |
|
} |
|
return false; |
|
}; |
|
if (destination) { |
|
link.className = 'internalLink'; |
|
} |
|
}, |
|
|
|
/** |
|
* Bind named actions to the link element. |
|
* |
|
* @private |
|
* @param {Object} link |
|
* @param {Object} action |
|
* @memberof LinkAnnotationElement |
|
*/ |
|
_bindNamedAction: |
|
function LinkAnnotationElement_bindNamedAction(link, action) { |
|
var self = this; |
|
|
|
link.href = this.linkService.getAnchorUrl(''); |
|
link.onclick = function() { |
|
self.linkService.executeNamedAction(action); |
|
return false; |
|
}; |
|
link.className = 'internalLink'; |
|
} |
|
}); |
|
|
|
return LinkAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias TextAnnotationElement |
|
*/ |
|
var TextAnnotationElement = (function TextAnnotationElementClosure() { |
|
function TextAnnotationElement(parameters) { |
|
var isRenderable = !!(parameters.data.hasPopup || |
|
parameters.data.title || parameters.data.contents); |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(TextAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the text annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof TextAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function TextAnnotationElement_render() { |
|
this.container.className = 'textAnnotation'; |
|
|
|
var image = document.createElement('img'); |
|
image.style.height = this.container.style.height; |
|
image.style.width = this.container.style.width; |
|
image.src = this.imageResourcesPath + 'annotation-' + |
|
this.data.name.toLowerCase() + '.svg'; |
|
image.alt = '[{{type}} Annotation]'; |
|
image.dataset.l10nId = 'text_annotation_type'; |
|
image.dataset.l10nArgs = JSON.stringify({type: this.data.name}); |
|
|
|
if (!this.data.hasPopup) { |
|
this._createPopup(this.container, image, this.data); |
|
} |
|
|
|
this.container.appendChild(image); |
|
return this.container; |
|
} |
|
}); |
|
|
|
return TextAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias WidgetAnnotationElement |
|
*/ |
|
var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() { |
|
function WidgetAnnotationElement(parameters) { |
|
var isRenderable = !parameters.data.hasAppearance && |
|
!!parameters.data.fieldValue; |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(WidgetAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the widget annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof WidgetAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function WidgetAnnotationElement_render() { |
|
var content = document.createElement('div'); |
|
content.textContent = this.data.fieldValue; |
|
var textAlignment = this.data.textAlignment; |
|
content.style.textAlign = ['left', 'center', 'right'][textAlignment]; |
|
content.style.verticalAlign = 'middle'; |
|
content.style.display = 'table-cell'; |
|
|
|
var font = (this.data.fontRefName ? |
|
this.page.commonObjs.getData(this.data.fontRefName) : null); |
|
this._setTextStyle(content, font); |
|
|
|
this.container.appendChild(content); |
|
return this.container; |
|
}, |
|
|
|
/** |
|
* Apply text styles to the text in the element. |
|
* |
|
* @private |
|
* @param {HTMLDivElement} element |
|
* @param {Object} font |
|
* @memberof WidgetAnnotationElement |
|
*/ |
|
_setTextStyle: |
|
function WidgetAnnotationElement_setTextStyle(element, font) { |
|
// TODO: This duplicates some of the logic in CanvasGraphics.setFont(). |
|
var style = element.style; |
|
style.fontSize = this.data.fontSize + 'px'; |
|
style.direction = (this.data.fontDirection < 0 ? 'rtl': 'ltr'); |
|
|
|
if (!font) { |
|
return; |
|
} |
|
|
|
style.fontWeight = (font.black ? |
|
(font.bold ? '900' : 'bold') : |
|
(font.bold ? 'bold' : 'normal')); |
|
style.fontStyle = (font.italic ? 'italic' : 'normal'); |
|
|
|
// Use a reasonable default font if the font doesn't specify a fallback. |
|
var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : ''; |
|
var fallbackName = font.fallbackName || 'Helvetica, sans-serif'; |
|
style.fontFamily = fontFamily + fallbackName; |
|
} |
|
}); |
|
|
|
return WidgetAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias PopupAnnotationElement |
|
*/ |
|
var PopupAnnotationElement = (function PopupAnnotationElementClosure() { |
|
function PopupAnnotationElement(parameters) { |
|
var isRenderable = !!(parameters.data.title || parameters.data.contents); |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(PopupAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the popup annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof PopupAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function PopupAnnotationElement_render() { |
|
this.container.className = 'popupAnnotation'; |
|
|
|
var selector = '[data-annotation-id="' + this.data.parentId + '"]'; |
|
var parentElement = this.layer.querySelector(selector); |
|
if (!parentElement) { |
|
return this.container; |
|
} |
|
|
|
var popup = new PopupElement({ |
|
container: this.container, |
|
trigger: parentElement, |
|
color: this.data.color, |
|
title: this.data.title, |
|
contents: this.data.contents |
|
}); |
|
|
|
// Position the popup next to the parent annotation's container. |
|
// PDF viewers ignore a popup annotation's rectangle. |
|
var parentLeft = parseFloat(parentElement.style.left); |
|
var parentWidth = parseFloat(parentElement.style.width); |
|
CustomStyle.setProp('transformOrigin', this.container, |
|
-(parentLeft + parentWidth) + 'px -' + |
|
parentElement.style.top); |
|
this.container.style.left = (parentLeft + parentWidth) + 'px'; |
|
|
|
this.container.appendChild(popup.render()); |
|
return this.container; |
|
} |
|
}); |
|
|
|
return PopupAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias PopupElement |
|
*/ |
|
var PopupElement = (function PopupElementClosure() { |
|
var BACKGROUND_ENLIGHT = 0.7; |
|
|
|
function PopupElement(parameters) { |
|
this.container = parameters.container; |
|
this.trigger = parameters.trigger; |
|
this.color = parameters.color; |
|
this.title = parameters.title; |
|
this.contents = parameters.contents; |
|
this.hideWrapper = parameters.hideWrapper || false; |
|
|
|
this.pinned = false; |
|
} |
|
|
|
PopupElement.prototype = /** @lends PopupElement.prototype */ { |
|
/** |
|
* Render the popup's HTML element. |
|
* |
|
* @public |
|
* @memberof PopupElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function PopupElement_render() { |
|
var wrapper = document.createElement('div'); |
|
wrapper.className = 'popupWrapper'; |
|
|
|
// For Popup annotations we hide the entire section because it contains |
|
// only the popup. However, for Text annotations without a separate Popup |
|
// annotation, we cannot hide the entire container as the image would |
|
// disappear too. In that special case, hiding the wrapper suffices. |
|
this.hideElement = (this.hideWrapper ? wrapper : this.container); |
|
this.hideElement.setAttribute('hidden', true); |
|
|
|
var popup = document.createElement('div'); |
|
popup.className = 'popup'; |
|
|
|
var color = this.color; |
|
if (color) { |
|
// Enlighten the color. |
|
var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0]; |
|
var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1]; |
|
var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2]; |
|
popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0); |
|
} |
|
|
|
var contents = this._formatContents(this.contents); |
|
var title = document.createElement('h1'); |
|
title.textContent = this.title; |
|
|
|
// Attach the event listeners to the trigger element. |
|
this.trigger.addEventListener('click', this._toggle.bind(this)); |
|
this.trigger.addEventListener('mouseover', this._show.bind(this, false)); |
|
this.trigger.addEventListener('mouseout', this._hide.bind(this, false)); |
|
popup.addEventListener('click', this._hide.bind(this, true)); |
|
|
|
popup.appendChild(title); |
|
popup.appendChild(contents); |
|
wrapper.appendChild(popup); |
|
return wrapper; |
|
}, |
|
|
|
/** |
|
* Format the contents of the popup by adding newlines where necessary. |
|
* |
|
* @private |
|
* @param {string} contents |
|
* @memberof PopupElement |
|
* @returns {HTMLParagraphElement} |
|
*/ |
|
_formatContents: function PopupElement_formatContents(contents) { |
|
var p = document.createElement('p'); |
|
var lines = contents.split(/(?:\r\n?|\n)/); |
|
for (var i = 0, ii = lines.length; i < ii; ++i) { |
|
var line = lines[i]; |
|
p.appendChild(document.createTextNode(line)); |
|
if (i < (ii - 1)) { |
|
p.appendChild(document.createElement('br')); |
|
} |
|
} |
|
return p; |
|
}, |
|
|
|
/** |
|
* Toggle the visibility of the popup. |
|
* |
|
* @private |
|
* @memberof PopupElement |
|
*/ |
|
_toggle: function PopupElement_toggle() { |
|
if (this.pinned) { |
|
this._hide(true); |
|
} else { |
|
this._show(true); |
|
} |
|
}, |
|
|
|
/** |
|
* Show the popup. |
|
* |
|
* @private |
|
* @param {boolean} pin |
|
* @memberof PopupElement |
|
*/ |
|
_show: function PopupElement_show(pin) { |
|
if (pin) { |
|
this.pinned = true; |
|
} |
|
if (this.hideElement.hasAttribute('hidden')) { |
|
this.hideElement.removeAttribute('hidden'); |
|
this.container.style.zIndex += 1; |
|
} |
|
}, |
|
|
|
/** |
|
* Hide the popup. |
|
* |
|
* @private |
|
* @param {boolean} unpin |
|
* @memberof PopupElement |
|
*/ |
|
_hide: function PopupElement_hide(unpin) { |
|
if (unpin) { |
|
this.pinned = false; |
|
} |
|
if (!this.hideElement.hasAttribute('hidden') && !this.pinned) { |
|
this.hideElement.setAttribute('hidden', true); |
|
this.container.style.zIndex -= 1; |
|
} |
|
} |
|
}; |
|
|
|
return PopupElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias HighlightAnnotationElement |
|
*/ |
|
var HighlightAnnotationElement = ( |
|
function HighlightAnnotationElementClosure() { |
|
function HighlightAnnotationElement(parameters) { |
|
var isRenderable = !!(parameters.data.hasPopup || |
|
parameters.data.title || parameters.data.contents); |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(HighlightAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the highlight annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof HighlightAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function HighlightAnnotationElement_render() { |
|
this.container.className = 'highlightAnnotation'; |
|
|
|
if (!this.data.hasPopup) { |
|
this._createPopup(this.container, null, this.data); |
|
} |
|
|
|
return this.container; |
|
} |
|
}); |
|
|
|
return HighlightAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias UnderlineAnnotationElement |
|
*/ |
|
var UnderlineAnnotationElement = ( |
|
function UnderlineAnnotationElementClosure() { |
|
function UnderlineAnnotationElement(parameters) { |
|
var isRenderable = !!(parameters.data.hasPopup || |
|
parameters.data.title || parameters.data.contents); |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(UnderlineAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the underline annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof UnderlineAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function UnderlineAnnotationElement_render() { |
|
this.container.className = 'underlineAnnotation'; |
|
|
|
if (!this.data.hasPopup) { |
|
this._createPopup(this.container, null, this.data); |
|
} |
|
|
|
return this.container; |
|
} |
|
}); |
|
|
|
return UnderlineAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias SquigglyAnnotationElement |
|
*/ |
|
var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() { |
|
function SquigglyAnnotationElement(parameters) { |
|
var isRenderable = !!(parameters.data.hasPopup || |
|
parameters.data.title || parameters.data.contents); |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(SquigglyAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the squiggly annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof SquigglyAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function SquigglyAnnotationElement_render() { |
|
this.container.className = 'squigglyAnnotation'; |
|
|
|
if (!this.data.hasPopup) { |
|
this._createPopup(this.container, null, this.data); |
|
} |
|
|
|
return this.container; |
|
} |
|
}); |
|
|
|
return SquigglyAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias StrikeOutAnnotationElement |
|
*/ |
|
var StrikeOutAnnotationElement = ( |
|
function StrikeOutAnnotationElementClosure() { |
|
function StrikeOutAnnotationElement(parameters) { |
|
var isRenderable = !!(parameters.data.hasPopup || |
|
parameters.data.title || parameters.data.contents); |
|
AnnotationElement.call(this, parameters, isRenderable); |
|
} |
|
|
|
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, { |
|
/** |
|
* Render the strikeout annotation's HTML element in the empty container. |
|
* |
|
* @public |
|
* @memberof StrikeOutAnnotationElement |
|
* @returns {HTMLSectionElement} |
|
*/ |
|
render: function StrikeOutAnnotationElement_render() { |
|
this.container.className = 'strikeoutAnnotation'; |
|
|
|
if (!this.data.hasPopup) { |
|
this._createPopup(this.container, null, this.data); |
|
} |
|
|
|
return this.container; |
|
} |
|
}); |
|
|
|
return StrikeOutAnnotationElement; |
|
})(); |
|
|
|
/** |
|
* @class |
|
* @alias FileAttachmentAnnotationElement |
|
*/ |
|
var FileAttachmentAnnotationElement = ( |
|
function FileAttachmentAnnotationElementClosure() { |
|
function FileAttachmentAnnotationElement(parameters) { |
|
AnnotationElement.call(this, parameters, true); |
|
|
|
this.filename = getFilenameFromUrl(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)) { |
|
this._createPopup(this.container, trigger, this.data); |
|
} |
|
|
|
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 |
|
* @property {HTMLDivElement} div |
|
* @property {Array} annotations |
|
* @property {PDFPage} page |
|
* @property {IPDFLinkService} linkService |
|
* @property {string} imageResourcesPath |
|
*/ |
|
|
|
/** |
|
* @class |
|
* @alias AnnotationLayer |
|
*/ |
|
var AnnotationLayer = (function AnnotationLayerClosure() { |
|
return { |
|
/** |
|
* Render a new annotation layer with all annotation elements. |
|
* |
|
* @public |
|
* @param {AnnotationLayerParameters} parameters |
|
* @memberof AnnotationLayer |
|
*/ |
|
render: function AnnotationLayer_render(parameters) { |
|
var annotationElementFactory = new AnnotationElementFactory(); |
|
|
|
for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { |
|
var data = parameters.annotations[i]; |
|
if (!data) { |
|
continue; |
|
} |
|
|
|
var properties = { |
|
data: data, |
|
layer: parameters.div, |
|
page: parameters.page, |
|
viewport: parameters.viewport, |
|
linkService: parameters.linkService, |
|
downloadManager: parameters.downloadManager, |
|
imageResourcesPath: parameters.imageResourcesPath || |
|
getDefaultSetting('imageResourcesPath') |
|
}; |
|
var element = annotationElementFactory.create(properties); |
|
if (element.isRenderable) { |
|
parameters.div.appendChild(element.render()); |
|
} |
|
} |
|
}, |
|
|
|
/** |
|
* Update the annotation elements on existing annotation layer. |
|
* |
|
* @public |
|
* @param {AnnotationLayerParameters} parameters |
|
* @memberof AnnotationLayer |
|
*/ |
|
update: function AnnotationLayer_update(parameters) { |
|
for (var i = 0, ii = parameters.annotations.length; i < ii; i++) { |
|
var data = parameters.annotations[i]; |
|
var element = parameters.div.querySelector( |
|
'[data-annotation-id="' + data.id + '"]'); |
|
if (element) { |
|
CustomStyle.setProp('transform', element, |
|
'matrix(' + parameters.viewport.transform.join(',') + ')'); |
|
} |
|
} |
|
parameters.div.removeAttribute('hidden'); |
|
} |
|
}; |
|
})(); |
|
|
|
exports.AnnotationLayer = AnnotationLayer; |
|
}));
|
|
|