mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
Move highlighting from Contents to View
This commit is contained in:
parent
9f0623b798
commit
37b0a2d42e
7 changed files with 231 additions and 211 deletions
|
@ -43,6 +43,14 @@
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ref="epubjs-mk"] {
|
||||||
|
background: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgeG1sbnM6eGxpbms9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsnIHg9JzBweCcgeT0nMHB4JyB2aWV3Qm94PScwIDAgNzUgNzUnPjxnIGZpbGw9JyNCREJEQkQnIGlkPSdidWJibGUnPjxwYXRoIGNsYXNzPSdzdDAnIGQ9J00zNy41LDkuNEMxOS42LDkuNCw1LDIwLjUsNSwzNC4zYzAsNS45LDIuNywxMS4zLDcuMSwxNS42TDkuNiw2NS42bDE5LTcuM2MyLjgsMC42LDUuOCwwLjksOC45LDAuOSBDNTUuNSw1OS4yLDcwLDQ4LjEsNzAsMzQuM0M3MCwyMC41LDU1LjQsOS40LDM3LjUsOS40eicvPjwvZz48L3N2Zz4=") no-repeat;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -62,7 +70,8 @@
|
||||||
var rendition = book.renderTo("viewer", {
|
var rendition = book.renderTo("viewer", {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: 600,
|
height: 600,
|
||||||
ignoreClass: 'annotator-hl'
|
ignoreClass: 'annotator-hl',
|
||||||
|
manager: "continuous"
|
||||||
});
|
});
|
||||||
|
|
||||||
var displayed = rendition.display(6);
|
var displayed = rendition.display(6);
|
||||||
|
|
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "epubjs",
|
"name": "epubjs",
|
||||||
"version": "0.3.47",
|
"version": "0.3.53",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -9808,9 +9808,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"marks-pane": {
|
"marks-pane": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/marks-pane/-/marks-pane-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/marks-pane/-/marks-pane-1.0.4.tgz",
|
||||||
"integrity": "sha512-S3OuXWgPlCR9nQEN52Ut/beuw7SwkmVrTd9Ce38uEoaTbaO3/5fzD5KPERlWILH1mfi/B91DYfwCeC0bgsliXQ=="
|
"integrity": "sha512-k3rauzqKlwDhIZClZ7/JGo3LEjxf1ReXzNoyFolniwKHsbAA8Cs8Ir4hpsWFB3KEW9NvtTYcffRnJCUybu0FVA=="
|
||||||
},
|
},
|
||||||
"math-expression-evaluator": {
|
"math-expression-evaluator": {
|
||||||
"version": "1.2.17",
|
"version": "1.2.17",
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
"event-emitter": "^0.3.5",
|
"event-emitter": "^0.3.5",
|
||||||
"jszip": "^3.1.4",
|
"jszip": "^3.1.4",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"marks-pane": "^1.0.2",
|
"marks-pane": "^1.0.4",
|
||||||
"path-webpack": "0.0.3",
|
"path-webpack": "0.0.3",
|
||||||
"stream-browserify": "^2.0.1",
|
"stream-browserify": "^2.0.1",
|
||||||
"xmldom": "^0.1.27"
|
"xmldom": "^0.1.27"
|
||||||
|
|
|
@ -35,7 +35,7 @@ class Annotations {
|
||||||
this._annotations = {};
|
this._annotations = {};
|
||||||
this._annotationsBySectionIndex = {};
|
this._annotationsBySectionIndex = {};
|
||||||
|
|
||||||
this.rendition.hooks.content.register(this.inject.bind(this));
|
this.rendition.hooks.render.register(this.inject.bind(this));
|
||||||
this.rendition.hooks.unloaded.register(this.clear.bind(this));
|
this.rendition.hooks.unloaded.register(this.clear.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,10 +59,11 @@ class Annotations {
|
||||||
this._annotationsBySectionIndex[sectionIndex] = [hash];
|
this._annotationsBySectionIndex[sectionIndex] = [hash];
|
||||||
}
|
}
|
||||||
|
|
||||||
let contents = this.rendition.getContents();
|
let views = this.rendition.views();
|
||||||
contents.forEach( (content) => {
|
|
||||||
if (annotation.sectionIndex === content.sectionIndex) {
|
views.each( (view) => {
|
||||||
annotation.attach(content);
|
if (annotation.sectionIndex === view.index) {
|
||||||
|
annotation.attach(view);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -75,10 +76,10 @@ class Annotations {
|
||||||
if (hash in this._annotations) {
|
if (hash in this._annotations) {
|
||||||
let annotation = this._annotations[hash];
|
let annotation = this._annotations[hash];
|
||||||
|
|
||||||
let contents = this.rendition.getContents();
|
let views = this.rendition.views();
|
||||||
contents.forEach( (content) => {
|
views.each( (view) => {
|
||||||
if (annotation.sectionIndex === content.sectionIndex) {
|
if (annotation.sectionIndex === view.index) {
|
||||||
annotation.detach(content);
|
annotation.detach(view);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -102,24 +103,24 @@ class Annotations {
|
||||||
return this._annotations.forEach.apply(this._annotations, arguments);
|
return this._annotations.forEach.apply(this._annotations, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
inject (contents) {
|
inject (view) {
|
||||||
let sectionIndex = contents.index;
|
let sectionIndex = view.index;
|
||||||
if (sectionIndex in this._annotationsBySectionIndex) {
|
if (sectionIndex in this._annotationsBySectionIndex) {
|
||||||
let annotations = this._annotationsBySectionIndex[sectionIndex];
|
let annotations = this._annotationsBySectionIndex[sectionIndex];
|
||||||
annotations.forEach((hash) => {
|
annotations.forEach((hash) => {
|
||||||
let annotation = this._annotations[hash];
|
let annotation = this._annotations[hash];
|
||||||
annotation.attach(contents);
|
annotation.attach(view);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear (contents) {
|
clear (view) {
|
||||||
let sectionIndex = contents.index;
|
let sectionIndex = view.index;
|
||||||
if (sectionIndex in this._annotationsBySectionIndex) {
|
if (sectionIndex in this._annotationsBySectionIndex) {
|
||||||
let annotations = this._annotationsBySectionIndex[sectionIndex];
|
let annotations = this._annotationsBySectionIndex[sectionIndex];
|
||||||
annotations.forEach((hash) => {
|
annotations.forEach((hash) => {
|
||||||
let annotation = this._annotations[hash];
|
let annotation = this._annotations[hash];
|
||||||
annotation.detach(contents);
|
annotation.detach(view);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,20 +141,22 @@ class Annotation {
|
||||||
type,
|
type,
|
||||||
cfiRange,
|
cfiRange,
|
||||||
data,
|
data,
|
||||||
sectionIndex
|
sectionIndex,
|
||||||
|
cb
|
||||||
}) {
|
}) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.cfiRange = cfiRange;
|
this.cfiRange = cfiRange;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.sectionIndex = sectionIndex;
|
this.sectionIndex = sectionIndex;
|
||||||
this.mark = undefined;
|
this.mark = undefined;
|
||||||
|
this.cb = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
update (data) {
|
update (data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
attach (contents) {
|
attach (view) {
|
||||||
let {cfiRange, data, type, mark, cb} = this;
|
let {cfiRange, data, type, mark, cb} = this;
|
||||||
let result;
|
let result;
|
||||||
/*
|
/*
|
||||||
|
@ -161,12 +164,13 @@ class Annotation {
|
||||||
return; // already added
|
return; // already added
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (type === "highlight") {
|
if (type === "highlight") {
|
||||||
result = contents.highlight(cfiRange, data, cb);
|
result = view.highlight(cfiRange, data, cb);
|
||||||
} else if (type === "underline") {
|
} else if (type === "underline") {
|
||||||
result = contents.underline(cfiRange, data, cb);
|
result = view.underline(cfiRange, data, cb);
|
||||||
} else if (type === "mark") {
|
} else if (type === "mark") {
|
||||||
result = contents.mark(cfiRange, data, cb);
|
result = view.mark(cfiRange, data, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mark = result;
|
this.mark = result;
|
||||||
|
@ -174,17 +178,17 @@ class Annotation {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
detach (contents) {
|
detach (view) {
|
||||||
let {cfiRange, type} = this;
|
let {cfiRange, type} = this;
|
||||||
let result;
|
let result;
|
||||||
|
|
||||||
if (contents) {
|
if (view) {
|
||||||
if (type === "highlight") {
|
if (type === "highlight") {
|
||||||
result = contents.unhighlight(cfiRange);
|
result = view.unhighlight(cfiRange);
|
||||||
} else if (type === "underline") {
|
} else if (type === "underline") {
|
||||||
result = contents.ununderline(cfiRange);
|
result = view.ununderline(cfiRange);
|
||||||
} else if (type === "mark") {
|
} else if (type === "mark") {
|
||||||
result = contents.unmark(cfiRange);
|
result = view.unmark(cfiRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
170
src/contents.js
170
src/contents.js
|
@ -3,7 +3,6 @@ import {isNumber, prefixed, borders} from "./utils/core";
|
||||||
import EpubCFI from "./epubcfi";
|
import EpubCFI from "./epubcfi";
|
||||||
import Mapping from "./mapping";
|
import Mapping from "./mapping";
|
||||||
import {replaceLinks} from "./utils/replacements";
|
import {replaceLinks} from "./utils/replacements";
|
||||||
import { Pane, Highlight, Underline } from "marks-pane";
|
|
||||||
|
|
||||||
// Dom events to listen for
|
// Dom events to listen for
|
||||||
const EVENTS = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
|
const EVENTS = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
|
||||||
|
@ -32,11 +31,6 @@ class Contents {
|
||||||
this.sectionIndex = sectionIndex || 0;
|
this.sectionIndex = sectionIndex || 0;
|
||||||
this.cfiBase = cfiBase || "";
|
this.cfiBase = cfiBase || "";
|
||||||
|
|
||||||
this.pane = undefined;
|
|
||||||
this.highlights = {};
|
|
||||||
this.underlines = {};
|
|
||||||
this.marks = {};
|
|
||||||
|
|
||||||
this.listeners();
|
this.listeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +339,6 @@ class Contents {
|
||||||
height: height
|
height: height
|
||||||
};
|
};
|
||||||
|
|
||||||
this.pane && this.pane.render();
|
|
||||||
this.onResize && this.onResize(this._size);
|
this.onResize && this.onResize(this._size);
|
||||||
this.emit("resize", this._size);
|
this.emit("resize", this._size);
|
||||||
}
|
}
|
||||||
|
@ -534,7 +527,6 @@ class Contents {
|
||||||
ready = true;
|
ready = true;
|
||||||
// Let apply
|
// Let apply
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.pane && this.pane.render();
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
@ -605,7 +597,6 @@ class Contents {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.pane && this.pane.render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addScript(src) {
|
addScript(src) {
|
||||||
|
@ -840,167 +831,6 @@ class Contents {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight(cfiRange, data={}, cb) {
|
|
||||||
let range = this.range(cfiRange);
|
|
||||||
let emitter = () => {
|
|
||||||
this.emit("markClicked", cfiRange, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
data["epubcfi"] = cfiRange;
|
|
||||||
|
|
||||||
if (!this.pane) {
|
|
||||||
this.pane = new Pane(this.content, this.document.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
let m = new Highlight(range, "epubjs-hl", data, {'fill': 'yellow', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'});
|
|
||||||
let h = this.pane.addMark(m);
|
|
||||||
|
|
||||||
this.highlights[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] };
|
|
||||||
|
|
||||||
h.element.addEventListener("click", emitter);
|
|
||||||
|
|
||||||
if (cb) {
|
|
||||||
h.element.addEventListener("click", cb);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
underline(cfiRange, data={}, cb) {
|
|
||||||
let range = this.range(cfiRange);
|
|
||||||
let emitter = () => {
|
|
||||||
this.emit("markClicked", cfiRange, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
data["epubcfi"] = cfiRange;
|
|
||||||
|
|
||||||
if (!this.pane) {
|
|
||||||
this.pane = new Pane(this.content, this.document.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
let m = new Underline(range, "epubjs-ul", data, {'stroke': 'black', 'stroke-opacity': '0.3', 'mix-blend-mode': 'multiply'});
|
|
||||||
let h = this.pane.addMark(m);
|
|
||||||
|
|
||||||
this.underlines[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] };
|
|
||||||
|
|
||||||
h.element.addEventListener("click", emitter);
|
|
||||||
|
|
||||||
if (cb) {
|
|
||||||
h.element.addEventListener("click", cb);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
mark(cfiRange, data={}, cb) {
|
|
||||||
let range = this.range(cfiRange);
|
|
||||||
|
|
||||||
let container = range.commonAncestorContainer;
|
|
||||||
let parent = (container.nodeType === 1) ? container : container.parentNode;
|
|
||||||
let emitter = () => {
|
|
||||||
this.emit("markClicked", cfiRange, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
parent.setAttribute("ref", "epubjs-mk");
|
|
||||||
|
|
||||||
parent.dataset["epubcfi"] = cfiRange;
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
Object.keys(data).forEach((key) => {
|
|
||||||
parent.dataset[key] = data[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.addEventListener("click", emitter);
|
|
||||||
|
|
||||||
if (cb) {
|
|
||||||
parent.addEventListener("click", cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.marks[cfiRange] = { "element": parent, "listeners": [emitter, cb] };
|
|
||||||
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
mark(cfiRange, data={}, cb) {
|
|
||||||
|
|
||||||
if (cfiRange in this.marks) {
|
|
||||||
let item = this.marks[cfiRange];
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = this.range(cfiRange);
|
|
||||||
|
|
||||||
let container = range.commonAncestorContainer;
|
|
||||||
let parent = (container.nodeType === 1) ? container : container.parentNode;
|
|
||||||
let emitter = (e) => {
|
|
||||||
this.emit("markClicked", cfiRange, data);
|
|
||||||
};
|
|
||||||
|
|
||||||
let pos = parent.getBoundingClientRect();
|
|
||||||
let mark = this.document.createElement('a');
|
|
||||||
mark.setAttribute("ref", "epubjs-mk");
|
|
||||||
mark.style.position = "absolute";
|
|
||||||
mark.style.top = `${pos.top}px`;
|
|
||||||
mark.style.left = `${pos.right}px`;
|
|
||||||
|
|
||||||
mark.dataset["epubcfi"] = cfiRange;
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
Object.keys(data).forEach((key) => {
|
|
||||||
mark.dataset[key] = data[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cb) {
|
|
||||||
mark.addEventListener("click", cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
mark.addEventListener("click", emitter);
|
|
||||||
|
|
||||||
this.content.appendChild(mark);
|
|
||||||
|
|
||||||
this.marks[cfiRange] = { "element": mark, "listeners": [emitter, cb] };
|
|
||||||
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
unhighlight(cfiRange) {
|
|
||||||
let item;
|
|
||||||
if (cfiRange in this.highlights) {
|
|
||||||
item = this.highlights[cfiRange];
|
|
||||||
this.pane.removeMark(item.mark);
|
|
||||||
item.listeners.forEach((l) => {
|
|
||||||
if (l) { item.element.removeEventListener("click", l) };
|
|
||||||
});
|
|
||||||
delete this.highlights[cfiRange];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ununderline(cfiRange) {
|
|
||||||
let item;
|
|
||||||
if (cfiRange in this.underlines) {
|
|
||||||
item = this.underlines[cfiRange];
|
|
||||||
this.pane.removeMark(item.mark);
|
|
||||||
item.listeners.forEach((l) => {
|
|
||||||
if (l) { item.element.removeEventListener("click", l) };
|
|
||||||
});
|
|
||||||
delete this.underlines[cfiRange];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unmark(cfiRange) {
|
|
||||||
let item;
|
|
||||||
if (cfiRange in this.marks) {
|
|
||||||
item = this.marks[cfiRange];
|
|
||||||
this.content.removeChild(item.element);
|
|
||||||
item.listeners.forEach((l) => {
|
|
||||||
if (l) { item.element.removeEventListener("click", l) };
|
|
||||||
});
|
|
||||||
delete this.marks[cfiRange];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
// Stop observing
|
// Stop observing
|
||||||
if(this.observer) {
|
if(this.observer) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import EventEmitter from "event-emitter";
|
||||||
import {extend, borders, uuid, isNumber, bounds, defer} from "../../utils/core";
|
import {extend, borders, uuid, isNumber, bounds, defer} from "../../utils/core";
|
||||||
import EpubCFI from "../../epubcfi";
|
import EpubCFI from "../../epubcfi";
|
||||||
import Contents from "../../contents";
|
import Contents from "../../contents";
|
||||||
|
import { Pane, Highlight, Underline } from "marks-pane";
|
||||||
|
|
||||||
class IframeView {
|
class IframeView {
|
||||||
constructor(section, options) {
|
constructor(section, options) {
|
||||||
|
@ -36,6 +37,12 @@ class IframeView {
|
||||||
this.layout = this.settings.layout;
|
this.layout = this.settings.layout;
|
||||||
// Dom events to listen for
|
// Dom events to listen for
|
||||||
// this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
|
// this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
|
||||||
|
|
||||||
|
this.pane = undefined;
|
||||||
|
this.highlights = {};
|
||||||
|
this.underlines = {};
|
||||||
|
this.marks = {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container(axis) {
|
container(axis) {
|
||||||
|
@ -47,6 +54,7 @@ class IframeView {
|
||||||
element.style.height = "0px";
|
element.style.height = "0px";
|
||||||
element.style.width = "0px";
|
element.style.width = "0px";
|
||||||
element.style.overflow = "hidden";
|
element.style.overflow = "hidden";
|
||||||
|
element.style.position = "relative";
|
||||||
|
|
||||||
if(axis && axis == "horizontal"){
|
if(axis && axis == "horizontal"){
|
||||||
element.style.display = "block";
|
element.style.display = "block";
|
||||||
|
@ -297,6 +305,8 @@ class IframeView {
|
||||||
heightDelta: heightDelta,
|
heightDelta: heightDelta,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.pane && this.pane.render();
|
||||||
|
|
||||||
this.onResize(this, size);
|
this.onResize(this, size);
|
||||||
|
|
||||||
this.emit("resized", size);
|
this.emit("resized", size);
|
||||||
|
@ -484,8 +494,166 @@ class IframeView {
|
||||||
return this.elementBounds;
|
return this.elementBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
highlight(cfiRange, data={}, cb) {
|
||||||
|
if (!this.contents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let range = this.contents.range(cfiRange);
|
||||||
|
|
||||||
|
let emitter = () => {
|
||||||
|
this.emit("markClicked", cfiRange, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
data["epubcfi"] = cfiRange;
|
||||||
|
|
||||||
|
if (!this.pane) {
|
||||||
|
this.pane = new Pane(this.iframe, this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
let m = new Highlight(range, "epubjs-hl", data, {'fill': 'yellow', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'});
|
||||||
|
let h = this.pane.addMark(m);
|
||||||
|
|
||||||
|
this.highlights[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] };
|
||||||
|
|
||||||
|
h.element.setAttribute("ref", "epubjs-hl");
|
||||||
|
h.element.addEventListener("click", emitter);
|
||||||
|
h.element.addEventListener("touchstart", emitter);
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
h.element.addEventListener("click", cb);
|
||||||
|
h.element.addEventListener("touchstart", cb);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
underline(cfiRange, data={}, cb) {
|
||||||
|
if (!this.contents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let range = this.contents.range(cfiRange);
|
||||||
|
let emitter = () => {
|
||||||
|
this.emit("markClicked", cfiRange, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
data["epubcfi"] = cfiRange;
|
||||||
|
|
||||||
|
if (!this.pane) {
|
||||||
|
this.pane = new Pane(this.iframe, this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
let m = new Underline(range, "epubjs-ul", data, {'stroke': 'black', 'stroke-opacity': '0.3', 'mix-blend-mode': 'multiply'});
|
||||||
|
let h = this.pane.addMark(m);
|
||||||
|
|
||||||
|
this.underlines[cfiRange] = { "mark": h, "element": h.element, "listeners": [emitter, cb] };
|
||||||
|
|
||||||
|
h.element.setAttribute("ref", "epubjs-ul");
|
||||||
|
h.element.addEventListener("click", emitter);
|
||||||
|
h.element.addEventListener("touchstart", emitter);
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
h.element.addEventListener("click", cb);
|
||||||
|
h.element.addEventListener("touchstart", cb);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark(cfiRange, data={}, cb) {
|
||||||
|
|
||||||
|
if (cfiRange in this.marks) {
|
||||||
|
let item = this.marks[cfiRange];
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
let range = this.contents.range(cfiRange);
|
||||||
|
|
||||||
|
let container = range.commonAncestorContainer;
|
||||||
|
let parent = (container.nodeType === 1) ? container : container.parentNode;
|
||||||
|
|
||||||
|
let emitter = (e) => {
|
||||||
|
this.emit("markClicked", cfiRange, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
let pos = parent.getBoundingClientRect();
|
||||||
|
let mark = this.document.createElement('a');
|
||||||
|
mark.setAttribute("ref", "epubjs-mk");
|
||||||
|
mark.style.position = "absolute";
|
||||||
|
mark.style.top = `${pos.top}px`;
|
||||||
|
mark.style.left = `${pos.right}px`;
|
||||||
|
|
||||||
|
mark.dataset["epubcfi"] = cfiRange;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
Object.keys(data).forEach((key) => {
|
||||||
|
mark.dataset[key] = data[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb) {
|
||||||
|
mark.addEventListener("click", cb);
|
||||||
|
mark.addEventListener("touchstart", cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
mark.addEventListener("click", emitter);
|
||||||
|
mark.addEventListener("touchstart", emitter);
|
||||||
|
|
||||||
|
this.element.appendChild(mark);
|
||||||
|
|
||||||
|
this.marks[cfiRange] = { "element": mark, "listeners": [emitter, cb] };
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
unhighlight(cfiRange) {
|
||||||
|
let item;
|
||||||
|
if (cfiRange in this.highlights) {
|
||||||
|
item = this.highlights[cfiRange];
|
||||||
|
|
||||||
|
this.pane.removeMark(item.mark);
|
||||||
|
item.listeners.forEach((l) => {
|
||||||
|
if (l) { item.element.removeEventListener("click", l) };
|
||||||
|
});
|
||||||
|
delete this.highlights[cfiRange];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ununderline(cfiRange) {
|
||||||
|
let item;
|
||||||
|
if (cfiRange in this.underlines) {
|
||||||
|
item = this.underlines[cfiRange];
|
||||||
|
this.pane.removeMark(item.mark);
|
||||||
|
item.listeners.forEach((l) => {
|
||||||
|
if (l) { item.element.removeEventListener("click", l) };
|
||||||
|
});
|
||||||
|
delete this.underlines[cfiRange];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmark(cfiRange) {
|
||||||
|
let item;
|
||||||
|
if (cfiRange in this.marks) {
|
||||||
|
item = this.marks[cfiRange];
|
||||||
|
this.element.removeChild(item.element);
|
||||||
|
item.listeners.forEach((l) => {
|
||||||
|
if (l) { item.element.removeEventListener("click", l) };
|
||||||
|
});
|
||||||
|
delete this.marks[cfiRange];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
|
||||||
|
for (let cfiRange in this.highlights) {
|
||||||
|
this.unhighlight(cfiRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let cfiRange in this.underlines) {
|
||||||
|
this.ununderline(cfiRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let cfiRange in this.marks) {
|
||||||
|
this.unmark(cfiRange);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.displayed){
|
if(this.displayed){
|
||||||
this.displayed = false;
|
this.displayed = false;
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ class Rendition {
|
||||||
|
|
||||||
this.book = book;
|
this.book = book;
|
||||||
|
|
||||||
this.views = null;
|
// this.views = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds Hook methods to the Rendition prototype
|
* Adds Hook methods to the Rendition prototype
|
||||||
|
@ -329,13 +329,19 @@ class Rendition {
|
||||||
* @param {*} view
|
* @param {*} view
|
||||||
*/
|
*/
|
||||||
afterDisplayed(view){
|
afterDisplayed(view){
|
||||||
if (view.contents) {
|
|
||||||
this.hooks.content.trigger(view.contents, this).then(() => {
|
view.on("markClicked", (cfiRange, data) => this.triggerMarkEvent(cfiRange, data, view));
|
||||||
this.emit("rendered", view.section, view);
|
|
||||||
|
this.hooks.render.trigger(view, this)
|
||||||
|
.then(() => {
|
||||||
|
if (view.contents) {
|
||||||
|
this.hooks.content.trigger(view.contents, this).then(() => {
|
||||||
|
this.emit("rendered", view.section, view);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.emit("rendered", view.section, view);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
this.emit("rendered", view.section, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this.reportLocation();
|
// this.reportLocation();
|
||||||
}
|
}
|
||||||
|
@ -661,7 +667,7 @@ class Rendition {
|
||||||
|
|
||||||
this.book = undefined;
|
this.book = undefined;
|
||||||
|
|
||||||
this.views = null;
|
// this.views = null;
|
||||||
|
|
||||||
// this.hooks.display.clear();
|
// this.hooks.display.clear();
|
||||||
// this.hooks.serialize.clear();
|
// this.hooks.serialize.clear();
|
||||||
|
@ -683,7 +689,7 @@ class Rendition {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass the events from a view
|
* Pass the events from a view's Contents
|
||||||
* @private
|
* @private
|
||||||
* @param {View} view
|
* @param {View} view
|
||||||
*/
|
*/
|
||||||
|
@ -695,7 +701,6 @@ class Rendition {
|
||||||
});
|
});
|
||||||
|
|
||||||
contents.on("selected", (e) => this.triggerSelectedEvent(e, contents));
|
contents.on("selected", (e) => this.triggerSelectedEvent(e, contents));
|
||||||
contents.on("markClicked", (cfiRange, data) => this.triggerMarkEvent(cfiRange, data, contents));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -776,6 +781,10 @@ class Rendition {
|
||||||
return this.manager ? this.manager.getContents() : [];
|
return this.manager ? this.manager.getContents() : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
views () {
|
||||||
|
return this.manager ? this.manager.views : [];
|
||||||
|
}
|
||||||
|
|
||||||
handleLinks(contents) {
|
handleLinks(contents) {
|
||||||
if (contents) {
|
if (contents) {
|
||||||
contents.on("link", (href) => {
|
contents.on("link", (href) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue