1
0
Fork 0
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:
Fred Chasen 2017-03-30 19:36:33 -04:00
parent 6b01c94d0c
commit 00fd8c6b3b
8 changed files with 170 additions and 40 deletions

View file

@ -20,7 +20,7 @@
// Load the opf // Load the opf
var book = ePub("https://s3.amazonaws.com/epubjs/books/alice/OPS/package.opf"); var book = ePub("https://s3.amazonaws.com/epubjs/books/alice/OPS/package.opf");
var rendition = book.renderTo("viewer", { var rendition = book.renderTo("viewer", {
flow: "scrolled-doc", flow: "scrolled-doc"
}); });
rendition.display("chapter_008.xhtml"); rendition.display("chapter_008.xhtml");
@ -38,7 +38,9 @@
e.preventDefault(); e.preventDefault();
}, false); }, false);
rendition.on("locationChanged", function(location){
console.log(location);
});
rendition.on("rendered", function(section){ rendition.on("rendered", function(section){
var nextSection = section.next(); var nextSection = section.next();

View file

@ -18,7 +18,7 @@
<a id="next" href="#next" class="arrow"></a> <a id="next" href="#next" class="arrow"></a>
<script> <script>
var currentSectionIndex = 8; var currentSectionIndex = 0;
// Load the opf // Load the opf
var book = ePub("https://s3.amazonaws.com/moby-dick/moby-dick.epub"); var book = ePub("https://s3.amazonaws.com/moby-dick/moby-dick.epub");
var rendition = book.renderTo("viewer", { var rendition = book.renderTo("viewer", {
@ -26,7 +26,7 @@
height: 600 height: 600
}); });
rendition.display(); rendition.display(currentSectionIndex);
var title = document.getElementById("title"); var title = document.getElementById("title");

View file

@ -37,7 +37,15 @@ class Layout {
* @param {string} flow paginated | scrolled * @param {string} flow paginated | scrolled
*/ */
flow(flow) { 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;
} }
/** /**

View file

@ -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(){ onScroll(){
let scrollTop; let scrollTop;
let scrollLeft; let scrollLeft;

View file

@ -79,12 +79,37 @@ class DefaultViewManager {
} }
addEventListeners(){ addEventListeners(){
var scroller;
window.addEventListener("unload", function(e){ window.addEventListener("unload", function(e){
this.destroy(); this.destroy();
}.bind(this)); }.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(){ destroy(){
this.removeEventListeners();
this.views.each(function(view){ this.views.each(function(view){
view.destroy(); view.destroy();
}); });
@ -156,9 +181,7 @@ class DefaultViewManager {
} }
// Hide all current views // Hide all current views
this.views.hide(); this.clear();
this.views.clear();
this.add(section) this.add(section)
.then(function(view){ .then(function(view){
@ -222,7 +245,7 @@ class DefaultViewManager {
} }
} }
this.scrollTo(distX, distY); this.scrollTo(distX, distY, true);
} }
add(section){ add(section){
@ -281,9 +304,9 @@ class DefaultViewManager {
left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta; left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta;
if(left < this.container.scrollWidth) { 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) { } 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(); next = this.views.last().section.next();
} else { } else {
next = this.views.last().section.next(); next = this.views.last().section.next();
@ -293,12 +316,12 @@ class DefaultViewManager {
} }
if(next) { if(next) {
this.views.clear(); this.clear();
return this.append(next) return this.append(next)
.then(function(){ .then(function(){
var right; var right;
if (this.layout.name && this.layout.divisor > 1) { if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) {
right = next.next(); right = next.next();
if (right) { if (right) {
return this.append(right); return this.append(right);
@ -326,7 +349,7 @@ class DefaultViewManager {
left = this.container.scrollLeft; left = this.container.scrollLeft;
if(left > 0) { if(left > 0) {
this.scrollBy(-this.layout.delta, 0); this.scrollBy(-this.layout.delta, 0, true);
} else { } else {
prev = this.views.first().section.prev(); prev = this.views.first().section.prev();
} }
@ -339,12 +362,12 @@ class DefaultViewManager {
} }
if(prev) { if(prev) {
this.views.clear(); this.clear();
return this.prepend(prev) return this.prepend(prev)
.then(function(){ .then(function(){
var left; var left;
if (this.layout.name && this.layout.divisor > 1) { if (this.layout.name === "pre-paginated" && this.layout.divisor > 1) {
left = prev.prev(); left = prev.prev();
if (left) { if (left) {
return this.prepend(left); return this.prepend(left);
@ -353,7 +376,7 @@ class DefaultViewManager {
}.bind(this)) }.bind(this))
.then(function(){ .then(function(){
if(this.settings.axis === "horizontal") { 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(); this.views.show();
}.bind(this)); }.bind(this));
@ -369,6 +392,12 @@ class DefaultViewManager {
return null; return null;
} }
clear () {
this.views.hide();
this.scrollTo(0,0, true);
this.views.clear();
}
currentLocation(){ currentLocation(){
if (this.settings.axis === "vertical") { if (this.settings.axis === "vertical") {
@ -383,12 +412,21 @@ class DefaultViewManager {
var visible = this.visible(); var visible = this.visible();
var startPage, endPage; var startPage, endPage;
var startA, startB, endA, endB;
var last; 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) { 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 { return {
index : visible[0].section.index, index : visible[0].section.index,
href : visible[0].section.href, href : visible[0].section.href,
@ -399,8 +437,15 @@ class DefaultViewManager {
if(visible.length > 1) { if(visible.length > 1) {
last = 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 { return {
index : visible[last].section.index, index : visible[last].section.index,
@ -421,7 +466,7 @@ class DefaultViewManager {
if(visible.length === 1) { if(visible.length === 1) {
startA = container.left - visible[0].position().left; 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) pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA)
return { return {
@ -437,11 +482,11 @@ class DefaultViewManager {
// Left Col // Left Col
startA = container.left - visible[0].position().left; startA = container.left - visible[0].position().left;
endA = startA + this.layout.columnWidth; endA = startA + this.layout.columnWidth + this.layout.gap / 2;
// Right Col // Right Col
startB = container.left + this.layout.spreadWidth - visible[visible.length-1].position().left; startB = container.left + this.layout.spreadWidth - visible[last].position().left;
endB = startB + this.layout.columnWidth; endB = startB + this.layout.columnWidth + this.layout.gap / 2;
pageLeft = this.mapping.page(visible[0].contents, visible[0].section.cfiBase, startA, endA); 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); pageRight = this.mapping.page(visible[last].contents, visible[last].section.cfiBase, startB, endB);
@ -534,6 +579,40 @@ class DefaultViewManager {
} }
onScroll(){ 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;
}
} }

View file

@ -1,8 +1,10 @@
import EpubCFI from "./epubcfi"; import EpubCFI from "./epubcfi";
class Mapping { class Mapping {
constructor(layout) { constructor(layout, dev) {
this.layout = layout; this.layout = layout;
this.horizontal = (this.layout.flow() === "paginated") ? true : false;
this._dev = dev;
} }
section(view) { section(view) {
@ -14,15 +16,31 @@ class Mapping {
page(contents, cfiBase, start, end) { page(contents, cfiBase, start, end) {
var root = contents && contents.document ? contents.document.body : false; var root = contents && contents.document ? contents.document.body : false;
var result;
if (!root) { if (!root) {
return; return;
} }
return this.rangePairToCfiPair(cfiBase, { result = this.rangePairToCfiPair(cfiBase, {
start: this.findStart(root, start, end), start: this.findStart(root, start, end),
end: this.findEnd(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) { walk(root, func) {
@ -71,11 +89,12 @@ class Mapping {
var $el; var $el;
var found; var found;
var $prev = root; var $prev = root;
while (stack.length) { while (stack.length) {
$el = stack.shift(); $el = stack.shift();
found = this.walk($el, function(node){ found = this.walk($el, (node) => {
var left, right; var left, right;
var elPos; var elPos;
var elRange; var elRange;
@ -89,8 +108,8 @@ class Mapping {
elPos = node.getBoundingClientRect(); elPos = node.getBoundingClientRect();
} }
left = elPos.left; left = this.horizontal ? elPos.left : elPos.top;
right = elPos.right; right = this.horizontal ? elPos.right : elPos.bottom;
if( left >= start && left <= end ) { if( left >= start && left <= end ) {
return node; return node;
@ -123,7 +142,7 @@ class Mapping {
$el = stack.shift(); $el = stack.shift();
found = this.walk($el, function(node){ found = this.walk($el, (node) => {
var left, right; var left, right;
var elPos; var elPos;
@ -138,8 +157,8 @@ class Mapping {
elPos = node.getBoundingClientRect(); elPos = node.getBoundingClientRect();
} }
left = elPos.left; left = this.horizontal ? elPos.left : elPos.top;
right = elPos.right; right = this.horizontal ? elPos.right : elPos.bottom;
if(left > end && $prev) { if(left > end && $prev) {
return $prev; return $prev;
@ -168,13 +187,15 @@ class Mapping {
var ranges = this.splitTextNodeIntoRanges(node); var ranges = this.splitTextNodeIntoRanges(node);
var range; var range;
var pos; var pos;
var left;
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
range = ranges[i]; range = ranges[i];
pos = range.getBoundingClientRect(); pos = range.getBoundingClientRect();
left = this.horizontal ? pos.left : pos.top;
if( pos.left >= start ) { if( left >= start ) {
return range; return range;
} }
@ -190,15 +211,18 @@ class Mapping {
var prev; var prev;
var range; var range;
var pos; var pos;
var left, right;
for (var i = 0; i < ranges.length; i++) { for (var i = 0; i < ranges.length; i++) {
range = ranges[i]; range = ranges[i];
pos = range.getBoundingClientRect(); 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; return prev;
} else if(pos.right > end) { } else if(right > end) {
return range; return range;
} }
@ -264,10 +288,8 @@ class Mapping {
var endRange = rangePair.end; var endRange = rangePair.end;
startRange.collapse(true); 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 startCfi = new EpubCFI(startRange, cfiBase).toString();
let endCfi = new EpubCFI(endRange, cfiBase).toString(); let endCfi = new EpubCFI(endRange, cfiBase).toString();

View file

@ -176,7 +176,7 @@ class Rendition {
this.manager.on("resized", this.onResized.bind(this)); this.manager.on("resized", this.onResized.bind(this));
// Listen for scroll changes // 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 // Trigger that rendering has started
this.emit("started"); this.emit("started");

View file

@ -63,11 +63,17 @@ class Themes {
registerUrl (name, input) { registerUrl (name, input) {
var url = new Url(input); var url = new Url(input);
this._themes[name] = { "url": url.toString() }; this._themes[name] = { "url": url.toString() };
if (this._injected[name]) {
this.update(name);
}
} }
registerRules (name, rules) { registerRules (name, rules) {
this._themes[name] = { "rules": rules }; this._themes[name] = { "rules": rules };
// TODO: serialize css rules // TODO: serialize css rules
if (this._injected[name]) {
this.update(name);
}
} }
apply (name) { apply (name) {
@ -102,6 +108,7 @@ class Themes {
if(theme.rules || (theme.url && links.indexOf(theme.url) === -1)) { if(theme.rules || (theme.url && links.indexOf(theme.url) === -1)) {
this.add(name, contents); this.add(name, contents);
} }
this._injected.push(name);
} }
} }