mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-04 15:09:16 +02:00
Added locations generator to get reading percentages
This commit is contained in:
parent
89a9ade8df
commit
d0725af232
18 changed files with 1206 additions and 66 deletions
2
books
2
books
|
@ -1 +1 @@
|
|||
Subproject commit ab9755a74714b647290c861f666515de220935d8
|
||||
Subproject commit e9790315c2510315e270a7a4c4921825e9918039
|
270
build/epub.js
270
build/epub.js
|
@ -2485,11 +2485,11 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
//-- Set Globbal Layout setting based on metadata
|
||||
book.globalLayoutProperties = book.parseLayoutProperties(book.metadata);
|
||||
|
||||
|
||||
if(book.contents.coverPath) {
|
||||
book.cover = book.contents.cover = book.settings.contentsPath + book.contents.coverPath;
|
||||
}
|
||||
|
||||
|
||||
book.spineNodeIndex = book.contents.spineNodeIndex;
|
||||
|
||||
book.ready.manifest.resolve(book.contents.manifest);
|
||||
|
@ -2497,6 +2497,7 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
book.ready.metadata.resolve(book.contents.metadata);
|
||||
book.ready.cover.resolve(book.contents.cover);
|
||||
|
||||
book.locations = new EPUBJS.Locations(book.spine);
|
||||
|
||||
//-- Load the TOC, optional; either the EPUB3 XHTML Navigation file or the EPUB2 NCX file
|
||||
if(book.contents.navPath) {
|
||||
|
@ -2763,11 +2764,11 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
EPUBJS.Book.prototype.loadChange = function(url){
|
||||
var uri = EPUBJS.core.uri(url);
|
||||
var chapter;
|
||||
|
||||
|
||||
if(this.currentChapter) {
|
||||
chapter = EPUBJS.core.uri(this.currentChapter.absolute);
|
||||
}
|
||||
|
||||
|
||||
if(!this._rendering && this.currentChapter && uri.path != chapter.path){
|
||||
console.warn("Miss Match", uri.path, this.currentChapter.absolute);
|
||||
this.goto(uri.filename);
|
||||
|
@ -3328,13 +3329,13 @@ EPUBJS.Book.prototype.fromStorage = function(stored) {
|
|||
|
||||
EPUBJS.Book.prototype.setStyle = function(style, val, prefixed) {
|
||||
var noreflow = ["color", "background", "background-color"];
|
||||
|
||||
|
||||
if(!this.isRendered) return this._q.enqueue("setStyle", arguments);
|
||||
|
||||
this.settings.styles[style] = val;
|
||||
|
||||
this.renderer.setStyle(style, val, prefixed);
|
||||
|
||||
|
||||
if(noreflow.indexOf(style) === -1) {
|
||||
// clearTimeout(this.reformatTimeout);
|
||||
// this.reformatTimeout = setTimeout(function(){
|
||||
|
@ -3366,7 +3367,7 @@ EPUBJS.Book.prototype.useSpreads = function(use) {
|
|||
|
||||
EPUBJS.Book.prototype.forceSingle = function(_use) {
|
||||
var force = typeof _use === "undefined" ? true : _use;
|
||||
|
||||
|
||||
this.renderer.forceSingle(force);
|
||||
this.settings.forceSingle = force;
|
||||
if(this.isRendered) {
|
||||
|
@ -3422,7 +3423,7 @@ EPUBJS.Book.prototype.destroy = function() {
|
|||
|
||||
this.unload();
|
||||
|
||||
if(this.render) this.render.remove();
|
||||
if(this.renderer) this.renderer.remove();
|
||||
|
||||
};
|
||||
|
||||
|
@ -5168,6 +5169,233 @@ EPUBJS.Layout.Fixed.prototype.calculatePages = function(){
|
|||
};
|
||||
};
|
||||
|
||||
EPUBJS.Locations = function(spine, store) {
|
||||
this.spine = spine;
|
||||
this.store = store;
|
||||
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
|
||||
this._locations = [];
|
||||
this.total = 0;
|
||||
|
||||
this.break = 150;
|
||||
|
||||
this._current = 0;
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.generate = function(chars) {
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var nextChapter = function(deferred){
|
||||
var chapter;
|
||||
var next = spinePos + 1;
|
||||
var done = deferred || new RSVP.defer();
|
||||
var loaded;
|
||||
if(next >= spineLength) {
|
||||
done.resolve();
|
||||
} else {
|
||||
spinePos = next;
|
||||
chapter = new EPUBJS.Chapter(this.spine[spinePos], this.store);
|
||||
|
||||
this.process(chapter).then(function() {
|
||||
// Load up the next chapter
|
||||
setTimeout(function(){
|
||||
nextChapter(done);
|
||||
}, 1);
|
||||
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
this.total = this._locations.length-1;
|
||||
|
||||
if (this._currentCfi) {
|
||||
this.currentLocation = this._currentCfi;
|
||||
}
|
||||
deferred.resolve(this._locations);
|
||||
}.bind(this));
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.process = function(chapter) {
|
||||
return chapter.load(this.request)
|
||||
.then(function(_doc) {
|
||||
|
||||
var range;
|
||||
var doc = _doc;
|
||||
var contents = doc.documentElement;
|
||||
var counter = 0;
|
||||
var prev;
|
||||
|
||||
this.sprint(contents, function(node) {
|
||||
var len = node.length;
|
||||
var dist;
|
||||
var pos = 0;
|
||||
|
||||
// Start range
|
||||
if (counter === 0) {
|
||||
range = doc.createRange();
|
||||
range.setStart(node, 0);
|
||||
}
|
||||
|
||||
dist = this.break - counter;
|
||||
|
||||
// Node is smaller than a break
|
||||
if(dist > len){
|
||||
counter += len;
|
||||
pos = len;
|
||||
}
|
||||
|
||||
while (pos < len) {
|
||||
counter = this.break;
|
||||
pos += this.break;
|
||||
|
||||
// Gone over
|
||||
if(pos >= len){
|
||||
// Continue counter for next node
|
||||
counter = len - (pos - this.break);
|
||||
|
||||
// At End
|
||||
} else {
|
||||
// End the previous range
|
||||
range.setEnd(node, pos);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
|
||||
// Start new range
|
||||
pos += 1;
|
||||
range = doc.createRange();
|
||||
range.setStart(node, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prev = node;
|
||||
|
||||
}.bind(this));
|
||||
|
||||
// Close remaining
|
||||
if (range) {
|
||||
range.setEnd(prev, prev.length);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.sprint = function(root, func) {
|
||||
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
||||
|
||||
while ((node = treeWalker.nextNode())) {
|
||||
func(node);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.locationFromCfi = function(cfi){
|
||||
// Check if the location has not been set yet
|
||||
if(this._locations.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return EPUBJS.core.locationOf(cfi, this._locations, this.epubcfi.compare);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromCfi = function(cfi) {
|
||||
// Find closest cfi
|
||||
var loc = this.locationFromCfi(cfi);
|
||||
// Get percentage in total
|
||||
return this.percentageFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromLocation = function(loc) {
|
||||
if (!loc || !this.total) {
|
||||
return 0;
|
||||
}
|
||||
return Math.floor((loc / this.total ) * 100);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromLocation = function(loc){
|
||||
var cfi = -1;
|
||||
// check that pg is an int
|
||||
if(typeof loc != "number"){
|
||||
loc = parseInt(loc);
|
||||
}
|
||||
|
||||
if(loc >= 0 && loc < this._locations.length) {
|
||||
cfi = this._locations[loc];
|
||||
}
|
||||
|
||||
return cfi;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromPercentage = function(percent){
|
||||
var loc = Math.ceil(this.total * (percent/100));
|
||||
|
||||
return this.cfiFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.load = function(locations){
|
||||
this._locations = JSON.parse(locations);
|
||||
this.total = this._locations.length-1;
|
||||
return this._locations;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.save = function(json){
|
||||
return JSON.stringify(this._locations);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.getCurrent = function(json){
|
||||
return this._current;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.setCurrent = function(curr){
|
||||
var loc;
|
||||
|
||||
if(typeof curr == "string"){
|
||||
this._currentCfi = curr;
|
||||
} else if (typeof curr == "number") {
|
||||
this._current = curr;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._locations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof curr == "string"){
|
||||
loc = this.locationFromCfi(curr);
|
||||
this._current = loc;
|
||||
} else {
|
||||
loc = curr;
|
||||
}
|
||||
|
||||
this.trigger("changed", {
|
||||
percentage: this.percentageFromLocation(loc)
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperty(EPUBJS.Locations.prototype, 'currentLocation', {
|
||||
get: function () {
|
||||
return this._current;
|
||||
},
|
||||
set: function (curr) {
|
||||
this.setCurrent(curr);
|
||||
}
|
||||
});
|
||||
|
||||
RSVP.EventTarget.mixin(EPUBJS.Locations.prototype);
|
||||
|
||||
EPUBJS.Pagination = function(pageList) {
|
||||
this.pages = [];
|
||||
this.locations = [];
|
||||
|
@ -7305,13 +7533,24 @@ EPUBJS.replace.hrefs = function(callback, renderer){
|
|||
link.setAttribute("target", "_blank");
|
||||
|
||||
}else{
|
||||
// Links may need to be resolved, such as ../chp1.xhtml
|
||||
directory = EPUBJS.core.uri(renderer.render.window.location.href).directory;
|
||||
if(directory) {
|
||||
relative = EPUBJS.core.resolveUrl(directory, href);
|
||||
} else {
|
||||
relative = href;
|
||||
}
|
||||
// Links may need to be resolved, such as ../chp1.xhtml
|
||||
var uri = EPUBJS.core.uri(renderer.render.window.location.href);
|
||||
|
||||
directory = uri.directory;
|
||||
|
||||
if(directory) {
|
||||
// We must ensure that the file:// protocol is preserved for
|
||||
// local file links, as in certain contexts (such as under
|
||||
// Titanium), file links without the file:// protocol will not
|
||||
// work
|
||||
if (uri.protocol === "file") {
|
||||
relative = EPUBJS.core.resolveUrl(uri.base, href);
|
||||
} else {
|
||||
relative = EPUBJS.core.resolveUrl(directory, href);
|
||||
}
|
||||
} else {
|
||||
relative = href;
|
||||
}
|
||||
|
||||
link.onclick = function(){
|
||||
book.goto(relative);
|
||||
|
@ -7435,6 +7674,7 @@ EPUBJS.replace.cssUrls = function(_store, base, text){
|
|||
|
||||
|
||||
|
||||
|
||||
EPUBJS.Unarchiver = function(url){
|
||||
|
||||
this.loadLib();
|
||||
|
|
File diff suppressed because one or more lines are too long
7
build/epub.min.js
vendored
7
build/epub.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -2484,11 +2484,11 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
//-- Set Globbal Layout setting based on metadata
|
||||
book.globalLayoutProperties = book.parseLayoutProperties(book.metadata);
|
||||
|
||||
|
||||
if(book.contents.coverPath) {
|
||||
book.cover = book.contents.cover = book.settings.contentsPath + book.contents.coverPath;
|
||||
}
|
||||
|
||||
|
||||
book.spineNodeIndex = book.contents.spineNodeIndex;
|
||||
|
||||
book.ready.manifest.resolve(book.contents.manifest);
|
||||
|
@ -2496,6 +2496,7 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
book.ready.metadata.resolve(book.contents.metadata);
|
||||
book.ready.cover.resolve(book.contents.cover);
|
||||
|
||||
book.locations = new EPUBJS.Locations(book.spine);
|
||||
|
||||
//-- Load the TOC, optional; either the EPUB3 XHTML Navigation file or the EPUB2 NCX file
|
||||
if(book.contents.navPath) {
|
||||
|
@ -2762,11 +2763,11 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
EPUBJS.Book.prototype.loadChange = function(url){
|
||||
var uri = EPUBJS.core.uri(url);
|
||||
var chapter;
|
||||
|
||||
|
||||
if(this.currentChapter) {
|
||||
chapter = EPUBJS.core.uri(this.currentChapter.absolute);
|
||||
}
|
||||
|
||||
|
||||
if(!this._rendering && this.currentChapter && uri.path != chapter.path){
|
||||
console.warn("Miss Match", uri.path, this.currentChapter.absolute);
|
||||
this.goto(uri.filename);
|
||||
|
@ -3327,13 +3328,13 @@ EPUBJS.Book.prototype.fromStorage = function(stored) {
|
|||
|
||||
EPUBJS.Book.prototype.setStyle = function(style, val, prefixed) {
|
||||
var noreflow = ["color", "background", "background-color"];
|
||||
|
||||
|
||||
if(!this.isRendered) return this._q.enqueue("setStyle", arguments);
|
||||
|
||||
this.settings.styles[style] = val;
|
||||
|
||||
this.renderer.setStyle(style, val, prefixed);
|
||||
|
||||
|
||||
if(noreflow.indexOf(style) === -1) {
|
||||
// clearTimeout(this.reformatTimeout);
|
||||
// this.reformatTimeout = setTimeout(function(){
|
||||
|
@ -3365,7 +3366,7 @@ EPUBJS.Book.prototype.useSpreads = function(use) {
|
|||
|
||||
EPUBJS.Book.prototype.forceSingle = function(_use) {
|
||||
var force = typeof _use === "undefined" ? true : _use;
|
||||
|
||||
|
||||
this.renderer.forceSingle(force);
|
||||
this.settings.forceSingle = force;
|
||||
if(this.isRendered) {
|
||||
|
@ -3421,7 +3422,7 @@ EPUBJS.Book.prototype.destroy = function() {
|
|||
|
||||
this.unload();
|
||||
|
||||
if(this.render) this.render.remove();
|
||||
if(this.renderer) this.renderer.remove();
|
||||
|
||||
};
|
||||
|
||||
|
@ -5167,6 +5168,233 @@ EPUBJS.Layout.Fixed.prototype.calculatePages = function(){
|
|||
};
|
||||
};
|
||||
|
||||
EPUBJS.Locations = function(spine, store) {
|
||||
this.spine = spine;
|
||||
this.store = store;
|
||||
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
|
||||
this._locations = [];
|
||||
this.total = 0;
|
||||
|
||||
this.break = 150;
|
||||
|
||||
this._current = 0;
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.generate = function(chars) {
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var nextChapter = function(deferred){
|
||||
var chapter;
|
||||
var next = spinePos + 1;
|
||||
var done = deferred || new RSVP.defer();
|
||||
var loaded;
|
||||
if(next >= spineLength) {
|
||||
done.resolve();
|
||||
} else {
|
||||
spinePos = next;
|
||||
chapter = new EPUBJS.Chapter(this.spine[spinePos], this.store);
|
||||
|
||||
this.process(chapter).then(function() {
|
||||
// Load up the next chapter
|
||||
setTimeout(function(){
|
||||
nextChapter(done);
|
||||
}, 1);
|
||||
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
this.total = this._locations.length-1;
|
||||
|
||||
if (this._currentCfi) {
|
||||
this.currentLocation = this._currentCfi;
|
||||
}
|
||||
deferred.resolve(this._locations);
|
||||
}.bind(this));
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.process = function(chapter) {
|
||||
return chapter.load(this.request)
|
||||
.then(function(_doc) {
|
||||
|
||||
var range;
|
||||
var doc = _doc;
|
||||
var contents = doc.documentElement;
|
||||
var counter = 0;
|
||||
var prev;
|
||||
|
||||
this.sprint(contents, function(node) {
|
||||
var len = node.length;
|
||||
var dist;
|
||||
var pos = 0;
|
||||
|
||||
// Start range
|
||||
if (counter === 0) {
|
||||
range = doc.createRange();
|
||||
range.setStart(node, 0);
|
||||
}
|
||||
|
||||
dist = this.break - counter;
|
||||
|
||||
// Node is smaller than a break
|
||||
if(dist > len){
|
||||
counter += len;
|
||||
pos = len;
|
||||
}
|
||||
|
||||
while (pos < len) {
|
||||
counter = this.break;
|
||||
pos += this.break;
|
||||
|
||||
// Gone over
|
||||
if(pos >= len){
|
||||
// Continue counter for next node
|
||||
counter = len - (pos - this.break);
|
||||
|
||||
// At End
|
||||
} else {
|
||||
// End the previous range
|
||||
range.setEnd(node, pos);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
|
||||
// Start new range
|
||||
pos += 1;
|
||||
range = doc.createRange();
|
||||
range.setStart(node, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prev = node;
|
||||
|
||||
}.bind(this));
|
||||
|
||||
// Close remaining
|
||||
if (range) {
|
||||
range.setEnd(prev, prev.length);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.sprint = function(root, func) {
|
||||
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
||||
|
||||
while ((node = treeWalker.nextNode())) {
|
||||
func(node);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.locationFromCfi = function(cfi){
|
||||
// Check if the location has not been set yet
|
||||
if(this._locations.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return EPUBJS.core.locationOf(cfi, this._locations, this.epubcfi.compare);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromCfi = function(cfi) {
|
||||
// Find closest cfi
|
||||
var loc = this.locationFromCfi(cfi);
|
||||
// Get percentage in total
|
||||
return this.percentageFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromLocation = function(loc) {
|
||||
if (!loc || !this.total) {
|
||||
return 0;
|
||||
}
|
||||
return Math.floor((loc / this.total ) * 100);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromLocation = function(loc){
|
||||
var cfi = -1;
|
||||
// check that pg is an int
|
||||
if(typeof loc != "number"){
|
||||
loc = parseInt(loc);
|
||||
}
|
||||
|
||||
if(loc >= 0 && loc < this._locations.length) {
|
||||
cfi = this._locations[loc];
|
||||
}
|
||||
|
||||
return cfi;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromPercentage = function(percent){
|
||||
var loc = Math.ceil(this.total * (percent/100));
|
||||
|
||||
return this.cfiFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.load = function(locations){
|
||||
this._locations = JSON.parse(locations);
|
||||
this.total = this._locations.length-1;
|
||||
return this._locations;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.save = function(json){
|
||||
return JSON.stringify(this._locations);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.getCurrent = function(json){
|
||||
return this._current;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.setCurrent = function(curr){
|
||||
var loc;
|
||||
|
||||
if(typeof curr == "string"){
|
||||
this._currentCfi = curr;
|
||||
} else if (typeof curr == "number") {
|
||||
this._current = curr;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._locations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof curr == "string"){
|
||||
loc = this.locationFromCfi(curr);
|
||||
this._current = loc;
|
||||
} else {
|
||||
loc = curr;
|
||||
}
|
||||
|
||||
this.trigger("changed", {
|
||||
percentage: this.percentageFromLocation(loc)
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperty(EPUBJS.Locations.prototype, 'currentLocation', {
|
||||
get: function () {
|
||||
return this._current;
|
||||
},
|
||||
set: function (curr) {
|
||||
this.setCurrent(curr);
|
||||
}
|
||||
});
|
||||
|
||||
RSVP.EventTarget.mixin(EPUBJS.Locations.prototype);
|
||||
|
||||
EPUBJS.Pagination = function(pageList) {
|
||||
this.pages = [];
|
||||
this.locations = [];
|
||||
|
@ -7304,13 +7532,24 @@ EPUBJS.replace.hrefs = function(callback, renderer){
|
|||
link.setAttribute("target", "_blank");
|
||||
|
||||
}else{
|
||||
// Links may need to be resolved, such as ../chp1.xhtml
|
||||
directory = EPUBJS.core.uri(renderer.render.window.location.href).directory;
|
||||
if(directory) {
|
||||
relative = EPUBJS.core.resolveUrl(directory, href);
|
||||
} else {
|
||||
relative = href;
|
||||
}
|
||||
// Links may need to be resolved, such as ../chp1.xhtml
|
||||
var uri = EPUBJS.core.uri(renderer.render.window.location.href);
|
||||
|
||||
directory = uri.directory;
|
||||
|
||||
if(directory) {
|
||||
// We must ensure that the file:// protocol is preserved for
|
||||
// local file links, as in certain contexts (such as under
|
||||
// Titanium), file links without the file:// protocol will not
|
||||
// work
|
||||
if (uri.protocol === "file") {
|
||||
relative = EPUBJS.core.resolveUrl(uri.base, href);
|
||||
} else {
|
||||
relative = EPUBJS.core.resolveUrl(directory, href);
|
||||
}
|
||||
} else {
|
||||
relative = href;
|
||||
}
|
||||
|
||||
link.onclick = function(){
|
||||
book.goto(relative);
|
||||
|
@ -7434,6 +7673,7 @@ EPUBJS.replace.cssUrls = function(_store, base, text){
|
|||
|
||||
|
||||
|
||||
|
||||
EPUBJS.Unarchiver = function(url){
|
||||
|
||||
this.loadLib();
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8,5 +8,5 @@
|
|||
"hooks/default/transculsions.js"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;A;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;A;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;A;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;A"
|
||||
"mappings": "AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"
|
||||
}
|
File diff suppressed because one or more lines are too long
2
build/reader.min.js
vendored
2
build/reader.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
190
examples/locations.html
Normal file
190
examples/locations.html
Normal file
|
@ -0,0 +1,190 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>Basic ePubJS Example</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<script src="../build/epub.min.js"></script>
|
||||
|
||||
<!-- Hooks -->
|
||||
<!-- <script src="../hooks/default/transculsions.js"></script> -->
|
||||
<!-- <script src="../hooks/default/endnotes.js"></script> -->
|
||||
<script src="../hooks/default/smartimages.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
EPUBJS.filePath = "../reader/js/libs/";
|
||||
EPUBJS.cssPath = "../reader/css/";
|
||||
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
|
||||
}
|
||||
|
||||
#main {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/* overflow: hidden; */
|
||||
}
|
||||
|
||||
#area {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: 5% auto;
|
||||
max-width: 1250px;
|
||||
}
|
||||
|
||||
#area iframe {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#prev {
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
#next {
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -32px;
|
||||
font-size: 64px;
|
||||
color: #E2E2E2;
|
||||
font-family: arial, sans-serif;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.arrow:hover {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.arrow:active {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 50%;
|
||||
width: 400px;
|
||||
margin-left: -200px;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#controls > input[type=range] {
|
||||
width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
var book = ePub("../books/moby-dick/", { width: 1076, height: 588 });
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div id="prev" onclick="book.prevPage();" class="arrow">‹</div>
|
||||
<div id="area"></div>
|
||||
<div id="next" onclick="book.nextPage();"class="arrow">›</div>
|
||||
<div id="controls">
|
||||
<input id="current-percent" size="3" value="0" /> %
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var controls = document.getElementById("controls");
|
||||
var currentPage = document.getElementById("current-percent");
|
||||
var slider = document.createElement("input");
|
||||
var slide = function(){
|
||||
var cfi = book.locations.cfiFromPercentage(slider.value);
|
||||
book.gotoCfi(cfi);
|
||||
};
|
||||
var throttledSlide = _.throttle(slide, 200);
|
||||
var mouseDown = false;
|
||||
|
||||
var rendered = book.renderTo("area");
|
||||
|
||||
|
||||
book.ready.all.then(function(){
|
||||
// Load in stored locations from json or local storage
|
||||
var key = book.generateBookKey()+'-locations';
|
||||
var stored = false;//localStorage.getItem(key);
|
||||
if (stored) {
|
||||
return book.locations.load(stored);
|
||||
} else {
|
||||
// Or generate the locations on the fly
|
||||
// Can pass an option number of chars to break sections by
|
||||
// default is 150 chars
|
||||
return book.locations.generate(1600);
|
||||
}
|
||||
})
|
||||
.then(function(locations){
|
||||
|
||||
controls.style.display = "block";
|
||||
slider.setAttribute("type", "range");
|
||||
slider.setAttribute("min", 0);
|
||||
slider.setAttribute("max", 100);
|
||||
// slider.setAttribute("max", book.locations.total+1);
|
||||
slider.setAttribute("step", 1);
|
||||
slider.setAttribute("value", 0);
|
||||
|
||||
slider.addEventListener("change", throttledSlide, false);
|
||||
slider.addEventListener("mousedown", function(){
|
||||
mouseDown = true;
|
||||
}, false);
|
||||
slider.addEventListener("mouseup", function(){
|
||||
mouseDown = false;
|
||||
}, false);
|
||||
|
||||
// Wait for book to be rendered to get current page
|
||||
rendered.then(function(){
|
||||
// Get the current CFI
|
||||
var currentLocation = book.getCurrentLocationCfi();
|
||||
// Get the Percentage (or location) from that CFI
|
||||
var currentPage = book.locations.percentageFromCfi(currentLocation);
|
||||
slider.value = currentPage;
|
||||
currentPage.value = currentPage;
|
||||
});
|
||||
|
||||
controls.appendChild(slider);
|
||||
|
||||
currentPage.addEventListener("change", function(){
|
||||
var cfi = book.locations.cfiFromPercentage(currentPage.value);
|
||||
book.gotoCfi(cfi);
|
||||
}, false);
|
||||
|
||||
// Listen for location changed event, get percentage from CFI
|
||||
book.on('renderer:locationChanged', function(location){
|
||||
var percent = book.locations.percentageFromCfi(location);
|
||||
if(!mouseDown) {
|
||||
slider.value = percent;
|
||||
}
|
||||
currentPage.value = percent;
|
||||
});
|
||||
|
||||
// Save out the generated locations to JSON
|
||||
localStorage.setItem(book.generateBookKey()+'-locations', book.locations.save());
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
270
reader/js/epub.min.js
vendored
270
reader/js/epub.min.js
vendored
|
@ -2485,11 +2485,11 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
//-- Set Globbal Layout setting based on metadata
|
||||
book.globalLayoutProperties = book.parseLayoutProperties(book.metadata);
|
||||
|
||||
|
||||
if(book.contents.coverPath) {
|
||||
book.cover = book.contents.cover = book.settings.contentsPath + book.contents.coverPath;
|
||||
}
|
||||
|
||||
|
||||
book.spineNodeIndex = book.contents.spineNodeIndex;
|
||||
|
||||
book.ready.manifest.resolve(book.contents.manifest);
|
||||
|
@ -2497,6 +2497,7 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
book.ready.metadata.resolve(book.contents.metadata);
|
||||
book.ready.cover.resolve(book.contents.cover);
|
||||
|
||||
book.locations = new EPUBJS.Locations(book.spine);
|
||||
|
||||
//-- Load the TOC, optional; either the EPUB3 XHTML Navigation file or the EPUB2 NCX file
|
||||
if(book.contents.navPath) {
|
||||
|
@ -2763,11 +2764,11 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
EPUBJS.Book.prototype.loadChange = function(url){
|
||||
var uri = EPUBJS.core.uri(url);
|
||||
var chapter;
|
||||
|
||||
|
||||
if(this.currentChapter) {
|
||||
chapter = EPUBJS.core.uri(this.currentChapter.absolute);
|
||||
}
|
||||
|
||||
|
||||
if(!this._rendering && this.currentChapter && uri.path != chapter.path){
|
||||
console.warn("Miss Match", uri.path, this.currentChapter.absolute);
|
||||
this.goto(uri.filename);
|
||||
|
@ -3328,13 +3329,13 @@ EPUBJS.Book.prototype.fromStorage = function(stored) {
|
|||
|
||||
EPUBJS.Book.prototype.setStyle = function(style, val, prefixed) {
|
||||
var noreflow = ["color", "background", "background-color"];
|
||||
|
||||
|
||||
if(!this.isRendered) return this._q.enqueue("setStyle", arguments);
|
||||
|
||||
this.settings.styles[style] = val;
|
||||
|
||||
this.renderer.setStyle(style, val, prefixed);
|
||||
|
||||
|
||||
if(noreflow.indexOf(style) === -1) {
|
||||
// clearTimeout(this.reformatTimeout);
|
||||
// this.reformatTimeout = setTimeout(function(){
|
||||
|
@ -3366,7 +3367,7 @@ EPUBJS.Book.prototype.useSpreads = function(use) {
|
|||
|
||||
EPUBJS.Book.prototype.forceSingle = function(_use) {
|
||||
var force = typeof _use === "undefined" ? true : _use;
|
||||
|
||||
|
||||
this.renderer.forceSingle(force);
|
||||
this.settings.forceSingle = force;
|
||||
if(this.isRendered) {
|
||||
|
@ -3422,7 +3423,7 @@ EPUBJS.Book.prototype.destroy = function() {
|
|||
|
||||
this.unload();
|
||||
|
||||
if(this.render) this.render.remove();
|
||||
if(this.renderer) this.renderer.remove();
|
||||
|
||||
};
|
||||
|
||||
|
@ -5168,6 +5169,233 @@ EPUBJS.Layout.Fixed.prototype.calculatePages = function(){
|
|||
};
|
||||
};
|
||||
|
||||
EPUBJS.Locations = function(spine, store) {
|
||||
this.spine = spine;
|
||||
this.store = store;
|
||||
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
|
||||
this._locations = [];
|
||||
this.total = 0;
|
||||
|
||||
this.break = 150;
|
||||
|
||||
this._current = 0;
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.generate = function(chars) {
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var nextChapter = function(deferred){
|
||||
var chapter;
|
||||
var next = spinePos + 1;
|
||||
var done = deferred || new RSVP.defer();
|
||||
var loaded;
|
||||
if(next >= spineLength) {
|
||||
done.resolve();
|
||||
} else {
|
||||
spinePos = next;
|
||||
chapter = new EPUBJS.Chapter(this.spine[spinePos], this.store);
|
||||
|
||||
this.process(chapter).then(function() {
|
||||
// Load up the next chapter
|
||||
setTimeout(function(){
|
||||
nextChapter(done);
|
||||
}, 1);
|
||||
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
this.total = this._locations.length-1;
|
||||
|
||||
if (this._currentCfi) {
|
||||
this.currentLocation = this._currentCfi;
|
||||
}
|
||||
deferred.resolve(this._locations);
|
||||
}.bind(this));
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.process = function(chapter) {
|
||||
return chapter.load(this.request)
|
||||
.then(function(_doc) {
|
||||
|
||||
var range;
|
||||
var doc = _doc;
|
||||
var contents = doc.documentElement;
|
||||
var counter = 0;
|
||||
var prev;
|
||||
|
||||
this.sprint(contents, function(node) {
|
||||
var len = node.length;
|
||||
var dist;
|
||||
var pos = 0;
|
||||
|
||||
// Start range
|
||||
if (counter === 0) {
|
||||
range = doc.createRange();
|
||||
range.setStart(node, 0);
|
||||
}
|
||||
|
||||
dist = this.break - counter;
|
||||
|
||||
// Node is smaller than a break
|
||||
if(dist > len){
|
||||
counter += len;
|
||||
pos = len;
|
||||
}
|
||||
|
||||
while (pos < len) {
|
||||
counter = this.break;
|
||||
pos += this.break;
|
||||
|
||||
// Gone over
|
||||
if(pos >= len){
|
||||
// Continue counter for next node
|
||||
counter = len - (pos - this.break);
|
||||
|
||||
// At End
|
||||
} else {
|
||||
// End the previous range
|
||||
range.setEnd(node, pos);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
|
||||
// Start new range
|
||||
pos += 1;
|
||||
range = doc.createRange();
|
||||
range.setStart(node, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prev = node;
|
||||
|
||||
}.bind(this));
|
||||
|
||||
// Close remaining
|
||||
if (range) {
|
||||
range.setEnd(prev, prev.length);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.sprint = function(root, func) {
|
||||
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
||||
|
||||
while ((node = treeWalker.nextNode())) {
|
||||
func(node);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.locationFromCfi = function(cfi){
|
||||
// Check if the location has not been set yet
|
||||
if(this._locations.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return EPUBJS.core.locationOf(cfi, this._locations, this.epubcfi.compare);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromCfi = function(cfi) {
|
||||
// Find closest cfi
|
||||
var loc = this.locationFromCfi(cfi);
|
||||
// Get percentage in total
|
||||
return this.percentageFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromLocation = function(loc) {
|
||||
if (!loc || !this.total) {
|
||||
return 0;
|
||||
}
|
||||
return Math.floor((loc / this.total ) * 100);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromLocation = function(loc){
|
||||
var cfi = -1;
|
||||
// check that pg is an int
|
||||
if(typeof loc != "number"){
|
||||
loc = parseInt(loc);
|
||||
}
|
||||
|
||||
if(loc >= 0 && loc < this._locations.length) {
|
||||
cfi = this._locations[loc];
|
||||
}
|
||||
|
||||
return cfi;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromPercentage = function(percent){
|
||||
var loc = Math.ceil(this.total * (percent/100));
|
||||
|
||||
return this.cfiFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.load = function(locations){
|
||||
this._locations = JSON.parse(locations);
|
||||
this.total = this._locations.length-1;
|
||||
return this._locations;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.save = function(json){
|
||||
return JSON.stringify(this._locations);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.getCurrent = function(json){
|
||||
return this._current;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.setCurrent = function(curr){
|
||||
var loc;
|
||||
|
||||
if(typeof curr == "string"){
|
||||
this._currentCfi = curr;
|
||||
} else if (typeof curr == "number") {
|
||||
this._current = curr;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._locations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof curr == "string"){
|
||||
loc = this.locationFromCfi(curr);
|
||||
this._current = loc;
|
||||
} else {
|
||||
loc = curr;
|
||||
}
|
||||
|
||||
this.trigger("changed", {
|
||||
percentage: this.percentageFromLocation(loc)
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperty(EPUBJS.Locations.prototype, 'currentLocation', {
|
||||
get: function () {
|
||||
return this._current;
|
||||
},
|
||||
set: function (curr) {
|
||||
this.setCurrent(curr);
|
||||
}
|
||||
});
|
||||
|
||||
RSVP.EventTarget.mixin(EPUBJS.Locations.prototype);
|
||||
|
||||
EPUBJS.Pagination = function(pageList) {
|
||||
this.pages = [];
|
||||
this.locations = [];
|
||||
|
@ -7305,13 +7533,24 @@ EPUBJS.replace.hrefs = function(callback, renderer){
|
|||
link.setAttribute("target", "_blank");
|
||||
|
||||
}else{
|
||||
// Links may need to be resolved, such as ../chp1.xhtml
|
||||
directory = EPUBJS.core.uri(renderer.render.window.location.href).directory;
|
||||
if(directory) {
|
||||
relative = EPUBJS.core.resolveUrl(directory, href);
|
||||
} else {
|
||||
relative = href;
|
||||
}
|
||||
// Links may need to be resolved, such as ../chp1.xhtml
|
||||
var uri = EPUBJS.core.uri(renderer.render.window.location.href);
|
||||
|
||||
directory = uri.directory;
|
||||
|
||||
if(directory) {
|
||||
// We must ensure that the file:// protocol is preserved for
|
||||
// local file links, as in certain contexts (such as under
|
||||
// Titanium), file links without the file:// protocol will not
|
||||
// work
|
||||
if (uri.protocol === "file") {
|
||||
relative = EPUBJS.core.resolveUrl(uri.base, href);
|
||||
} else {
|
||||
relative = EPUBJS.core.resolveUrl(directory, href);
|
||||
}
|
||||
} else {
|
||||
relative = href;
|
||||
}
|
||||
|
||||
link.onclick = function(){
|
||||
book.goto(relative);
|
||||
|
@ -7435,6 +7674,7 @@ EPUBJS.replace.cssUrls = function(_store, base, text){
|
|||
|
||||
|
||||
|
||||
|
||||
EPUBJS.Unarchiver = function(url){
|
||||
|
||||
this.loadLib();
|
||||
|
|
File diff suppressed because one or more lines are too long
2
reader/js/reader.min.js
vendored
2
reader/js/reader.min.js
vendored
File diff suppressed because one or more lines are too long
15
src/book.js
15
src/book.js
|
@ -234,11 +234,11 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
//-- Set Globbal Layout setting based on metadata
|
||||
book.globalLayoutProperties = book.parseLayoutProperties(book.metadata);
|
||||
|
||||
|
||||
if(book.contents.coverPath) {
|
||||
book.cover = book.contents.cover = book.settings.contentsPath + book.contents.coverPath;
|
||||
}
|
||||
|
||||
|
||||
book.spineNodeIndex = book.contents.spineNodeIndex;
|
||||
|
||||
book.ready.manifest.resolve(book.contents.manifest);
|
||||
|
@ -246,6 +246,7 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
book.ready.metadata.resolve(book.contents.metadata);
|
||||
book.ready.cover.resolve(book.contents.cover);
|
||||
|
||||
book.locations = new EPUBJS.Locations(book.spine);
|
||||
|
||||
//-- Load the TOC, optional; either the EPUB3 XHTML Navigation file or the EPUB2 NCX file
|
||||
if(book.contents.navPath) {
|
||||
|
@ -512,11 +513,11 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
EPUBJS.Book.prototype.loadChange = function(url){
|
||||
var uri = EPUBJS.core.uri(url);
|
||||
var chapter;
|
||||
|
||||
|
||||
if(this.currentChapter) {
|
||||
chapter = EPUBJS.core.uri(this.currentChapter.absolute);
|
||||
}
|
||||
|
||||
|
||||
if(!this._rendering && this.currentChapter && uri.path != chapter.path){
|
||||
console.warn("Miss Match", uri.path, this.currentChapter.absolute);
|
||||
this.goto(uri.filename);
|
||||
|
@ -1077,13 +1078,13 @@ EPUBJS.Book.prototype.fromStorage = function(stored) {
|
|||
|
||||
EPUBJS.Book.prototype.setStyle = function(style, val, prefixed) {
|
||||
var noreflow = ["color", "background", "background-color"];
|
||||
|
||||
|
||||
if(!this.isRendered) return this._q.enqueue("setStyle", arguments);
|
||||
|
||||
this.settings.styles[style] = val;
|
||||
|
||||
this.renderer.setStyle(style, val, prefixed);
|
||||
|
||||
|
||||
if(noreflow.indexOf(style) === -1) {
|
||||
// clearTimeout(this.reformatTimeout);
|
||||
// this.reformatTimeout = setTimeout(function(){
|
||||
|
@ -1115,7 +1116,7 @@ EPUBJS.Book.prototype.useSpreads = function(use) {
|
|||
|
||||
EPUBJS.Book.prototype.forceSingle = function(_use) {
|
||||
var force = typeof _use === "undefined" ? true : _use;
|
||||
|
||||
|
||||
this.renderer.forceSingle(force);
|
||||
this.settings.forceSingle = force;
|
||||
if(this.isRendered) {
|
||||
|
|
226
src/locations.js
Normal file
226
src/locations.js
Normal file
|
@ -0,0 +1,226 @@
|
|||
EPUBJS.Locations = function(spine, store) {
|
||||
this.spine = spine;
|
||||
this.store = store;
|
||||
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
|
||||
this._locations = [];
|
||||
this.total = 0;
|
||||
|
||||
this.break = 150;
|
||||
|
||||
this._current = 0;
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.generate = function(chars) {
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var nextChapter = function(deferred){
|
||||
var chapter;
|
||||
var next = spinePos + 1;
|
||||
var done = deferred || new RSVP.defer();
|
||||
var loaded;
|
||||
if(next >= spineLength) {
|
||||
done.resolve();
|
||||
} else {
|
||||
spinePos = next;
|
||||
chapter = new EPUBJS.Chapter(this.spine[spinePos], this.store);
|
||||
|
||||
this.process(chapter).then(function() {
|
||||
// Load up the next chapter
|
||||
setTimeout(function(){
|
||||
nextChapter(done);
|
||||
}, 1);
|
||||
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
this.total = this._locations.length-1;
|
||||
|
||||
if (this._currentCfi) {
|
||||
this.currentLocation = this._currentCfi;
|
||||
}
|
||||
deferred.resolve(this._locations);
|
||||
}.bind(this));
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.process = function(chapter) {
|
||||
return chapter.load(this.request)
|
||||
.then(function(_doc) {
|
||||
|
||||
var range;
|
||||
var doc = _doc;
|
||||
var contents = doc.documentElement;
|
||||
var counter = 0;
|
||||
var prev;
|
||||
|
||||
this.sprint(contents, function(node) {
|
||||
var len = node.length;
|
||||
var dist;
|
||||
var pos = 0;
|
||||
|
||||
// Start range
|
||||
if (counter === 0) {
|
||||
range = doc.createRange();
|
||||
range.setStart(node, 0);
|
||||
}
|
||||
|
||||
dist = this.break - counter;
|
||||
|
||||
// Node is smaller than a break
|
||||
if(dist > len){
|
||||
counter += len;
|
||||
pos = len;
|
||||
}
|
||||
|
||||
while (pos < len) {
|
||||
counter = this.break;
|
||||
pos += this.break;
|
||||
|
||||
// Gone over
|
||||
if(pos >= len){
|
||||
// Continue counter for next node
|
||||
counter = len - (pos - this.break);
|
||||
|
||||
// At End
|
||||
} else {
|
||||
// End the previous range
|
||||
range.setEnd(node, pos);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
|
||||
// Start new range
|
||||
pos += 1;
|
||||
range = doc.createRange();
|
||||
range.setStart(node, pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prev = node;
|
||||
|
||||
}.bind(this));
|
||||
|
||||
// Close remaining
|
||||
if (range) {
|
||||
range.setEnd(prev, prev.length);
|
||||
cfi = chapter.cfiFromRange(range);
|
||||
this._locations.push(cfi);
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.sprint = function(root, func) {
|
||||
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
||||
|
||||
while ((node = treeWalker.nextNode())) {
|
||||
func(node);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.locationFromCfi = function(cfi){
|
||||
// Check if the location has not been set yet
|
||||
if(this._locations.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return EPUBJS.core.locationOf(cfi, this._locations, this.epubcfi.compare);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromCfi = function(cfi) {
|
||||
// Find closest cfi
|
||||
var loc = this.locationFromCfi(cfi);
|
||||
// Get percentage in total
|
||||
return this.percentageFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.percentageFromLocation = function(loc) {
|
||||
if (!loc || !this.total) {
|
||||
return 0;
|
||||
}
|
||||
return Math.floor((loc / this.total ) * 100);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromLocation = function(loc){
|
||||
var cfi = -1;
|
||||
// check that pg is an int
|
||||
if(typeof loc != "number"){
|
||||
loc = parseInt(loc);
|
||||
}
|
||||
|
||||
if(loc >= 0 && loc < this._locations.length) {
|
||||
cfi = this._locations[loc];
|
||||
}
|
||||
|
||||
return cfi;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.cfiFromPercentage = function(percent){
|
||||
var loc = Math.ceil(this.total * (percent/100));
|
||||
|
||||
return this.cfiFromLocation(loc);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.load = function(locations){
|
||||
this._locations = JSON.parse(locations);
|
||||
this.total = this._locations.length-1;
|
||||
return this._locations;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.save = function(json){
|
||||
return JSON.stringify(this._locations);
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.getCurrent = function(json){
|
||||
return this._current;
|
||||
};
|
||||
|
||||
EPUBJS.Locations.prototype.setCurrent = function(curr){
|
||||
var loc;
|
||||
|
||||
if(typeof curr == "string"){
|
||||
this._currentCfi = curr;
|
||||
} else if (typeof curr == "number") {
|
||||
this._current = curr;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this._locations.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(typeof curr == "string"){
|
||||
loc = this.locationFromCfi(curr);
|
||||
this._current = loc;
|
||||
} else {
|
||||
loc = curr;
|
||||
}
|
||||
|
||||
this.trigger("changed", {
|
||||
percentage: this.percentageFromLocation(loc)
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperty(EPUBJS.Locations.prototype, 'currentLocation', {
|
||||
get: function () {
|
||||
return this._current;
|
||||
},
|
||||
set: function (curr) {
|
||||
this.setCurrent(curr);
|
||||
}
|
||||
});
|
||||
|
||||
RSVP.EventTarget.mixin(EPUBJS.Locations.prototype);
|
Loading…
Add table
Add a link
Reference in a new issue