From 076b3433b4de05a51716bbeccd6a839a3d0a8d6c Mon Sep 17 00:00:00 2001 From: Samuel Chantaraud Date: Fri, 7 Mar 2014 10:48:42 -0400 Subject: [PATCH] Improved annotations' display/behavior. Added an "InteractiveAnnotation" class to homogenize the annotations' structure (highlighting) and user interactions (for now, used for text and link annotations). Text annotations: The appearance (AP) has priority over the icon (Name). The popup extends horizontally (up to a limit) as well as vertically. Reduced the title's font size. The annotation's color (C) is used to color the popup's background. On top of the mouseover show/hide behavior, a click on the icon will lock the annotation open (for mobile purposes). It can be closed with another click on either the icon or the popup. An annotation printing is conditioned by its "print" bit Unsupported annotations are not displayed at all. --- src/core/core.js | 9 +- src/core/evaluator.js | 6 +- src/core/worker.js | 5 +- src/display/api.js | 87 +++++++---- src/shared/annotation.js | 250 +++++++++++++++++++++++-------- web/images/annotation-noicon.svg | 7 + web/page_view.js | 17 ++- web/viewer.css | 55 ++++--- 8 files changed, 305 insertions(+), 131 deletions(-) create mode 100644 web/images/annotation-noicon.svg diff --git a/src/core/core.js b/src/core/core.js index 13f64454c..ab17644c7 100644 --- a/src/core/core.js +++ b/src/core/core.js @@ -134,7 +134,7 @@ var Page = (function PageClosure() { }.bind(this)); return promise; }, - getOperatorList: function Page_getOperatorList(handler) { + getOperatorList: function Page_getOperatorList(handler, intent) { var self = this; var promise = new LegacyPromise(); @@ -169,11 +169,12 @@ var Page = (function PageClosure() { var contentStream = data[0]; - var opList = new OperatorList(handler, self.pageIndex); + var opList = new OperatorList(intent, handler, self.pageIndex); handler.send('StartRenderPage', { transparency: partialEvaluator.hasBlendModes(self.resources), - pageIndex: self.pageIndex + pageIndex: self.pageIndex, + intent: intent }); partialEvaluator.getOperatorList(contentStream, self.resources, opList); pageListPromise.resolve(opList); @@ -191,7 +192,7 @@ var Page = (function PageClosure() { } var annotationsReadyPromise = Annotation.appendToOperatorList( - annotations, pageOpList, pdfManager, partialEvaluator); + annotations, pageOpList, pdfManager, partialEvaluator, intent); annotationsReadyPromise.then(function () { pageOpList.flush(true); promise.resolve(pageOpList); diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 288a7299b..f1d835eda 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -1376,7 +1376,7 @@ var OperatorList = (function OperatorListClosure() { } - function OperatorList(messageHandler, pageIndex) { + function OperatorList(intent, messageHandler, pageIndex) { this.messageHandler = messageHandler; // When there isn't a message handler the fn array needs to be able to grow // since we can't flush the operators. @@ -1389,6 +1389,7 @@ var OperatorList = (function OperatorListClosure() { this.dependencies = {}; this.pageIndex = pageIndex; this.fnIndex = 0; + this.intent = intent; } OperatorList.prototype = { @@ -1449,7 +1450,8 @@ var OperatorList = (function OperatorListClosure() { lastChunk: lastChunk, length: this.length }, - pageIndex: this.pageIndex + pageIndex: this.pageIndex, + intent: this.intent }, null, transfers); this.dependencies = []; this.fnIndex = 0; diff --git a/src/core/worker.js b/src/core/worker.js index b1d86a116..c31bf8c6d 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -334,7 +334,7 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { var pageNum = data.pageIndex + 1; var start = Date.now(); // Pre compile the pdf page and fetch the fonts/images. - page.getOperatorList(handler).then(function(operatorList) { + page.getOperatorList(handler, data.intent).then(function(operatorList) { info('page=' + pageNum + ' - getOperatorList: time=' + (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length); @@ -366,7 +366,8 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = { handler.send('PageError', { pageNum: pageNum, - error: wrappedException + error: wrappedException, + intent: data.intent }); }); }); diff --git a/src/display/api.js b/src/display/api.js index 63a312da7..d34d2426b 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -341,10 +341,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() { this.stats.enabled = !!globalScope.PDFJS.enableStats; this.commonObjs = transport.commonObjs; this.objs = new PDFObjects(); - this.receivingOperatorList = false; this.cleanupAfterRender = false; this.pendingDestroy = false; - this.renderTasks = []; + this.intentStates = {}; } PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ { /** @@ -423,12 +422,21 @@ var PDFPageProxy = (function PDFPageProxyClosure() { // this call to render. this.pendingDestroy = false; + var renderingIntent = 'intent' in params ? + (params.intent == 'print' ? 'print' : 'display') : + 'display'; + + if (!this.intentStates[renderingIntent]) { + this.intentStates[renderingIntent] = {}; + } + var intentState = this.intentStates[renderingIntent]; + // If there is no displayReadyPromise yet, then the operatorList was never // requested before. Make the request and create the promise. - if (!this.displayReadyPromise) { - this.receivingOperatorList = true; - this.displayReadyPromise = new LegacyPromise(); - this.operatorList = { + if (!intentState.displayReadyPromise) { + intentState.receivingOperatorList = true; + intentState.displayReadyPromise = new LegacyPromise(); + intentState.operatorList = { fnArray: [], argsArray: [], lastChunk: false @@ -436,18 +444,23 @@ var PDFPageProxy = (function PDFPageProxyClosure() { this.stats.time('Page Request'); this.transport.messageHandler.send('RenderPageRequest', { - pageIndex: this.pageNumber - 1 + pageIndex: this.pageNumber - 1, + intent: renderingIntent }); } var internalRenderTask = new InternalRenderTask(complete, params, this.objs, this.commonObjs, - this.operatorList, this.pageNumber); - this.renderTasks.push(internalRenderTask); + intentState.operatorList, + this.pageNumber); + if (!intentState.renderTasks) { + intentState.renderTasks = []; + } + intentState.renderTasks.push(internalRenderTask); var renderTask = new RenderTask(internalRenderTask); var self = this; - this.displayReadyPromise.then( + intentState.displayReadyPromise.then( function pageDisplayReadyPromise(transparency) { if (self.pendingDestroy) { complete(); @@ -463,9 +476,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() { ); function complete(error) { - var i = self.renderTasks.indexOf(internalRenderTask); + var i = intentState.renderTasks.indexOf(internalRenderTask); if (i >= 0) { - self.renderTasks.splice(i, 1); + intentState.renderTasks.splice(i, 1); } if (self.cleanupAfterRender) { @@ -513,14 +526,17 @@ var PDFPageProxy = (function PDFPageProxyClosure() { */ _tryDestroy: function PDFPageProxy__destroy() { if (!this.pendingDestroy || - this.renderTasks.length !== 0 || - this.receivingOperatorList) { + Object.keys(this.intentStates).some(function(intent) { + var intentState = this.intentStates[intent]; + return intentState.renderTasks.length !== 0 || + intentState.receivingOperatorList; + }, this)) { return; } - delete this.operatorList; - delete this.displayReadyPromise; - delete this.annotationsPromise; + Object.keys(this.intentStates).forEach(function(intent) { + delete this.intentStates[intent]; + }, this); this.objs.clear(); this.pendingDestroy = false; }, @@ -528,28 +544,33 @@ var PDFPageProxy = (function PDFPageProxyClosure() { * For internal use only. * @ignore */ - _startRenderPage: function PDFPageProxy_startRenderPage(transparency) { - this.displayReadyPromise.resolve(transparency); + _startRenderPage: function PDFPageProxy_startRenderPage(transparency, + intent) { + var intentState = this.intentStates[intent]; + intentState.displayReadyPromise.resolve(transparency); }, /** * For internal use only. * @ignore */ - _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk) { + _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk, + intent) { + var intentState = this.intentStates[intent]; // Add the new chunk to the current operator list. for (var i = 0, ii = operatorListChunk.length; i < ii; i++) { - this.operatorList.fnArray.push(operatorListChunk.fnArray[i]); - this.operatorList.argsArray.push(operatorListChunk.argsArray[i]); + intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]); + intentState.operatorList.argsArray.push( + operatorListChunk.argsArray[i]); } - this.operatorList.lastChunk = operatorListChunk.lastChunk; + intentState.operatorList.lastChunk = operatorListChunk.lastChunk; // Notify all the rendering tasks there are more operators to be consumed. - for (var i = 0; i < this.renderTasks.length; i++) { - this.renderTasks[i].operatorListChanged(); + for (var i = 0; i < intentState.renderTasks.length; i++) { + intentState.renderTasks[i].operatorListChanged(); } if (operatorListChunk.lastChunk) { - this.receivingOperatorList = false; + intentState.receivingOperatorList = false; this._tryDestroy(); } } @@ -775,13 +796,13 @@ var WorkerTransport = (function WorkerTransportClosure() { var page = this.pageCache[data.pageIndex]; page.stats.timeEnd('Page Request'); - page._startRenderPage(data.transparency); + page._startRenderPage(data.transparency, data.intent); }, this); messageHandler.on('RenderPageChunk', function transportRender(data) { var page = this.pageCache[data.pageIndex]; - page._renderPageChunk(data.operatorList); + page._renderPageChunk(data.operatorList, data.intent); }, this); messageHandler.on('commonobj', function transportObj(data) { @@ -824,8 +845,9 @@ var WorkerTransport = (function WorkerTransportClosure() { var pageIndex = data[1]; var type = data[2]; var pageProxy = this.pageCache[pageIndex]; - if (pageProxy.objs.hasData(id)) + if (pageProxy.objs.hasData(id)) { return; + } switch (type) { case 'JpegStream': @@ -861,10 +883,11 @@ var WorkerTransport = (function WorkerTransportClosure() { this.workerReadyPromise.reject(data); }, this); - messageHandler.on('PageError', function transportError(data) { + messageHandler.on('PageError', function transportError(data, intent) { var page = this.pageCache[data.pageNum - 1]; - if (page.displayReadyPromise) - page.displayReadyPromise.reject(data.error); + var intentState = page.intentStates[intent]; + if (intentState.displayReadyPromise) + intentState.displayReadyPromise.reject(data.error); else error(data.error); }, this); diff --git a/src/shared/annotation.js b/src/shared/annotation.js index 631aaf865..67587b91c 100644 --- a/src/shared/annotation.js +++ b/src/shared/annotation.js @@ -21,6 +21,9 @@ 'use strict'; +var HIGHLIGHT_OFFSET = 4; // px +var SUPPORTED_TYPES = ['Link', 'Text', 'Widget']; + var Annotation = (function AnnotationClosure() { // 12.5.5: Algorithm: Appearance streams function getTransformMatrix(rect, bbox, matrix) { @@ -143,25 +146,50 @@ var Annotation = (function AnnotationClosure() { }, // TODO(mack): Remove this, it's not really that helpful. - getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) { + getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect, + borderWidth) { assert(!isWorker, 'getEmptyContainer() should be called from main thread'); + var bWidth = borderWidth || 0; + rect = rect || this.data.rect; var element = document.createElement(tagName); - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; + element.style.borderWidth = bWidth + 'px'; + var width = rect[2] - rect[0] - 2 * bWidth; + var height = rect[3] - rect[1] - 2 * bWidth; + element.style.width = width + 'px'; + element.style.height = height + 'px'; return element; }, + isInvisible: function Annotation_isInvisible() { + var data = this.data; + if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) { + return false; + } else { + return !!(data && + data.annotationFlags && // Default: not invisible + data.annotationFlags & 0x1); // Invisible + } + }, + isViewable: function Annotation_isViewable() { var data = this.data; - return !!( - data && - (!data.annotationFlags || - !(data.annotationFlags & 0x22)) && // Hidden or NoView - data.rect // rectangle is nessessary - ); + return !!(!this.isInvisible() && + data && + (!data.annotationFlags || + !(data.annotationFlags & 0x22)) && // Hidden or NoView + data.rect); // rectangle is nessessary + }, + + isPrintable: function Annotation_isPrintable() { + var data = this.data; + return !!(!this.isInvisible() && + data && + data.annotationFlags && // Default: not printable + data.annotationFlags & 0x4 && // Print + data.rect); // rectangle is nessessary }, loadResources: function(keys) { @@ -182,7 +210,7 @@ var Annotation = (function AnnotationClosure() { return promise; }, - getOperatorList: function Annotation_getToOperatorList(evaluator) { + getOperatorList: function Annotation_getOperatorList(evaluator) { var promise = new LegacyPromise(); @@ -289,7 +317,7 @@ var Annotation = (function AnnotationClosure() { var annotation = new Constructor(params); - if (annotation.isViewable()) { + if (annotation.isViewable() || annotation.isPrintable()) { return annotation; } else { warn('unimplemented annotation type: ' + subtype); @@ -297,7 +325,7 @@ var Annotation = (function AnnotationClosure() { }; Annotation.appendToOperatorList = function Annotation_appendToOperatorList( - annotations, opList, pdfManager, partialEvaluator) { + annotations, opList, pdfManager, partialEvaluator, intent) { function reject(e) { annotationsReadyPromise.reject(e); @@ -307,7 +335,11 @@ var Annotation = (function AnnotationClosure() { var annotationPromises = []; for (var i = 0, n = annotations.length; i < n; ++i) { - annotationPromises.push(annotations[i].getOperatorList(partialEvaluator)); + if (intent === 'display' && annotations[i].isViewable() || + intent === 'print' && annotations[i].isPrintable()) { + annotationPromises.push( + annotations[i].getOperatorList(partialEvaluator)); + } } Promise.all(annotationPromises).then(function(datas) { opList.addOp(OPS.beginAnnotations, []); @@ -519,9 +551,64 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() { return TextWidgetAnnotation; })(); +var InteractiveAnnotation = (function InteractiveAnnotationClosure() { + function InteractiveAnnotation(params) { + Annotation.call(this, params); + } + + Util.inherit(InteractiveAnnotation, Annotation, { + hasHtml: function InteractiveAnnotation_hasHtml() { + return true; + }, + + highlight: function InteractiveAnnotation_highlight() { + if (this.highlightElement && + this.highlightElement.hasAttribute('hidden')) { + this.highlightElement.removeAttribute('hidden'); + } + }, + + unhighlight: function InteractiveAnnotation_unhighlight() { + if (this.highlightElement && + !this.highlightElement.hasAttribute('hidden')) { + this.highlightElement.setAttribute('hidden', true); + } + }, + + initContainer: function InteractiveAnnotation_initContainer() { + + var item = this.data; + var rect = item.rect; + + var container = this.getEmptyContainer('section', rect, item.borderWidth); + container.style.backgroundColor = item.color; + + var color = item.color; + var rgb = []; + for (var i = 0; i < 3; ++i) { + rgb[i] = Math.round(color[i] * 255); + } + item.colorCssRgb = Util.makeCssRgb(rgb); + + var highlight = document.createElement('div'); + highlight.className = 'annotationHighlight'; + highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px'; + highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px'; + highlight.setAttribute('hidden', true); + + this.highlightElement = highlight; + container.appendChild(this.highlightElement); + + return container; + } + }); + + return InteractiveAnnotation; +})(); + var TextAnnotation = (function TextAnnotationClosure() { function TextAnnotation(params) { - Annotation.call(this, params); + InteractiveAnnotation.call(this, params); if (params.data) { return; @@ -534,22 +621,21 @@ var TextAnnotation = (function TextAnnotationClosure() { var title = dict.get('T'); data.content = stringToPDFString(content || ''); data.title = stringToPDFString(title || ''); - data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name; + + if (data.hasAppearance) { + data.name = 'NoIcon'; + } else { + data.name = dict.has('Name') ? dict.get('Name').name : 'Note'; + } + + if (dict.has('C')) { + data.hasBgColor = true; + } } var ANNOT_MIN_SIZE = 10; - Util.inherit(TextAnnotation, Annotation, { - - getOperatorList: function TextAnnotation_getOperatorList(evaluator) { - var promise = new LegacyPromise(); - promise.resolve(new OperatorList()); - return promise; - }, - - hasHtml: function TextAnnotation_hasHtml() { - return true; - }, + Util.inherit(TextAnnotation, InteractiveAnnotation, { getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) { assert(!isWorker, 'getHtmlElement() shall be called from main thread'); @@ -565,23 +651,40 @@ var TextAnnotation = (function TextAnnotationClosure() { rect[2] = rect[0] + (rect[3] - rect[1]); // make it square } - var container = this.getEmptyContainer('section', rect); + var container = this.initContainer(); container.className = 'annotText'; - var image = document.createElement('img'); + var image = document.createElement('img'); image.style.height = container.style.height; + image.style.width = container.style.width; var iconName = item.name; image.src = PDFJS.imageResourcesPath + 'annotation-' + iconName.toLowerCase() + '.svg'; image.alt = '[{{type}} Annotation]'; image.dataset.l10nId = 'text_annotation_type'; image.dataset.l10nArgs = JSON.stringify({type: iconName}); + + var contentWrapper = document.createElement('div'); + contentWrapper.className = 'annotTextContentWrapper'; + contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px'; + contentWrapper.style.top = '-10px'; + var content = document.createElement('div'); + content.className = 'annotTextContent'; content.setAttribute('hidden', true); + if (item.hasBgColor) { + var color = item.color; + var rgb = []; + for (var i = 0; i < 3; ++i) { + // Enlighten the color (70%) + var c = Math.round(color[i] * 255); + rgb[i] = Math.round((255 - c) * 0.7) + c; + } + content.style.backgroundColor = Util.makeCssRgb(rgb); + } + var title = document.createElement('h1'); var text = document.createElement('p'); - content.style.left = Math.floor(rect[2] - rect[0]) + 'px'; - content.style.top = '0px'; title.textContent = item.title; if (!item.content && !item.title) { @@ -597,28 +700,57 @@ var TextAnnotation = (function TextAnnotationClosure() { } text.appendChild(e); - var showAnnotation = function showAnnotation() { - container.style.zIndex += 1; - content.removeAttribute('hidden'); + var pinned = false; + + var showAnnotation = function showAnnotation(pin) { + if (pin) { + pinned = true; + } + if (content.hasAttribute('hidden')) { + container.style.zIndex += 1; + content.removeAttribute('hidden'); + } }; - var hideAnnotation = function hideAnnotation(e) { - if (e.toElement || e.relatedTarget) { // No context menu is used + var hideAnnotation = function hideAnnotation(unpin) { + if (unpin) { + pinned = false; + } + if (!content.hasAttribute('hidden') && !pinned) { container.style.zIndex -= 1; content.setAttribute('hidden', true); } }; - content.addEventListener('mouseover', showAnnotation, false); - content.addEventListener('mouseout', hideAnnotation, false); - image.addEventListener('mouseover', showAnnotation, false); - image.addEventListener('mouseout', hideAnnotation, false); + var toggleAnnotation = function toggleAnnotation() { + if (pinned) { + hideAnnotation(true); + } else { + showAnnotation(true); + } + }; + + var self = this; + image.addEventListener('click', function image_clickHandler() { + toggleAnnotation(); + }, false); + image.addEventListener('mouseover', function image_mouseOverHandler() { + showAnnotation(); + }, false); + image.addEventListener('mouseout', function image_mouseOutHandler() { + hideAnnotation(); + }, false); + + content.addEventListener('click', function content_clickHandler() { + hideAnnotation(true); + }, false); } content.appendChild(title); content.appendChild(text); + contentWrapper.appendChild(content); container.appendChild(image); - container.appendChild(content); + container.appendChild(contentWrapper); return container; } @@ -629,7 +761,7 @@ var TextAnnotation = (function TextAnnotationClosure() { var LinkAnnotation = (function LinkAnnotationClosure() { function LinkAnnotation(params) { - Annotation.call(this, params); + InteractiveAnnotation.call(this, params); if (params.data) { return; @@ -692,36 +824,28 @@ var LinkAnnotation = (function LinkAnnotationClosure() { return url; } - Util.inherit(LinkAnnotation, Annotation, { + Util.inherit(LinkAnnotation, InteractiveAnnotation, { hasOperatorList: function LinkAnnotation_hasOperatorList() { return false; }, - hasHtml: function LinkAnnotation_hasHtml() { - return true; - }, - getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) { - var rect = this.data.rect; - var element = document.createElement('a'); - var borderWidth = this.data.borderWidth; - element.style.borderWidth = borderWidth + 'px'; - var color = this.data.color; - var rgb = []; - for (var i = 0; i < 3; ++i) { - rgb[i] = Math.round(color[i] * 255); - } - element.style.borderColor = Util.makeCssRgb(rgb); - element.style.borderStyle = 'solid'; + var container = this.initContainer(); + container.className = 'annotLink'; - var width = rect[2] - rect[0] - 2 * borderWidth; - var height = rect[3] - rect[1] - 2 * borderWidth; - element.style.width = width + 'px'; - element.style.height = height + 'px'; + var item = this.data; + var rect = item.rect; - element.href = this.data.url || ''; - return element; + container.style.borderColor = item.colorCssRgb; + container.style.borderStyle = 'solid'; + + var link = document.createElement('a'); + link.href = link.title = this.data.url || ''; + + container.appendChild(link); + + return container; } }); diff --git a/web/images/annotation-noicon.svg b/web/images/annotation-noicon.svg new file mode 100644 index 000000000..c07d10808 --- /dev/null +++ b/web/images/annotation-noicon.svg @@ -0,0 +1,7 @@ + + + diff --git a/web/page_view.js b/web/page_view.js index 1e4efbad4..ac693078a 100644 --- a/web/page_view.js +++ b/web/page_view.js @@ -306,10 +306,13 @@ var PageView = function pageView(container, id, scale, CustomStyle.setProp('transformOrigin', element, transformOriginStr); if (data.subtype === 'Link' && !data.url) { - if (data.action) { - bindNamedAction(element, data.action); - } else { - bindLink(element, ('dest' in data) ? data.dest : null); + var link = element.getElementsByTagName('a')[0]; + if (link) { + if (data.action) { + bindNamedAction(link, data.action); + } else { + bindLink(link, ('dest' in data) ? data.dest : null); + } } } @@ -579,6 +582,7 @@ var PageView = function pageView(container, id, scale, canvasContext: ctx, viewport: this.viewport, textLayer: textLayer, + // intent: 'default', // === 'display' continueCallback: function pdfViewcContinueCallback(cont) { if (PDFView.highestPriorityPage !== 'page' + self.id) { self.renderingState = RenderingStates.PAUSED; @@ -650,13 +654,13 @@ var PageView = function pageView(container, id, scale, var renderContext = { canvasContext: ctx, - viewport: viewport + viewport: viewport, + intent: 'print' }; pdfPage.render(renderContext).promise.then(function() { // Tell the printEngine that rendering this canvas/page has finished. obj.done(); - self.pdfPage.destroy(); }, function(error) { console.error(error); // Tell the printEngine that rendering this canvas/page has failed. @@ -666,7 +670,6 @@ var PageView = function pageView(container, id, scale, } else { obj.done(); } - self.pdfPage.destroy(); }); }; }; diff --git a/web/viewer.css b/web/viewer.css index d07521705..a7008d84d 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -1247,14 +1247,7 @@ canvas { background-color: white; } -.page > a, -.annotationLayer > a { - display: block; - position: absolute; -} - -.page > a:hover, -.annotationLayer > a:hover { +.annotLink > a:hover { opacity: 0.2; background: #ff0; box-shadow: 0px 2px 10px #ff0; @@ -1319,29 +1312,49 @@ canvas { ::selection { background:rgba(0,0,255,0.3); } ::-moz-selection { background:rgba(0,0,255,0.3); } -.annotText > div { - z-index: 200; +.annotationHighlight { position: absolute; - padding: 0.6em; - max-width: 20em; - background-color: #FFFF99; - box-shadow: 0px 2px 10px #333; - border-radius: 7px; + border: 2px #FFFF99 solid; } .annotText > img { position: absolute; - opacity: 0.6; + cursor: pointer; } -.annotText > img:hover { - opacity: 1; +.annotTextContentWrapper { + position: absolute; + width: 20em; } -.annotText > div > h1 { - font-size: 1.2em; +.annotTextContent { + z-index: 200; + float: left; + max-width: 20em; + background-color: #FFFF99; + box-shadow: 0px 2px 5px #333; + border-radius: 2px; + padding: 0.6em; + cursor: pointer; +} + +.annotTextContent > h1 { + font-size: 1em; border-bottom: 1px solid #000000; - margin: 0px; + padding-bottom: 0.2em; +} + +.annotTextContent > p { + padding-top: 0.2em; +} + +.annotLink > a { + position: absolute; + font-size: 1em; + top: 0; + left: 0; + width: 100%; + height: 100%; } #errorWrapper {