diff --git a/static/html/pdf.html b/static/html/pdf.html index e063457..2fcf5e8 100644 --- a/static/html/pdf.html +++ b/static/html/pdf.html @@ -50,9 +50,11 @@ See https://github.com/adobe-type-tools/cmap-resources - + + @@ -426,7 +428,6 @@ See https://github.com/adobe-type-tools/cmap-resources - diff --git a/static/reader/epub.js b/static/reader/epub.js index c065bed..dbc013d 100644 --- a/static/reader/epub.js +++ b/static/reader/epub.js @@ -2,6 +2,7 @@ var reader; var id = document.location.pathname.split('/')[1]; var annotations = JSON.parse(localStorage[id + '.annotations'] || '[]') +var currentSelection; function saveAnnotations() { localStorage[id + '.annotations'] = JSON.stringify(annotations) @@ -45,6 +46,7 @@ document.onreadystatechange = function () { rendition.annotations.highlight(a.cfiRange, a.data || {}, onHighlightClicked); }) + reader.rendition.on('keydown', function(event) { if (event.key == 'Delete') { document.querySelectorAll('.epubjs-hl.selected').forEach(function(a) { @@ -55,23 +57,43 @@ document.onreadystatechange = function () { saveAnnotations() }) } + if (event.key == 'n') { + if (currentSelection) { + /* + var range = currentSelection.contents.window.getSelection().getRangeAt(0) + console.log( + currentSelection.cfiRange, + reader.rendition.book.section().cfiFromRange(range).toString() + ) + //currentSelection.cfiRange = reader.rendition.book.section().cfiFromRange(range).toString() + */ + + rendition.annotations.highlight(currentSelection.cfiRange, currentSelection.data, onHighlightClicked); + currentSelection.contents.window.getSelection().removeAllRanges(); + delete currentSelection.contents + annotations.push(currentSelection) + saveAnnotations() + document.querySelectorAll('.epubjs-hl.selected').forEach(function(other) { + other.classList.remove('selected') + }) + currentSelection = null + } + } + }) + rendition.on("mark", function(cfiRange, contents) { + console.log('!! mark', cfiRange) }) rendition.on("selected", function(cfiRange, contents) { + console.log('!! selected', cfiRange) getText(book, cfiRange, function(quote) { - var data = { - quote: quote - } - rendition.annotations.highlight(cfiRange, data, onHighlightClicked); - annotations.push({ + currentSelection = { cfiRange: cfiRange, - data: data - }) - saveAnnotations() - document.querySelectorAll('.epubjs-hl.selected').forEach(function(other) { - other.classList.remove('selected') - }) + data: { + quote: quote + }, + contents: contents + } }) - contents.window.getSelection().removeAllRanges(); }); } }; diff --git a/static/reader/pdf.js b/static/reader/pdf.js new file mode 100644 index 0000000..490c62d --- /dev/null +++ b/static/reader/pdf.js @@ -0,0 +1,124 @@ +var id = document.location.pathname.split('/')[1]; +var annotations = JSON.parse(localStorage[id + '.annotations'] || '[]') +var currentPage = 1, rendered = false + +function getID() { + var id = 0; + while (annotations.filter(function(a) { + return a.id == id + }).length) { + id++ + } + return id +} + +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') { + if (!window.getSelection().isCollapsed) { + var annot = getHighlight() + renderAnnotation(annot) + addAnnotation(annot) + window.getSelection().removeAllRanges(); + } + event.stopPropagation() + event.preventDefault() + } +}) + +window.addEventListener('pagerendered', function (event) { + loadAnnotations(event.detail.pageNumber - 1) +}) + +function getHighlight() { + var pageIndex = PDFViewerApplication.pdfViewer.currentPageNumber - 1; + var page = PDFViewerApplication.pdfViewer.getPageView(pageIndex); + var pageRect = page.canvas.getClientRects()[0]; + var selectionRects = window.getSelection().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)); + }); + return {page: pageIndex, coords: selected, id: getID()}; +} + +function renderAnnotation(annotation) { + var pageIndex = annotation.page; + var page = PDFViewerApplication.pdfViewer.getPageView(pageIndex); + if (!page.canvas) { + setTimeout(function() { + renderAnnotation(annotation) + }, 50) + return + } + var pageElement = page.canvas.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')) { + deselectAnnotation(annotation.id) + } else { + selectAnnotation(annotation.id) + } + }); + pageElement.appendChild(el); + }); +} + +function addAnnotation(annotation) { + annotations.push(annotation) + saveAnnotations() +} + +function selectAnnotation(id) { + 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 removeAnnotation(id) { + document.querySelectorAll('.oml-annotation.a' + id).forEach(function(a) { + a.remove() + }) + annotations = annotations.filter(function(annotation) { + return annotation.id != id + }) + saveAnnotations() +} + +function saveAnnotations() { + localStorage[id + '.annotations'] = JSON.stringify(annotations) +} + +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) + }) +} +