This repository has been archived on 2024-01-19. You can view files and clone it, but cannot push or open issues or pull requests.
epubreader/public/pdfjs/controllers/notes_controller.js

428 lines
14 KiB
JavaScript
Raw Permalink Normal View History

2020-04-21 20:37:42 +00:00
PDFJS.reader.NotesController = function(book) {
var book = this.book,
reader = this,
eventBus = this.eventBus,
$notesView = $("#notesView"),
$notes = $("#notes"),
$text = $("#note-text"),
$anchor = $("#note-anchor"),
$next = $("#next"),
$prev = $("#prev"),
$touch_nav = $("#touch_nav"),
$viewer = $("#viewer"),
annotations = reader.settings.annotations,
renderer = book.renderer,
popups = [];
var show = function() {
$notesView.addClass('open');
$text.focus();
};
var hide = function() {
$notesView.removeClass('open');
};
$text.on("keydown", function(e) {
e.stopPropagation();
});
var insertAtPoint = function(e) {
var range,
textNode,
offset,
doc = document,
loc,
annotation;
// standard
if (doc.caretPositionFromPoint) {
range = doc.caretPositionFromPoint(e.clientX, e.clientY);
textNode = range.offsetNode;
offset = range.offset;
// WebKit
} else if (doc.caretRangeFromPoint) {
range = doc.caretRangeFromPoint(e.clientX, e.clientY);
textNode = range.startContainer;
offset = range.startOffset;
}
console.log("textNode", textNode, "offset", offset);
console.log(e);
if (textNode.nodeType !== 3) {
for (var i=0; i < textNode.childNodes.length; i++) {
if (textNode.childNodes[i].nodeType == 3) {
textNode = textNode.childNodes[i];
break;
}
}
}
// Find the end of the sentence
offset = textNode.textContent.indexOf(".", offset);
if(offset === -1){
offset = textNode.length; // Last item
} else {
offset += 1; // After the period
}
loc = "";
annotation = new reader.Annotation('annotation', loc, $text.val());
// save...
reader.addAnnotation(annotation);
// show...
addAnnotationItem(annotation);
// add marker...
placeMarker(annotation);
// clear entry
$text.val('');
$anchor.removeClass("icon-location_off");
$anchor.addClass("icon-room");
$text.prop("disabled", false);
book.off("renderer:click", insertAtPoint);
};
var addAnnotationItem = function(annotation) {
$notes.append(createItem(annotation));
//reader.settings.session.setBookmark(annotation.id, annotation.anchor, annotation.type, annotation);
};
var removeAnnotation = function (id) {
if (annotations[id] !== undefined) {
if (annotations[id].type == "bookmark")
eventBus.dispatch("bookmarkremoved", {
source: this,
id: id
});
deleteAnnotationItem(id);
delete annotations[id];
reader.settings.session.deleteBookmark(id);
}
};
var deleteAnnotationItem = function (id) {
var item = document.getElementById(id);
if (item)
item.remove();
};
/* items are HTML-representations of annotations */
var createItem = function(annotation){
var item = document.createElement("li");
var text = document.createElement("div");
var date = document.createElement("div");
var edit = document.createElement("span");
var del = document.createElement("span");
var link = document.createElement("a");
var div = document.createElement("div");
var save = document.createElement("span");
var cancel = document.createElement("span");
text.textContent = annotation.body;
date.textContent = new Date(annotation.edited).toUTCString();
item.classList.add("note");
del.classList.add("item-delete", "item-control", "icon-delete");
edit.classList.add("item-edit", "item-control", "icon-rate_review");
link.classList.add("note-link");
//link.classList.add("note-link", "icon-link2");
date.classList.add("item-date");
del.setAttribute("title", "delete");
edit.setAttribute("title", "edit");
link.setAttribute("title", "context");
item.setAttribute("id", annotation.id);
save.classList.add("item-save", "edit-control", "hide", "icon-check");
cancel.classList.add("item-cancel", "edit-control", "hide", "icon-close");
save.setAttribute("display", "none");
cancel.setAttribute("display", "none");
link.href = "#"+annotation.anchor;
link.textContent = "Page " + annotation.anchor;
link.onclick = function(){
reader.queuePage(annotation.anchor);
return false;
};
if (!annotation.readonly) {
del.onclick = function() {
var id = this.parentNode.parentNode.getAttribute("id");
deleteAnnotationItem(id);
reader.removeAnnotation(id);
};
save.onclick = function() {
var id = this.parentNode.parentNode.getAttribute("id");
var annotation = annotations[id];
var text = this.parentNode.parentNode.firstChild;
try {
annotation.body = text.textContent;
reader.updateAnnotation(annotation);
} catch (e) {
console.log("Updating annotation failed: " + e);
}
closeEditor(id);
};
cancel.onclick = function () {
var id = this.parentNode.parentNode.getAttribute("id");
var text = this.parentNode.parentNode.firstChild;
text.textContent = annotations[id].body;
closeEditor(id);
};
edit.onclick = function() {
openEditor(this.parentNode.parentNode.getAttribute("id"));
};
div.appendChild(cancel);
div.appendChild(save);
div.appendChild(del);
div.appendChild(edit);
}
div.appendChild(link);
item.appendChild(text);
if (!annotation.readonly)
item.appendChild(date);
item.appendChild(div);
return item;
};
var editAnnotation = function (e) {
var text = e.target;
var id = text.parentNode.getAttribute("id");
if (e.keyCode === 27) { // escape - cancel editor, discard changes
text.textContent = annotations[id].body;
closeEditor(id);
}
e.stopPropagation();
};
var openEditor = function(id) {
var item = document.getElementById(id);
var text = item.firstChild;
$(item).find(".item-control").toggleClass("hide");
$(item).find(".edit-control").toggleClass("hide");
text.setAttribute("contenteditable", "true");
text.classList.add("editable");
text.addEventListener("keydown", editAnnotation, false);
};
var closeEditor = function (id) {
var item = document.getElementById(id);
var text = item.firstChild;
$(item).find(".item-control").toggleClass("hide");
$(item).find(".edit-control").toggleClass("hide");
text.classList.remove("editable");
text.removeAttribute("contenteditable");
text.removeEventListener("keydown", editAnnotation, false);
};
var findIndex = function (id) {
// list has items
var i,
list = $notes[0].getElementsByTagName("li");
for (i = 0; i < list.length; i++) {
if (list[i].getAttribute("id") === id)
break;
}
return i+1;
};
var placeMarker = function(annotation){
var doc = book.renderer.doc,
marker = document.createElement("span"),
mark = document.createElement("a");
marker.classList.add("note-marker", "footnotesuperscript", "reader_generated");
marker.id = "note-" + annotation.id;
mark.innerHTML = findIndex(annotation.id) + "[Reader]";
marker.appendChild(mark);
// epubcfi.addMarker(annotation.anchor, doc, marker);
markerEvents(marker, annotation.body);
renumberMarkers();
}
var markerEvents = function(item, txt){
var id = item.id;
var showPop = function(){
var poppos,
iheight = renderer.height,
iwidth = renderer.width,
tip,
pop,
maxHeight = 225,
itemRect,
left,
top,
pos;
//-- create a popup with endnote inside of it
if(!popups[id]) {
popups[id] = document.createElement("div");
popups[id].setAttribute("class", "popup");
pop_content = document.createElement("div");
popups[id].appendChild(pop_content);
pop_content.innerHTML = txt;
pop_content.setAttribute("class", "pop_content");
renderer.render.document.body.appendChild(popups[id]);
//-- TODO: will these leak memory? - Fred
popups[id].addEventListener("mouseover", onPop, false);
popups[id].addEventListener("mouseout", offPop, false);
//-- Add hide on page change
renderer.on("renderer:locationChanged", hidePop, this);
renderer.on("renderer:locationChanged", offPop, this);
// chapter.book.on("renderer:chapterDestroy", hidePop, this);
}
pop = popups[id];
//-- get location of item
itemRect = item.getBoundingClientRect();
left = itemRect.left;
top = itemRect.top;
//-- show the popup
pop.classList.add("show");
//-- locations of popup
popRect = pop.getBoundingClientRect();
//-- position the popup
pop.style.left = left - popRect.width / 2 + "px";
pop.style.top = top + "px";
//-- Adjust max height
if(maxHeight > iheight / 2.5) {
maxHeight = iheight / 2.5;
pop_content.style.maxHeight = maxHeight + "px";
}
//-- switch above / below
if(popRect.height + top >= iheight - 25) {
pop.style.top = top - popRect.height + "px";
pop.classList.add("above");
}else{
pop.classList.remove("above");
}
//-- switch left
if(left - popRect.width <= 0) {
pop.style.left = left + "px";
pop.classList.add("left");
}else{
pop.classList.remove("left");
}
//-- switch right
if(left + popRect.width / 2 >= iwidth) {
//-- TEMP MOVE: 300
pop.style.left = left - 300 + "px";
popRect = pop.getBoundingClientRect();
pop.style.left = left - popRect.width + "px";
//-- switch above / below again
if(popRect.height + top >= iheight - 25) {
pop.style.top = top - popRect.height + "px";
pop.classList.add("above");
}else{
pop.classList.remove("above");
}
pop.classList.add("right");
}else{
pop.classList.remove("right");
}
}
var onPop = function(){
popups[id].classList.add("on");
}
var offPop = function(){
popups[id].classList.remove("on");
}
var hidePop = function(){
setTimeout(function(){
popups[id].classList.remove("show");
}, 100);
}
var openSidebar = function(){
reader.SidebarController.changePanelTo('Notes');
reader.SidebarController.show();
};
item.addEventListener("mouseover", showPop, false);
item.addEventListener("mouseout", hidePop, false);
item.addEventListener("click", openSidebar, false);
}
$anchor.on("click", function(e){
if ($anchor[0].classList.contains("icon-room")) {
$anchor.removeClass("icon-room");
$anchor.addClass("icon-location_off");
$text.prop("disabled", true);
// disable extra-wide navigation as it interferes with anchor placment
if ($prev.hasClass("touch_nav")) {
$prev.removeClass("touch_nav");
$next.removeClass("touch_nav");
$prev.addClass("restore_touch_nav");
}
// listen for selection
$viewer.on("click", insertAtPoint);
} else {
$text.prop("disabled", false);
$anchor.removeClass("icon-location_off");
$anchor.addClass("icon-room");
if ($prev.hasClass("restore_touch_nav")) {
$prev.removeClass("restore_touch_nav");
$prev.addClass("touch_nav");
$next.addClass("touch_nav");
}
$viewer.off("click", insertAtPoint);
}
});
for (var note in annotations) {
if (annotations.hasOwnProperty(note) && (annotations[note].type === "annotation"))
addAnnotationItem(annotations[note]);
};
return {
"show" : show,
"hide" : hide,
"createItem": createItem,
"addItem" : addAnnotationItem,
"removeAnnotation" : removeAnnotation
};
};