1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-03 14:59:18 +02:00

Respect linear in spine

This commit is contained in:
Fred Chasen 2017-06-28 20:40:55 -04:00
parent fd9510f190
commit 101af4f0f4
9 changed files with 125 additions and 35 deletions

View file

@ -25,16 +25,16 @@
var currentPage = document.getElementById("current-percent"); var currentPage = document.getElementById("current-percent");
var slider = document.createElement("input"); var slider = document.createElement("input");
var slide = function(){ var slide = function(){
var cfi = book.locations.cfiFromPercentage(slider.value); var cfi = book.locations.cfiFromPercentage(slider.value / 100);
rendition.display(cfi); rendition.display(cfi);
}; };
var mouseDown = false; var mouseDown = false;
// Load the opf // Load the opf
var book = ePub("../test/fixtures/alice/OPS/package.opf"); var book = ePub("https://s3.amazonaws.com/moby-dick/moby-dick.epub");
var rendition = book.renderTo("viewer", { var rendition = book.renderTo("viewer", {
width: "100%", width: "100%",
height: 500 height: 600
}); });
var displayed = rendition.display(); var displayed = rendition.display();
@ -109,7 +109,7 @@
// Get the current CFI // Get the current CFI
var currentLocation = rendition.currentLocation(); var currentLocation = rendition.currentLocation();
// Get the Percentage (or location) from that CFI // Get the Percentage (or location) from that CFI
var currentPage = book.locations.percentageFromCfi(currentLocation); var currentPage = book.locations.percentageFromCfi(currentLocation.start);
slider.value = currentPage; slider.value = currentPage;
currentPage.value = currentPage; currentPage.value = currentPage;
}); });
@ -123,7 +123,7 @@
// Listen for location changed event, get percentage from CFI // Listen for location changed event, get percentage from CFI
rendition.on('locationChanged', function(location){ rendition.on('locationChanged', function(location){
var percent = book.locations.percentageFromCfi(location); var percent = book.locations.percentageFromCfi(location.start);
var percentage = Math.floor(percent * 100); var percentage = Math.floor(percent * 100);
if(!mouseDown) { if(!mouseDown) {
slider.value = percentage; slider.value = percentage;

View file

@ -73,7 +73,7 @@
"dependencies": { "dependencies": {
"event-emitter": "^0.3.4", "event-emitter": "^0.3.4",
"jszip": "^3.1.3", "jszip": "^3.1.3",
"marks-pane": "^1.0.0", "marks-pane": "^1.0.1",
"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"

View file

@ -1,4 +1,4 @@
import {extend, type, findChildren, RangeObject} from "./utils/core"; import {extend, type, findChildren, RangeObject, isNumber} from "./utils/core";
/** /**
EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html
@ -193,10 +193,14 @@ class EpubCFI {
var assertion = termialStr.match(/\[(.*)\]/); var assertion = termialStr.match(/\[(.*)\]/);
if(assertion && assertion[1]){ if(assertion && assertion[1]){
characterOffset = parseInt(termialStr.split("[")[0]) || null; characterOffset = parseInt(termialStr.split("[")[0]);
textLocationAssertion = assertion[1]; textLocationAssertion = assertion[1];
} else { } else {
characterOffset = parseInt(termialStr) || null; characterOffset = parseInt(termialStr);
}
if (!isNumber(characterOffset)) {
characterOffset = null;
} }
return { return {
@ -294,12 +298,12 @@ class EpubCFI {
cfiString += this.segmentString(this.path); cfiString += this.segmentString(this.path);
// Add Range, if present // Add Range, if present
if(this.start) { if(this.range && this.start) {
cfiString += ","; cfiString += ",";
cfiString += this.segmentString(this.start); cfiString += this.segmentString(this.start);
} }
if(this.end) { if(this.range && this.end) {
cfiString += ","; cfiString += ",";
cfiString += this.segmentString(this.end); cfiString += this.segmentString(this.end);
} }
@ -313,6 +317,11 @@ class EpubCFI {
var stepsA, stepsB; var stepsA, stepsB;
var terminalA, terminalB; var terminalA, terminalB;
var rangeAStartSteps, rangeAEndSteps;
var rangeBEndSteps, rangeBEndSteps;
var rangeAStartTerminal, rangeAEndTerminal;
var rangeBStartTerminal, rangeBEndTerminal;
if(typeof cfiOne === "string") { if(typeof cfiOne === "string") {
cfiOne = new EpubCFI(cfiOne); cfiOne = new EpubCFI(cfiOne);
} }
@ -968,6 +977,23 @@ class EpubCFI {
return cfi; return cfi;
} }
collapse(toStart) {
if (!this.range) {
return;
}
this.range = false;
if (toStart) {
this.path.steps = this.path.steps.concat(this.start.steps);
this.path.terminal = this.start.terminal;
} else {
this.path.steps = this.path.steps.concat(this.end.steps);
this.path.terminal = this.end.terminal;
}
}
} }
export default EpubCFI; export default EpubCFI;

View file

@ -43,13 +43,13 @@ class Locations {
this.q.pause(); this.q.pause();
this.spine.each(function(section) { this.spine.each(function(section) {
if (section.linear) {
this.q.enqueue(this.process.bind(this), section); this.q.enqueue(this.process.bind(this), section);
}
}.bind(this)); }.bind(this));
return this.q.run().then(function() { return this.q.run().then(function() {
this.total = this._locations.length-1; this.total = this._locations.length - 1;
if (this._currentCfi) { if (this._currentCfi) {
this.currentLocation = this._currentCfi; this.currentLocation = this._currentCfi;
@ -164,11 +164,22 @@ class Locations {
} }
locationFromCfi(cfi){ locationFromCfi(cfi){
let loc;
if (EpubCFI.prototype.isCfiString(cfi)) {
cfi = new EpubCFI(cfi);
}
// Check if the location has not been set yet // Check if the location has not been set yet
if(this._locations.length === 0) { if(this._locations.length === 0) {
return -1; return -1;
} }
return locationOf(cfi.start, this._locations, this.epubcfi.compare);
loc = locationOf(cfi, this._locations, this.epubcfi.compare);
if (loc > this.total) {
return this.total;
}
return loc;
} }
percentageFromCfi(cfi) { percentageFromCfi(cfi) {
@ -185,6 +196,7 @@ class Locations {
if (!loc || !this.total) { if (!loc || !this.total) {
return 0; return 0;
} }
return (loc / this.total); return (loc / this.total);
} }
@ -202,16 +214,26 @@ class Locations {
return cfi; return cfi;
} }
cfiFromPercentage(value){ cfiFromPercentage(percentage){
var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1 let loc;
var loc = Math.ceil(this.total * percentage); if (percentage > 1) {
console.warn("Normalize cfiFromPercentage value to between 0 - 1");
}
// Make sure 1 goes to very end
if (percentage >= 1) {
let cfi = new EpubCFI(this._locations[this.total]);
cfi.collapse();
return cfi.toString();
}
loc = Math.ceil(this.total * percentage);
return this.cfiFromLocation(loc); return this.cfiFromLocation(loc);
} }
load(locations){ load(locations){
this._locations = JSON.parse(locations); this._locations = JSON.parse(locations);
this.total = this._locations.length-1; this.total = this._locations.length - 1;
return this._locations; return this._locations;
} }

View file

@ -544,8 +544,8 @@ class IframeView {
var targetPos = this.contents.locationOf(target, this.settings.ignoreClass); var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
return { return {
"left": window.scrollX + parentPos.left + targetPos.left, "left": window.scrollX + targetPos.left,
"top": window.scrollY + parentPos.top + targetPos.top "top": window.scrollY + targetPos.top
}; };
} }

View file

@ -244,8 +244,11 @@ class Rendition {
var moveTo; var moveTo;
// Check if this is a book percentage // Check if this is a book percentage
if (this.book.locations.length && isFloat(target)) { if (this.book.locations.length &&
target = this.book.locations.cfiFromPercentage(target); (isFloat(target) ||
(typeof target === "string" && target == parseFloat(target))) // Handle 1.0
) {
target = this.book.locations.cfiFromPercentage(parseFloat(target));
} }
section = this.book.spine.get(target); section = this.book.spine.get(target);
@ -487,7 +490,7 @@ class Rendition {
location.then(function(result) { location.then(function(result) {
this.location = result; this.location = result;
this.percentage = this.book.locations.percentageFromCfi(result); this.percentage = this.book.locations.percentageFromCfi(result.start);
if (this.percentage != null) { if (this.percentage != null) {
this.location.percentage = this.percentage; this.location.percentage = this.percentage;
} }
@ -496,7 +499,7 @@ class Rendition {
}.bind(this)); }.bind(this));
} else if (location) { } else if (location) {
this.location = location; this.location = location;
this.percentage = this.book.locations.percentageFromCfi(location); this.percentage = this.book.locations.percentageFromCfi(location.start);
if (this.percentage != null) { if (this.percentage != null) {
this.location.percentage = this.percentage; this.location.percentage = this.percentage;
} }
@ -515,14 +518,14 @@ class Rendition {
var location = this.manager.currentLocation(); var location = this.manager.currentLocation();
if (location && location.then && typeof location.then === "function") { if (location && location.then && typeof location.then === "function") {
location.then(function(result) { location.then(function(result) {
var percentage = this.book.locations.percentageFromCfi(result); var percentage = this.book.locations.percentageFromCfi(result.start);
if (percentage != null) { if (percentage != null) {
result.percentage = percentage; result.percentage = percentage;
} }
return result; return result;
}.bind(this)); }.bind(this));
} else if (location) { } else if (location) {
var percentage = this.book.locations.percentageFromCfi(location); var percentage = this.book.locations.percentageFromCfi(location.start);
if (percentage != null) { if (percentage != null) {
location.percentage = percentage; location.percentage = percentage;
} }

View file

@ -13,7 +13,7 @@ import { replaceBase } from "./utils/replacements";
class Section { class Section {
constructor(item, hooks){ constructor(item, hooks){
this.idref = item.idref; this.idref = item.idref;
this.linear = item.linear; this.linear = item.linear === "yes";
this.properties = item.properties; this.properties = item.properties;
this.index = item.index; this.index = item.index;
this.href = item.href; this.href = item.href;

View file

@ -48,6 +48,7 @@ class Spine {
var manifestItem = this.manifest[item.idref]; var manifestItem = this.manifest[item.idref];
var spineItem; var spineItem;
item.index = index;
item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref); item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);
if (item.href) { if (item.href) {
@ -62,8 +63,39 @@ class Spine {
} }
} }
item.prev = function(){ return this.get(index-1); }.bind(this); if (item.linear === "yes") {
item.next = function(){ return this.get(index+1); }.bind(this); item.prev = function() {
let prevIndex = item.index;
while (prevIndex > 0) {
let prev = this.get(prevIndex-1);
if (prev && prev.linear) {
return prev;
}
prevIndex -= 1;
}
return;
}.bind(this);
item.next = function() {
let nextIndex = item.index;
while (nextIndex < this.spineItems.length-1) {
let next = this.get(nextIndex+1);
if (next && next.linear) {
return next;
}
nextIndex += 1;
}
return;
}.bind(this);
} else {
item.prev = function() {
return;
}
item.next = function() {
return;
}
}
spineItem = new Section(item, this.hooks); spineItem = new Section(item, this.hooks);
@ -87,10 +119,18 @@ class Spine {
get(target) { get(target) {
var index = 0; var index = 0;
if(this.epubcfi.isCfiString(target)) { if (typeof target === "undefined") {
while (index < this.spineItems.length) {
let next = this.spineItems[index];
if (next && next.linear) {
break;
}
index += 1;
}
} else if(this.epubcfi.isCfiString(target)) {
let cfi = new EpubCFI(target); let cfi = new EpubCFI(target);
index = cfi.spinePos; index = cfi.spinePos;
} else if(target && (typeof target === "number" || isNaN(target) === false)){ } else if(typeof target === "number" || isNaN(target) === false){
index = target; index = target;
} else if(target && target.indexOf("#") === 0) { } else if(target && target.indexOf("#") === 0) {
index = this.spineById[target.substring(1)]; index = this.spineById[target.substring(1)];

View file

@ -105,9 +105,8 @@ export function locationOf(item, array, compareFunction, _start, _end) {
compared = compareFunction(array[pivot], item); compared = compareFunction(array[pivot], item);
if(end-start === 1) { if(end-start === 1) {
return compared > 0 ? pivot : pivot + 1; return compared >= 0 ? pivot : pivot + 1;
} }
if(compared === 0) { if(compared === 0) {
return pivot; return pivot;
} }