var id = document.location.pathname.split('/')[1]; var annotations = []; var currentPage = 1, rendered = false Ox.load({ 'UI': { loadCSS: false } }, function() { Ox.$parent.bindMessage(function(data, event) { if (event == 'selectAnnotation') { var annotation = annotations.filter(function(a) { return a.id == data.id })[0] var delay = 0 if ( annotation && annotation.page && PDFViewerApplication.pdfViewer.currentPageNumber != annotation.page ) { PDFViewerApplication.pdfViewer.currentPageNumber = annotation.page; delay = 250 } annotation && setTimeout(function() { var el = document.querySelector('.a' + annotation.id); if (el && !isInView(el)) { document.querySelector('#viewerContainer').scrollTop = el.offsetTop + el.parentElement.offsetTop - 64; } }, delay) selectAnnotation(data.id) } else if (event == 'addAnnotation') { createAnnotation() } else if (event == 'addAnnotations') { if (data.replace) { document.querySelectorAll('.oml-annotation').forEach(function(a) { a.remove() }) annotations = [] } data.annotations.forEach(function(annotation) { annotations.push(annotation) renderAnnotation(annotation) }) } else if (event == 'removeAnnotation') { removeAnnotation(data.id) } else { console.log('got', event, 'data', data) } }) }) window.addEventListener('keydown', function(event) { if (event.key == 'Delete') { var selected = document.querySelector('.oml-annotation.selected') if (selected) { removeAnnotation(selected.dataset.id) } } else if (event.key == 'n' || event.keyCode == 13) { if (event.target.nodeName != 'INPUT') { var selected = document.querySelector('.oml-annotation.selected') if (!window.getSelection().isCollapsed) { createAnnotation() } else if (selected) { console.log('editNote?', selected.dataset.id) } event.stopPropagation() event.preventDefault() } } }) window.addEventListener('mouseup', function(event) { var selection = window.getSelection() if (selection.isCollapsed) { Ox.$parent.postMessage('selectText', false) } else { Ox.$parent.postMessage('selectText', true) } }) function bindEvents() { if (!window.PDFViewerApplication || !window.PDFViewerApplication.eventBus) { setTimeout(bindEvents, 10) return } PDFViewerApplication.eventBus.on('pagerendered', function(event) { loadAnnotations(event.pageNumber) }) } bindEvents() function getHighlight() { var pageNumber = PDFViewerApplication.pdfViewer.currentPageNumber; var pageIndex = pageNumber - 1; var page = PDFViewerApplication.pdfViewer.getPageView(pageIndex); var pageRect = page.canvas.getClientRects()[0]; var selection = window.getSelection() var selectionRects = selection.getRangeAt(0).getClientRects(); var viewport = page.viewport; var selected = Array.from(selectionRects).map(function (r) { return viewport.convertToPdfPoint(r.left - pageRect.x, r.top - pageRect.y).concat( viewport.convertToPdfPoint(r.right - pageRect.x, r.bottom - pageRect.y)); }); var text = selection.toString(); var position = [pageNumber].concat(Ox.sort(selected.map(function(c) { return [c[1], c[0]]}))[0]); return { page: pageNumber, pageLabel: PDFViewerApplication.pdfViewer.currentPageLabel, position: position, coords: selected, text: text, id: Ox.SHA1(pageNumber.toString() + JSON.stringify(selected)) }; } function createAnnotation() { var selected = document.querySelector('.oml-annotation.selected') if (selected) { deselectAllAnnotations() } var annot = getHighlight() renderAnnotation(annot) addAnnotation(annot) window.getSelection().removeAllRanges(); } function renderAnnotation(annotation) { var pageIndex = annotation.page - 1; var page = PDFViewerApplication.pdfViewer.getPageView(pageIndex); if (!page || !page.canvas) { setTimeout(function() { renderAnnotation(annotation) }, 50) return } var pageElement = page.canvas.parentElement.parentElement; var viewport = page.viewport; annotation.coords.forEach(function (rect) { var bounds = viewport.convertToViewportRectangle(rect); var el = document.createElement('div'); el.classList.add('oml-annotation') el.classList.add('a' + annotation.id) el.classList.add('page' + annotation.page) el.dataset.id = annotation.id el.setAttribute('style', 'position: absolute; background-color: yellow;opacity:0.3;' + 'left:' + Math.min(bounds[0], bounds[2]) + 'px; top:' + Math.min(bounds[1], bounds[3]) + 'px;' + 'width:' + Math.abs(bounds[0] - bounds[2]) + 'px; height:' + Math.abs(bounds[1] - bounds[3]) + 'px;'); el.addEventListener('click', function() { if (!el.classList.contains('selected')) { selectAnnotation(annotation.id) Ox.$parent.postMessage('selectAnnotation', {id: annotation.id}) } }); pageElement.appendChild(el); }); } function addAnnotation(annotation) { annotations.push(annotation) Ox.$parent.postMessage('addAnnotation', annotation) } function selectAnnotation(id) { document.querySelectorAll('.oml-annotation.selected').forEach(function(g) { g.classList.remove('selected') g.style.backgroundColor = 'yellow' }) document.querySelectorAll('.oml-annotation.a' + id).forEach(function(g) { g.classList.add('selected') g.style.backgroundColor = 'blue' }) } function deselectAnnotation(id) { document.querySelectorAll('.oml-annotation.a' + id).forEach(function(g) { g.classList.remove('selected') g.style.backgroundColor = 'yellow' }) } function deselectAllAnnotations() { var ids = [] document.querySelectorAll('.oml-annotation.selected').forEach(function(g) { g.classList.remove('selected') g.style.backgroundColor = 'yellow' var id = $(g).parents('.oml-annotation').data('id') //console.log('deselect', g, id) if (!Ox.contains(ids, id)) { ids.push(id) Ox.$parent.postMessage('selectAnnotation', {id: null}) } }) } function removeAnnotation(id) { document.querySelectorAll('.oml-annotation.a' + id).forEach(function(a) { a.remove() }) annotations = annotations.filter(function(annotation) { return annotation.id != id }) Ox.$parent.postMessage('removeAnnotation', {id: id}) } function loadAnnotations(page) { document.querySelectorAll('.oml-annotation.page' + page).forEach(function(e) { e.remove() }) annotations.filter(function(a) { return a.page == page }).forEach(function(annot) { renderAnnotation(annot) }) } function isInView(element) { var docViewTop = $(window).scrollTop(); var docViewBottom = docViewTop + $(window).height(); var elementTop = $(element).offset().top; var elementBottom = elementTop + $(element).height(); return elementTop < docViewBottom && elementBottom > docViewTop; }