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:
parent
fd9510f190
commit
101af4f0f4
9 changed files with 125 additions and 35 deletions
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
48
src/spine.js
48
src/spine.js
|
@ -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)];
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue