diff --git a/examples/locations.html b/examples/locations.html
index 826d0f9..c23d1ae 100644
--- a/examples/locations.html
+++ b/examples/locations.html
@@ -25,16 +25,16 @@
var currentPage = document.getElementById("current-percent");
var slider = document.createElement("input");
var slide = function(){
- var cfi = book.locations.cfiFromPercentage(slider.value);
+ var cfi = book.locations.cfiFromPercentage(slider.value / 100);
rendition.display(cfi);
};
var mouseDown = false;
// 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", {
width: "100%",
- height: 500
+ height: 600
});
var displayed = rendition.display();
@@ -109,7 +109,7 @@
// Get the current CFI
var currentLocation = rendition.currentLocation();
// Get the Percentage (or location) from that CFI
- var currentPage = book.locations.percentageFromCfi(currentLocation);
+ var currentPage = book.locations.percentageFromCfi(currentLocation.start);
slider.value = currentPage;
currentPage.value = currentPage;
});
@@ -123,7 +123,7 @@
// Listen for location changed event, get percentage from CFI
rendition.on('locationChanged', function(location){
- var percent = book.locations.percentageFromCfi(location);
+ var percent = book.locations.percentageFromCfi(location.start);
var percentage = Math.floor(percent * 100);
if(!mouseDown) {
slider.value = percentage;
diff --git a/package.json b/package.json
index 6b8df10..2e3e98f 100644
--- a/package.json
+++ b/package.json
@@ -73,7 +73,7 @@
"dependencies": {
"event-emitter": "^0.3.4",
"jszip": "^3.1.3",
- "marks-pane": "^1.0.0",
+ "marks-pane": "^1.0.1",
"path-webpack": "^0.0.3",
"stream-browserify": "^2.0.1",
"xmldom": "0.1.27"
diff --git a/src/epubcfi.js b/src/epubcfi.js
index fb5e538..23d63f1 100644
--- a/src/epubcfi.js
+++ b/src/epubcfi.js
@@ -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
@@ -193,10 +193,14 @@ class EpubCFI {
var assertion = termialStr.match(/\[(.*)\]/);
if(assertion && assertion[1]){
- characterOffset = parseInt(termialStr.split("[")[0]) || null;
+ characterOffset = parseInt(termialStr.split("[")[0]);
textLocationAssertion = assertion[1];
} else {
- characterOffset = parseInt(termialStr) || null;
+ characterOffset = parseInt(termialStr);
+ }
+
+ if (!isNumber(characterOffset)) {
+ characterOffset = null;
}
return {
@@ -294,12 +298,12 @@ class EpubCFI {
cfiString += this.segmentString(this.path);
// Add Range, if present
- if(this.start) {
+ if(this.range && this.start) {
cfiString += ",";
cfiString += this.segmentString(this.start);
}
- if(this.end) {
+ if(this.range && this.end) {
cfiString += ",";
cfiString += this.segmentString(this.end);
}
@@ -313,6 +317,11 @@ class EpubCFI {
var stepsA, stepsB;
var terminalA, terminalB;
+ var rangeAStartSteps, rangeAEndSteps;
+ var rangeBEndSteps, rangeBEndSteps;
+ var rangeAStartTerminal, rangeAEndTerminal;
+ var rangeBStartTerminal, rangeBEndTerminal;
+
if(typeof cfiOne === "string") {
cfiOne = new EpubCFI(cfiOne);
}
@@ -968,6 +977,23 @@ class EpubCFI {
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;
diff --git a/src/locations.js b/src/locations.js
index 71e9c0f..4f2dcf3 100644
--- a/src/locations.js
+++ b/src/locations.js
@@ -43,13 +43,13 @@ class Locations {
this.q.pause();
this.spine.each(function(section) {
-
- this.q.enqueue(this.process.bind(this), section);
-
+ if (section.linear) {
+ this.q.enqueue(this.process.bind(this), section);
+ }
}.bind(this));
return this.q.run().then(function() {
- this.total = this._locations.length-1;
+ this.total = this._locations.length - 1;
if (this._currentCfi) {
this.currentLocation = this._currentCfi;
@@ -164,11 +164,22 @@ class Locations {
}
locationFromCfi(cfi){
+ let loc;
+ if (EpubCFI.prototype.isCfiString(cfi)) {
+ cfi = new EpubCFI(cfi);
+ }
// Check if the location has not been set yet
if(this._locations.length === 0) {
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) {
@@ -185,6 +196,7 @@ class Locations {
if (!loc || !this.total) {
return 0;
}
+
return (loc / this.total);
}
@@ -202,16 +214,26 @@ class Locations {
return cfi;
}
- cfiFromPercentage(value){
- var percentage = (value > 1) ? value / 100 : value; // Normalize value to 0-1
- var loc = Math.ceil(this.total * percentage);
+ cfiFromPercentage(percentage){
+ let loc;
+ 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);
}
load(locations){
this._locations = JSON.parse(locations);
- this.total = this._locations.length-1;
+ this.total = this._locations.length - 1;
return this._locations;
}
diff --git a/src/managers/views/iframe.js b/src/managers/views/iframe.js
index 25e4c50..6a82bf3 100644
--- a/src/managers/views/iframe.js
+++ b/src/managers/views/iframe.js
@@ -545,8 +545,8 @@ class IframeView {
var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
return {
- "left": window.scrollX + parentPos.left + targetPos.left,
- "top": window.scrollY + parentPos.top + targetPos.top
+ "left": window.scrollX + targetPos.left,
+ "top": window.scrollY + targetPos.top
};
}
diff --git a/src/rendition.js b/src/rendition.js
index 8c74e0f..b4bdcbc 100644
--- a/src/rendition.js
+++ b/src/rendition.js
@@ -244,8 +244,11 @@ class Rendition {
var moveTo;
// Check if this is a book percentage
- if (this.book.locations.length && isFloat(target)) {
- target = this.book.locations.cfiFromPercentage(target);
+ if (this.book.locations.length &&
+ (isFloat(target) ||
+ (typeof target === "string" && target == parseFloat(target))) // Handle 1.0
+ ) {
+ target = this.book.locations.cfiFromPercentage(parseFloat(target));
}
section = this.book.spine.get(target);
@@ -487,7 +490,7 @@ class Rendition {
location.then(function(result) {
this.location = result;
- this.percentage = this.book.locations.percentageFromCfi(result);
+ this.percentage = this.book.locations.percentageFromCfi(result.start);
if (this.percentage != null) {
this.location.percentage = this.percentage;
}
@@ -496,7 +499,7 @@ class Rendition {
}.bind(this));
} else if (location) {
this.location = location;
- this.percentage = this.book.locations.percentageFromCfi(location);
+ this.percentage = this.book.locations.percentageFromCfi(location.start);
if (this.percentage != null) {
this.location.percentage = this.percentage;
}
@@ -515,14 +518,14 @@ class Rendition {
var location = this.manager.currentLocation();
if (location && location.then && typeof location.then === "function") {
location.then(function(result) {
- var percentage = this.book.locations.percentageFromCfi(result);
+ var percentage = this.book.locations.percentageFromCfi(result.start);
if (percentage != null) {
result.percentage = percentage;
}
return result;
}.bind(this));
} else if (location) {
- var percentage = this.book.locations.percentageFromCfi(location);
+ var percentage = this.book.locations.percentageFromCfi(location.start);
if (percentage != null) {
location.percentage = percentage;
}
diff --git a/src/section.js b/src/section.js
index f32d865..4a9efd5 100644
--- a/src/section.js
+++ b/src/section.js
@@ -13,7 +13,7 @@ import { replaceBase } from "./utils/replacements";
class Section {
constructor(item, hooks){
this.idref = item.idref;
- this.linear = item.linear;
+ this.linear = item.linear === "yes";
this.properties = item.properties;
this.index = item.index;
this.href = item.href;
diff --git a/src/spine.js b/src/spine.js
index 052b05e..9a2d531 100644
--- a/src/spine.js
+++ b/src/spine.js
@@ -48,6 +48,7 @@ class Spine {
var manifestItem = this.manifest[item.idref];
var spineItem;
+ item.index = index;
item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);
if (item.href) {
@@ -62,8 +63,39 @@ class Spine {
}
}
- item.prev = function(){ return this.get(index-1); }.bind(this);
- item.next = function(){ return this.get(index+1); }.bind(this);
+ if (item.linear === "yes") {
+ 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);
@@ -87,10 +119,18 @@ class Spine {
get(target) {
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);
index = cfi.spinePos;
- } else if(target && (typeof target === "number" || isNaN(target) === false)){
+ } else if(typeof target === "number" || isNaN(target) === false){
index = target;
} else if(target && target.indexOf("#") === 0) {
index = this.spineById[target.substring(1)];
diff --git a/src/utils/core.js b/src/utils/core.js
index ab2ec62..b4c5bd0 100644
--- a/src/utils/core.js
+++ b/src/utils/core.js
@@ -105,9 +105,8 @@ export function locationOf(item, array, compareFunction, _start, _end) {
compared = compareFunction(array[pivot], item);
if(end-start === 1) {
- return compared > 0 ? pivot : pivot + 1;
+ return compared >= 0 ? pivot : pivot + 1;
}
-
if(compared === 0) {
return pivot;
}