mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
fixes scrolled location reporting
This commit is contained in:
parent
6b01c94d0c
commit
00fd8c6b3b
8 changed files with 170 additions and 40 deletions
|
@ -20,7 +20,7 @@
|
|||
// Load the opf
|
||||
var book = ePub("https://s3.amazonaws.com/epubjs/books/alice/OPS/package.opf");
|
||||
var rendition = book.renderTo("viewer", {
|
||||
flow: "scrolled-doc",
|
||||
flow: "scrolled-doc"
|
||||
});
|
||||
|
||||
rendition.display("chapter_008.xhtml");
|
||||
|
@ -38,7 +38,9 @@
|
|||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
|
||||
rendition.on("locationChanged", function(location){
|
||||
console.log(location);
|
||||
});
|
||||
|
||||
rendition.on("rendered", function(section){
|
||||
var nextSection = section.next();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<a id="next" href="#next" class="arrow">›</a>
|
||||
|
||||
<script>
|
||||
var currentSectionIndex = 8;
|
||||
var currentSectionIndex = 0;
|
||||
// Load the opf
|
||||
var book = ePub("https://s3.amazonaws.com/moby-dick/moby-dick.epub");
|
||||
var rendition = book.renderTo("viewer", {
|
||||
|
@ -26,7 +26,7 @@
|
|||
height: 600
|
||||
});
|
||||
|
||||
rendition.display();
|
||||
rendition.display(currentSectionIndex);
|
||||
|
||||
var title = document.getElementById("title");
|
||||
|
||||
|
|
|
@ -37,7 +37,15 @@ class Layout {
|
|||
* @param {string} flow paginated | scrolled
|
||||
*/
|
||||
flow(flow) {
|
||||
this._flow = (flow === "paginated") ? "paginated" : "scrolled";
|
||||
if (typeof(flow) != "undefined") {
|
||||
if (flow === "scrolled-continuous" ||
|
||||
flow === "scrolled-doc") {
|
||||
this._flow = "scrolled";
|
||||
} else {
|
||||
this._flow = "paginated";
|
||||
}
|
||||
}
|
||||
return this._flow;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -408,6 +408,18 @@ class ContinuousViewManager extends DefaultViewManager {
|
|||
|
||||
}
|
||||
|
||||
removeEventListeners(){
|
||||
var scroller;
|
||||
|
||||
if(this.settings.height) {
|
||||
scroller = this.container;
|
||||
} else {
|
||||
scroller = window;
|
||||
}
|
||||
|
||||
scroller.removeEventListener("scroll", this.onScroll.bind(this));
|
||||
}
|
||||
|
||||
onScroll(){
|
||||
let scrollTop;
|
||||
let scrollLeft;
|
||||
|
|
|
@ -79,12 +79,37 @@ class DefaultViewManager {
|
|||
}
|
||||
|
||||
addEventListeners(){
|
||||
var scroller;
|
||||
|
||||
window.addEventListener("unload", function(e){
|
||||
this.destroy();
|
||||
}.bind(this));
|
||||
|
||||
if(this.settings.height) {
|
||||
scroller = this.container;
|
||||
} else {
|
||||
scroller = window;
|
||||
}
|
||||
|
||||
scroller.addEventListener("scroll", this.onScroll.bind(this));
|
||||
}
|
||||
|
||||
removeEventListeners(){
|
||||
var scroller;
|
||||
|
||||
if(this.settings.height) {
|
||||
scroller = this.container;
|
||||
} else {
|
||||
scroller = window;
|
||||
}
|
||||
|
||||
scroller.removeEventListener("scroll", this.onScroll.bind(this));
|
||||
}
|
||||
|
||||
destroy(){
|
||||
|
||||
this.removeEventListeners();
|
||||
|
||||
this.views.each(function(view){
|
||||
view.destroy();
|
||||
});
|
||||
|
@ -156,9 +181,7 @@ class DefaultViewManager {
|
|||
}
|
||||
|
||||
// Hide all current views
|
||||
this.views.hide();
|
||||
|
||||
this.views.clear();
|
||||
this.clear();
|
||||
|
||||
this.add(section)
|
||||
.then(function(view){
|
||||
|
@ -222,7 +245,7 @@ class DefaultViewManager {
|
|||
}
|
||||
}
|
||||
|
||||
this.scrollTo(distX, distY);
|
||||
this.scrollTo(distX, distY, true);
|
||||
}
|
||||
|
||||
add(section){
|
||||
|
@ -281,9 +304,9 @@ class DefaultViewManager {
|
|||
left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta;
|
||||
|
||||
if(left < this.container.scrollWidth) {
|
||||
this.scrollBy(this.layout.delta, 0);
|
||||
this.scrollBy(this.layout.delta, 0, true);
|
||||
} else if (left - this.layout.columnWidth === this.container.scrollWidth) {
|
||||
this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
|
||||
this.scrollTo(this.container.scrollWidth - this.layout.delta, 0, true);
|
||||
next = this.views.last().section.next();
|
||||
} else {
|
||||
next = this.views.last().section.next();
|
||||
|
@ -293,12 +316,12 @@ class DefaultViewManager {
|
|||
}
|
||||
|
||||
if(next) {
|
||||
this.views.clear();
|
||||
this.clear();
|
||||
|
||||
return this.append(next)
|
||||
.then(function(){
|
||||
var right;
|
||||
if (this.layout.name && this.layout.divisor > 1) {
|
||||
if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) {
|
||||
right = next.next();
|
||||
if (right) {
|
||||
return this.append(right);
|
||||
|
@ -326,7 +349,7 @@ class DefaultViewManager {
|
|||
left = this.container.scrollLeft;
|
||||
|
||||
if(left > 0) {
|
||||
this.scrollBy(-this.layout.delta, 0);
|
||||
this.scrollBy(-this.layout.delta, 0, true);
|
||||
} else {
|
||||
prev = this.views.first().section.prev();
|
||||
}
|
||||
|
@ -339,12 +362,12 @@ class DefaultViewManager {
|
|||
}
|
||||
|
||||
if(prev) {
|
||||
this.views.clear();
|
||||
this.clear();
|
||||
|
||||
return this.prepend(prev)
|
||||
.then(function(){
|
||||
var left;
|
||||
if (this.layout.name && this.layout.divisor > 1) {
|
||||
if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) {
|
||||
left = prev.prev();
|
||||
if (left) {
|
||||
return this.prepend(left);
|
||||
|
@ -353,7 +376,7 @@ class DefaultViewManager {
|
|||
}.bind(this))
|
||||
.then(function(){
|
||||
if(this.settings.axis === "horizontal") {
|
||||
this.scrollTo(this.container.scrollWidth - this.layout.delta, 0);
|
||||
this.scrollTo(this.container.scrollWidth - this.layout.delta, 0, true);
|
||||
}
|
||||
this.views.show();
|
||||
}.bind(this));
|
||||
|
@ -369,6 +392,12 @@ class DefaultViewManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
clear () {
|
||||
this.views.hide();
|
||||
this.scrollTo(0,0, true);
|
||||
this.views.clear();
|
||||
}
|
||||
|
||||
currentLocation(){
|
||||
|
||||
if (this.settings.axis === "vertical") {
|
||||
|
@ -383,12 +412,21 @@ class DefaultViewManager {
|
|||
|
||||
var visible = this.visible();
|
||||
var startPage, endPage;
|
||||
var startA, startB, endA, endB;
|
||||
var last;
|
||||
var container = this.container.getBoundingClientRect();
|
||||
var pageHeight = (container.height < window.innerHeight) ? container.height : window.innerHeight;
|
||||
var offset = 0;
|
||||
|
||||
// var container = this.container.getBoundingClientRect();
|
||||
if(!this.settings.height) {
|
||||
offset = window.scrollY;
|
||||
}
|
||||
|
||||
if(visible.length === 1) {
|
||||
startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase);
|
||||
startA = (container.top - visible[0].position().top) + offset;
|
||||
endA = startA + pageHeight;
|
||||
startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA)
|
||||
|
||||
return {
|
||||
index : visible[0].section.index,
|
||||
href : visible[0].section.href,
|
||||
|
@ -399,8 +437,15 @@ class DefaultViewManager {
|
|||
|
||||
if(visible.length > 1) {
|
||||
last = visible.length - 1;
|
||||
startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase);
|
||||
endPage = this.mapping.page(visible[last].contents, visible[last].section.cfiBase);
|
||||
|
||||
startA = (container.top - visible[0].position().top) + offset;
|
||||
endA = startA + (container.top - visible[0].position().bottom);
|
||||
|
||||
startB = (container.top - visible[last].position().top) + offset;
|
||||
endB = startB + pageHeight;
|
||||
|
||||
startPage = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA)
|
||||
endPage = this.mapping.page(visible[last].contents, visible[last].section.cfiBase, startB, endB);
|
||||
|
||||
return {
|
||||
index : visible[last].section.index,
|
||||
|
@ -421,7 +466,7 @@ class DefaultViewManager {
|
|||
|
||||
if(visible.length === 1) {
|
||||
startA = container.left - visible[0].position().left;
|
||||
endA = startA + this.layout.spreadWidth;
|
||||
endA = startA + this.layout.spreadWidth + this.layout.gap;
|
||||
|
||||
pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA)
|
||||
return {
|
||||
|
@ -437,11 +482,11 @@ class DefaultViewManager {
|
|||
|
||||
// Left Col
|
||||
startA = container.left - visible[0].position().left;
|
||||
endA = startA + this.layout.columnWidth;
|
||||
endA = startA + this.layout.columnWidth + this.layout.gap / 2;
|
||||
|
||||
// Right Col
|
||||
startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left;
|
||||
endB = startB + this.layout.columnWidth;
|
||||
startB = container.left + this.layout.spreadWidth - visible[last].position().left;
|
||||
endB = startB + this.layout.columnWidth + this.layout.gap / 2;
|
||||
|
||||
pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA);
|
||||
pageRight = this.mapping.page(visible[last].contents, visible[last].section.cfiBase, startB, endB);
|
||||
|
@ -534,6 +579,40 @@ class DefaultViewManager {
|
|||
}
|
||||
|
||||
onScroll(){
|
||||
let scrollTop;
|
||||
let scrollLeft;
|
||||
|
||||
if(this.settings.height) {
|
||||
scrollTop = this.container.scrollTop;
|
||||
scrollLeft = this.container.scrollLeft;
|
||||
} else {
|
||||
scrollTop = window.scrollY;
|
||||
scrollLeft = window.scrollX;
|
||||
}
|
||||
|
||||
this.scrollTop = scrollTop;
|
||||
this.scrollLeft = scrollLeft;
|
||||
|
||||
if(!this.ignore) {
|
||||
console.log("scroll", scrollLeft, scrollTop);
|
||||
this.emit("scroll", {
|
||||
top: scrollTop,
|
||||
left: scrollLeft
|
||||
});
|
||||
|
||||
clearTimeout(this.afterScrolled);
|
||||
this.afterScrolled = setTimeout(function () {
|
||||
this.emit("scrolled", {
|
||||
top: this.scrollTop,
|
||||
left: this.scrollLeft
|
||||
});
|
||||
}.bind(this), 20);
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
this.ignore = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import EpubCFI from "./epubcfi";
|
||||
|
||||
class Mapping {
|
||||
constructor(layout) {
|
||||
constructor(layout, dev) {
|
||||
this.layout = layout;
|
||||
this.horizontal = (this.layout.flow() === "paginated") ? true : false;
|
||||
this._dev = dev;
|
||||
}
|
||||
|
||||
section(view) {
|
||||
|
@ -14,15 +16,31 @@ class Mapping {
|
|||
|
||||
page(contents, cfiBase, start, end) {
|
||||
var root = contents && contents.document ? contents.document.body : false;
|
||||
var result;
|
||||
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.rangePairToCfiPair(cfiBase, {
|
||||
result = this.rangePairToCfiPair(cfiBase, {
|
||||
start: this.findStart(root, start, end),
|
||||
end: this.findEnd(root, start, end)
|
||||
});
|
||||
|
||||
if (this._dev === true) {
|
||||
let doc = contents.document;
|
||||
let startRange = new EpubCFI(result.start).toRange(doc);
|
||||
let endRange = new EpubCFI(result.end).toRange(doc);
|
||||
|
||||
let selection = doc.defaultView.getSelection();
|
||||
let r = doc.createRange();
|
||||
selection.removeAllRanges();
|
||||
r.setStart(startRange.startContainer, startRange.startOffset);
|
||||
r.setEnd(endRange.endContainer, endRange.endOffset);
|
||||
selection.addRange(r);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
walk(root, func) {
|
||||
|
@ -71,11 +89,12 @@ class Mapping {
|
|||
var $el;
|
||||
var found;
|
||||
var $prev = root;
|
||||
|
||||
while (stack.length) {
|
||||
|
||||
$el = stack.shift();
|
||||
|
||||
found = this.walk($el, function(node){
|
||||
found = this.walk($el, (node) => {
|
||||
var left, right;
|
||||
var elPos;
|
||||
var elRange;
|
||||
|
@ -89,8 +108,8 @@ class Mapping {
|
|||
elPos = node.getBoundingClientRect();
|
||||
}
|
||||
|
||||
left = elPos.left;
|
||||
right = elPos.right;
|
||||
left = this.horizontal ? elPos.left : elPos.top;
|
||||
right = this.horizontal ? elPos.right : elPos.bottom;
|
||||
|
||||
if( left >= start && left <= end ) {
|
||||
return node;
|
||||
|
@ -123,7 +142,7 @@ class Mapping {
|
|||
|
||||
$el = stack.shift();
|
||||
|
||||
found = this.walk($el, function(node){
|
||||
found = this.walk($el, (node) => {
|
||||
|
||||
var left, right;
|
||||
var elPos;
|
||||
|
@ -138,8 +157,8 @@ class Mapping {
|
|||
elPos = node.getBoundingClientRect();
|
||||
}
|
||||
|
||||
left = elPos.left;
|
||||
right = elPos.right;
|
||||
left = this.horizontal ? elPos.left : elPos.top;
|
||||
right = this.horizontal ? elPos.right : elPos.bottom;
|
||||
|
||||
if(left > end && $prev) {
|
||||
return $prev;
|
||||
|
@ -168,13 +187,15 @@ class Mapping {
|
|||
var ranges = this.splitTextNodeIntoRanges(node);
|
||||
var range;
|
||||
var pos;
|
||||
var left;
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
range = ranges[i];
|
||||
|
||||
pos = range.getBoundingClientRect();
|
||||
left = this.horizontal ? pos.left : pos.top;
|
||||
|
||||
if( pos.left >= start ) {
|
||||
if( left >= start ) {
|
||||
return range;
|
||||
}
|
||||
|
||||
|
@ -190,15 +211,18 @@ class Mapping {
|
|||
var prev;
|
||||
var range;
|
||||
var pos;
|
||||
var left, right;
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
range = ranges[i];
|
||||
|
||||
pos = range.getBoundingClientRect();
|
||||
left = this.horizontal ? pos.left : pos.top;
|
||||
right = this.horizontal ? pos.right : pos.bottom;
|
||||
|
||||
if(pos.left > end && prev) {
|
||||
if(left > end && prev) {
|
||||
return prev;
|
||||
} else if(pos.right > end) {
|
||||
} else if(right > end) {
|
||||
return range;
|
||||
}
|
||||
|
||||
|
@ -264,10 +288,8 @@ class Mapping {
|
|||
var endRange = rangePair.end;
|
||||
|
||||
startRange.collapse(true);
|
||||
endRange.collapse(true);
|
||||
endRange.collapse(false);
|
||||
|
||||
// startCfi = section.cfiFromRange(startRange);
|
||||
// endCfi = section.cfiFromRange(endRange);
|
||||
let startCfi = new EpubCFI(startRange, cfiBase).toString();
|
||||
let endCfi = new EpubCFI(endRange, cfiBase).toString();
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ class Rendition {
|
|||
this.manager.on("resized", this.onResized.bind(this));
|
||||
|
||||
// Listen for scroll changes
|
||||
this.manager.on("scroll", this.reportLocation.bind(this));
|
||||
this.manager.on("scrolled", this.reportLocation.bind(this));
|
||||
|
||||
// Trigger that rendering has started
|
||||
this.emit("started");
|
||||
|
|
|
@ -63,11 +63,17 @@ class Themes {
|
|||
registerUrl (name, input) {
|
||||
var url = new Url(input);
|
||||
this._themes[name] = { "url": url.toString() };
|
||||
if (this._injected[name]) {
|
||||
this.update(name);
|
||||
}
|
||||
}
|
||||
|
||||
registerRules (name, rules) {
|
||||
this._themes[name] = { "rules": rules };
|
||||
// TODO: serialize css rules
|
||||
if (this._injected[name]) {
|
||||
this.update(name);
|
||||
}
|
||||
}
|
||||
|
||||
apply (name) {
|
||||
|
@ -102,6 +108,7 @@ class Themes {
|
|||
if(theme.rules || (theme.url && links.indexOf(theme.url) === -1)) {
|
||||
this.add(name, contents);
|
||||
}
|
||||
this._injected.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue