diff --git a/LICENSE b/LICENSE index f8a848205..db52dec8e 100644 --- a/LICENSE +++ b/LICENSE @@ -9,6 +9,7 @@ Yury Delendik Kalervo Kujala Adil Allawi <@ironymark> + Jakob Miland Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/src/core.js b/src/core.js index 71c18f178..93cbc72ac 100644 --- a/src/core.js +++ b/src/core.js @@ -323,10 +323,10 @@ var Page = (function PageClosure() { if (a) { switch (a.get('S').name) { case 'URI': - link.url = a.get('URI'); + item.url = a.get('URI'); break; case 'GoTo': - link.dest = a.get('D'); + item.dest = a.get('D'); break; default: TODO('other link types'); @@ -334,7 +334,7 @@ var Page = (function PageClosure() { } else if (annotation.has('Dest')) { // simple destination link var dest = annotation.get('Dest'); - link.dest = isName(dest) ? dest.name : dest; + item.dest = isName(dest) ? dest.name : dest; } break; case 'Widget': @@ -379,6 +379,16 @@ var Page = (function PageClosure() { item.textAlignment = getInheritableProperty(annotation, 'Q'); item.flags = getInheritableProperty(annotation, 'Ff') || 0; break; + case 'Text': + var content = annotation.get('Contents'); + var title = annotation.get('T'); + item.content = stringToPDFString(content || ''); + item.title = stringToPDFString(title || ''); + item.name = annotation.get('Name').name; + break; + default: + TODO('unimplemented annotation type: ' + subtype.name); + break; } items.push(item); } diff --git a/web/images/check.svg b/web/images/check.svg new file mode 100644 index 000000000..e0e1590a9 --- /dev/null +++ b/web/images/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/images/comment.svg b/web/images/comment.svg new file mode 100644 index 000000000..84feef1c8 --- /dev/null +++ b/web/images/comment.svg @@ -0,0 +1,3 @@ + + + diff --git a/web/viewer.css b/web/viewer.css index a1ef92810..0b64d9d86 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -247,6 +247,35 @@ canvas { line-height:1.3; } +.annotComment > div { + position: absolute; +} + +.annotComment > img { + position: absolute; +} + +.annotComment > img:hover { + cursor: pointer; + opacity: 0.7; +} + +.annotComment > div { + padding: 0.2em; + max-width: 20em; + background-color: #F1E47B; + box-shadow: 0px 2px 10px #333; + -moz-box-shadow: 0px 2px 10px #333; + -webkit-box-shadow: 0px 2px 10px #333; +} + +.annotComment > div > h1 { + font-weight: normal; + font-size: 1.2em; + border-bottom: 1px solid #000000; + margin: 0px; +} + /* TODO: file FF bug to support ::-moz-selection:window-inactive so we can override the opaque grey background when the window is inactive; see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */ diff --git a/web/viewer.js b/web/viewer.js index 32b3101c2..e2ffcef29 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -11,7 +11,7 @@ var kCssUnits = 96.0 / 72.0; var kScrollbarPadding = 40; var kMinScale = 0.25; var kMaxScale = 4.0; - +var kImageDirectory = './images/'; var Cache = function cacheCache(size) { var data = []; @@ -475,6 +475,41 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, element.style.height = Math.ceil(item.height * scale) + 'px'; return element; } + function createCommentAnnotation(type, item) { + var container = document.createElement('section'); + container.className = 'annotComment'; + + var image = createElementWithStyle('img', item); + image.src = kImageDirectory + type.toLowerCase() + '.svg'; + var content = document.createElement('div'); + content.setAttribute('hidden', true); + var title = document.createElement('h1'); + var text = document.createElement('p'); + var offsetPos = Math.floor(item.x - view.x + item.width); + content.style.left = (offsetPos * scale) + 'px'; + content.style.top = (Math.floor(item.y - view.y) * scale) + 'px'; + title.textContent = item.title; + + if (!item.content) { + content.setAttribute('hidden', true); + } else { + text.innerHTML = item.content.replace('\n', '
'); + image.addEventListener('mouseover', function annotationImageOver() { + this.nextSibling.removeAttribute('hidden'); + }, false); + + image.addEventListener('mouseout', function annotationImageOut() { + this.nextSibling.setAttribute('hidden', true); + }, false); + } + + content.appendChild(title); + content.appendChild(text); + container.appendChild(image); + container.appendChild(content); + + return container; + } var items = content.getAnnotations(); for (var i = 0; i < items.length; i++) { @@ -487,6 +522,11 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight, bindLink(link, ('dest' in item) ? item.dest : null); div.appendChild(link); break; + case 'Text': + var comment = createCommentAnnotation(item.name, item); + if (comment) + div.appendChild(comment); + break; } } }