1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-04 15:09:16 +02:00

Added locations

This commit is contained in:
fchasen 2015-07-08 21:54:00 -04:00
parent d7371a619d
commit 80787fc86b
10 changed files with 648 additions and 125 deletions

285
dist/epub.js vendored
View file

@ -2174,6 +2174,7 @@ EPUBJS.Queue = function(_context){
this.context = _context; this.context = _context;
this.tick = EPUBJS.core.requestAnimationFrame; this.tick = EPUBJS.core.requestAnimationFrame;
this.running = false; this.running = false;
this.paused = false;
}; };
// Add an item to the queue // Add an item to the queue
@ -2215,7 +2216,11 @@ EPUBJS.Queue.prototype.enqueue = function() {
this._q.push(queued); this._q.push(queued);
// Wait to start queue flush // Wait to start queue flush
setTimeout(this.flush.bind(this), 0); if (this.paused == false && !this.running) {
// setTimeout(this.flush.bind(this), 0);
// this.tick.call(window, this.run.bind(this));
this.run();
}
return queued.promise; return queued.promise;
}; };
@ -2268,25 +2273,46 @@ EPUBJS.Queue.prototype.dump = function(){
// Run all sequentially, at convince // Run all sequentially, at convince
EPUBJS.Queue.prototype.run = function(){ EPUBJS.Queue.prototype.run = function(){
if(!this.running && this._q.length) {
if(!this.running){
this.running = true; this.running = true;
this.dequeue().then(function(){ this.defered = new RSVP.defer();
this.running = false;
}.bind(this));
} }
this.tick.call(window, this.run.bind(this)); this.tick.call(window, function() {
if(this._q.length) {
this.dequeue()
.then(function(){
this.run();
}.bind(this));
} else {
this.defered.resolve();
this.running = undefined;
}
}.bind(this));
// Unpause
if(this.paused == true) {
this.paused = false;
}
return this.defered.promise;
}; };
// Flush all, as quickly as possible // Flush all, as quickly as possible
EPUBJS.Queue.prototype.flush = function(){ EPUBJS.Queue.prototype.flush = function(){
if(this.running){ if(this.running){
return this.running; return this.running;
} }
if(this._q.length) { if(this._q.length) {
this.running = this.dequeue(). this.running = this.dequeue()
then(function(){ .then(function(){
this.running = undefined; this.running = undefined;
return this.flush(); return this.flush();
}.bind(this)); }.bind(this));
@ -2306,6 +2332,10 @@ EPUBJS.Queue.prototype.length = function(){
return this._q.length; return this._q.length;
}; };
EPUBJS.Queue.prototype.pause = function(){
this.paused = true;
};
// Create a new task from a callback // Create a new task from a callback
EPUBJS.Task = function(task, args, context){ EPUBJS.Task = function(task, args, context){
@ -3165,7 +3195,14 @@ EPUBJS.EpubCFI.prototype.generateCfiFromRange = function(range, base) {
endPath = this.generatePathComponent(endSteps); endPath = this.generatePathComponent(endSteps);
endOffset = range.endOffset; endOffset = range.endOffset;
return "epubcfi(" + base + "!" + startPath + "/" + startIndex + ":" + startOffset + "," + endPath + "/" + endIndex + ":" + endOffset + ")"; // Remove steps present in startPath
endPath = endPath.replace(startPath, '');
if (endPath.length) {
endPath = endPath + "/";
}
return "epubcfi(" + base + "!" + startPath + "/" + startIndex + ":" + startOffset + "," + endPath + endIndex + ":" + endOffset + ")";
} else { } else {
return "epubcfi(" + base + "!" + startPath + "/"+ startIndex +":"+ startOffset +")"; return "epubcfi(" + base + "!" + startPath + "/"+ startIndex +":"+ startOffset +")";
@ -3245,6 +3282,7 @@ EPUBJS.EpubCFI.prototype.isCfiString = function(target) {
return false; return false;
}; };
EPUBJS.Navigation = function(_package, _request){ EPUBJS.Navigation = function(_package, _request){
var navigation = this; var navigation = this;
var parse = new EPUBJS.Parser(); var parse = new EPUBJS.Parser();
@ -3468,6 +3506,11 @@ EPUBJS.Section.prototype.reconcileLayoutSettings = function(global){
EPUBJS.Section.prototype.cfiFromRange = function(_range) { EPUBJS.Section.prototype.cfiFromRange = function(_range) {
return this.epubcfi.generateCfiFromRange(_range, this.cfiBase); return this.epubcfi.generateCfiFromRange(_range, this.cfiBase);
}; };
EPUBJS.Section.prototype.cfiFromElement = function(el) {
return this.epubcfi.generateCfiFromElement(el, this.cfiBase);
};
EPUBJS.Spine = function(_request){ EPUBJS.Spine = function(_request){
this.request = _request; this.request = _request;
this.spineItems = []; this.spineItems = [];
@ -3580,6 +3623,10 @@ EPUBJS.Spine.prototype.remove = function(section) {
} }
}; };
EPUBJS.Spine.prototype.each = function() {
return this.spineItems.forEach.apply(this.spineItems, arguments);
};
EPUBJS.replace = {}; EPUBJS.replace = {};
EPUBJS.replace.links = function(view, renderer) { EPUBJS.replace.links = function(view, renderer) {
@ -3623,7 +3670,7 @@ EPUBJS.replace.links = function(view, renderer) {
}; };
EPUBJS.Book = function(_url){ EPUBJS.Book = function(_url, options){
// Promises // Promises
this.opening = new RSVP.defer(); this.opening = new RSVP.defer();
this.opened = this.opening.promise; this.opened = this.opening.promise;
@ -3631,8 +3678,6 @@ EPUBJS.Book = function(_url){
this.url = undefined; this.url = undefined;
this.spine = new EPUBJS.Spine(this.request);
this.loading = { this.loading = {
manifest: new RSVP.defer(), manifest: new RSVP.defer(),
spine: new RSVP.defer(), spine: new RSVP.defer(),
@ -3659,6 +3704,9 @@ EPUBJS.Book = function(_url){
this.request = this.requestMethod.bind(this); this.request = this.requestMethod.bind(this);
this.spine = new EPUBJS.Spine(this.request);
this.locations = new EPUBJS.Locations(this.spine, this.request);
if(_url) { if(_url) {
this.open(_url); this.open(_url);
} }
@ -3822,6 +3870,7 @@ EPUBJS.Book.prototype.setRequestCredentials = function(_credentials) {
EPUBJS.Book.prototype.setRequestHeaders = function(_headers) { EPUBJS.Book.prototype.setRequestHeaders = function(_headers) {
this.requestHeaders = _headers; this.requestHeaders = _headers;
}; };
//-- Enable binding events to book //-- Enable binding events to book
RSVP.EventTarget.mixin(EPUBJS.Book.prototype); RSVP.EventTarget.mixin(EPUBJS.Book.prototype);
@ -3837,6 +3886,7 @@ RSVP.configure('instrument', true); //-- true | will logging out all RSVP reject
RSVP.on('rejected', function(event){ RSVP.on('rejected', function(event){
console.error(event.detail.message, event.detail.stack); console.error(event.detail.message, event.detail.stack);
}); });
EPUBJS.View = function(section, options) { EPUBJS.View = function(section, options) {
this.settings = options || {}; this.settings = options || {};
@ -6495,3 +6545,214 @@ EPUBJS.Map.prototype.rangeListToCfiList = function(view, columns){
return map; return map;
}; };
EPUBJS.Locations = function(spine, request) {
this.spine = spine;
this.request = request;
this.q = new EPUBJS.Queue(this);
this.epubcfi = new EPUBJS.EpubCFI();
this._locations = [];
this.total = 0;
this.break = 150;
this._current = 0;
};
// Load all of sections in the book
EPUBJS.Locations.prototype.generate = function(chars) {
if (chars) {
this.break = chars;
}
this.q.pause();
this.spine.each(function(section) {
this.q.enqueue(this.process, section);
}.bind(this));
return this.q.run().then(function() {
this.total = this._locations.length-1;
if (this._currentCfi) {
this.currentLocation = this._currentCfi;
}
return this._locations;
// console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end));
}.bind(this));
};
EPUBJS.Locations.prototype.process = function(section) {
return section.load(this.request)
.then(function(contents) {
var range;
var doc = contents.ownerDocument;
var counter = 0;
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 = section.cfiFromRange(range);
this._locations.push(cfi);
counter = 0;
// Start new range
pos += 1;
range = doc.createRange();
range.setStart(node, pos);
}
}
}.bind(this));
// Close remaining
if (range) {
range.setEnd(prev, prev.length);
cfi = section.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.precentageFromCfi = function(cfi) {
// Find closest cfi
var loc = this.locationFromCfi(cfi);
// Get percentage in total
return this.precentageFromLocation(loc);
};
EPUBJS.Locations.prototype.precentageFromLocation = function(loc) {
return Math.ceil((loc / this.total ) * 1000) / 1000;
};
EPUBJS.Locations.prototype.cfiFromLocation = function(loc){
var cfi = -1;
// check that pg is an int
if(typeof loc != "number"){
loc = parseInt(pg);
}
if(loc >= 0 && loc < this._locations.length) {
cfi = this._locations[loc];
}
return cfi;
};
EPUBJS.Locations.prototype.cfiFromPercentage = function(percent){
var loc = Math.round(this.total * percent);
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;
}
console.log( this.precentageFromLocation(loc))
this.trigger("changed", {
percentage: this.precentageFromLocation(loc)
});
};
Object.defineProperty(EPUBJS.Locations.prototype, 'currentLocation', {
get: function () {
return this._current;
},
set: function (curr) {
this.setCurrent(curr);
}
});
RSVP.EventTarget.mixin(EPUBJS.Locations.prototype);

6
dist/epub.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -119,7 +119,7 @@
<script> <script>
// Load the opf // Load the opf
// var book = ePub("https://s3.amazonaws.com/moby-dick/OPS/package.opf"); // var book = ePub("https://s3.amazonaws.com/moby-dick/OPS/package.opf");
var book = ePub("books/alice/OPS/package.opf"); var book = ePub("../books/alice/OPS/package.opf");
var rendition = book.renderTo("viewer", { var rendition = book.renderTo("viewer", {
method: "paginate", method: "paginate",
width: "100%", width: "100%",
@ -148,7 +148,7 @@
rendition.prev(); rendition.prev();
}, false); }, false);
document.addEventListener("keyup", function(e){ var keyListener = function(e){
// Left Key // Left Key
if ((e.keyCode || e.which) == 37) { if ((e.keyCode || e.which) == 37) {
@ -160,7 +160,10 @@
rendition.next(); rendition.next();
} }
}, false); };
rendition.on("keyup", keyListener);
document.addEventListener("keyup", keyListener, false);
</script> </script>

View file

@ -29,7 +29,8 @@ var files = [
'src/rendition.js', 'src/rendition.js',
'src/continuous.js', 'src/continuous.js',
'src/paginate.js', 'src/paginate.js',
'src/map.js' 'src/map.js',
'src/locations.js'
]; ];
// Lint JS // Lint JS

View file

@ -1,4 +1,4 @@
EPUBJS.Book = function(_url){ EPUBJS.Book = function(_url, options){
// Promises // Promises
this.opening = new RSVP.defer(); this.opening = new RSVP.defer();
this.opened = this.opening.promise; this.opened = this.opening.promise;
@ -6,8 +6,6 @@ EPUBJS.Book = function(_url){
this.url = undefined; this.url = undefined;
this.spine = new EPUBJS.Spine(this.request);
this.loading = { this.loading = {
manifest: new RSVP.defer(), manifest: new RSVP.defer(),
spine: new RSVP.defer(), spine: new RSVP.defer(),
@ -34,6 +32,9 @@ EPUBJS.Book = function(_url){
this.request = this.requestMethod.bind(this); this.request = this.requestMethod.bind(this);
this.spine = new EPUBJS.Spine(this.request);
this.locations = new EPUBJS.Locations(this.spine, this.request);
if(_url) { if(_url) {
this.open(_url); this.open(_url);
} }
@ -197,6 +198,7 @@ EPUBJS.Book.prototype.setRequestCredentials = function(_credentials) {
EPUBJS.Book.prototype.setRequestHeaders = function(_headers) { EPUBJS.Book.prototype.setRequestHeaders = function(_headers) {
this.requestHeaders = _headers; this.requestHeaders = _headers;
}; };
//-- Enable binding events to book //-- Enable binding events to book
RSVP.EventTarget.mixin(EPUBJS.Book.prototype); RSVP.EventTarget.mixin(EPUBJS.Book.prototype);

View file

@ -430,7 +430,14 @@ EPUBJS.EpubCFI.prototype.generateCfiFromRange = function(range, base) {
endPath = this.generatePathComponent(endSteps); endPath = this.generatePathComponent(endSteps);
endOffset = range.endOffset; endOffset = range.endOffset;
return "epubcfi(" + base + "!" + startPath + "/" + startIndex + ":" + startOffset + "," + endPath + "/" + endIndex + ":" + endOffset + ")"; // Remove steps present in startPath
endPath = endPath.replace(startPath, '');
if (endPath.length) {
endPath = endPath + "/";
}
return "epubcfi(" + base + "!" + startPath + "/" + startIndex + ":" + startOffset + "," + endPath + endIndex + ":" + endOffset + ")";
} else { } else {
return "epubcfi(" + base + "!" + startPath + "/"+ startIndex +":"+ startOffset +")"; return "epubcfi(" + base + "!" + startPath + "/"+ startIndex +":"+ startOffset +")";

211
src/locations.js Normal file
View file

@ -0,0 +1,211 @@
EPUBJS.Locations = function(spine, request) {
this.spine = spine;
this.request = request;
this.q = new EPUBJS.Queue(this);
this.epubcfi = new EPUBJS.EpubCFI();
this._locations = [];
this.total = 0;
this.break = 150;
this._current = 0;
};
// Load all of sections in the book
EPUBJS.Locations.prototype.generate = function(chars) {
if (chars) {
this.break = chars;
}
this.q.pause();
this.spine.each(function(section) {
this.q.enqueue(this.process, section);
}.bind(this));
return this.q.run().then(function() {
this.total = this._locations.length-1;
if (this._currentCfi) {
this.currentLocation = this._currentCfi;
}
return this._locations;
// console.log(this.precentage(this.book.rendition.location.start), this.precentage(this.book.rendition.location.end));
}.bind(this));
};
EPUBJS.Locations.prototype.process = function(section) {
return section.load(this.request)
.then(function(contents) {
var range;
var doc = contents.ownerDocument;
var counter = 0;
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 = section.cfiFromRange(range);
this._locations.push(cfi);
counter = 0;
// Start new range
pos += 1;
range = doc.createRange();
range.setStart(node, pos);
}
}
}.bind(this));
// Close remaining
if (range) {
range.setEnd(prev, prev.length);
cfi = section.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.precentageFromCfi = function(cfi) {
// Find closest cfi
var loc = this.locationFromCfi(cfi);
// Get percentage in total
return this.precentageFromLocation(loc);
};
EPUBJS.Locations.prototype.precentageFromLocation = function(loc) {
return Math.ceil((loc / this.total ) * 1000) / 1000;
};
EPUBJS.Locations.prototype.cfiFromLocation = function(loc){
var cfi = -1;
// check that pg is an int
if(typeof loc != "number"){
loc = parseInt(pg);
}
if(loc >= 0 && loc < this._locations.length) {
cfi = this._locations[loc];
}
return cfi;
};
EPUBJS.Locations.prototype.cfiFromPercentage = function(percent){
var loc = Math.round(this.total * percent);
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;
}
console.log( this.precentageFromLocation(loc))
this.trigger("changed", {
percentage: this.precentageFromLocation(loc)
});
};
Object.defineProperty(EPUBJS.Locations.prototype, 'currentLocation', {
get: function () {
return this._current;
},
set: function (curr) {
this.setCurrent(curr);
}
});
RSVP.EventTarget.mixin(EPUBJS.Locations.prototype);

View file

@ -3,6 +3,7 @@ EPUBJS.Queue = function(_context){
this.context = _context; this.context = _context;
this.tick = EPUBJS.core.requestAnimationFrame; this.tick = EPUBJS.core.requestAnimationFrame;
this.running = false; this.running = false;
this.paused = false;
}; };
// Add an item to the queue // Add an item to the queue
@ -44,7 +45,11 @@ EPUBJS.Queue.prototype.enqueue = function() {
this._q.push(queued); this._q.push(queued);
// Wait to start queue flush // Wait to start queue flush
setTimeout(this.flush.bind(this), 0); if (this.paused == false && !this.running) {
// setTimeout(this.flush.bind(this), 0);
// this.tick.call(window, this.run.bind(this));
this.run();
}
return queued.promise; return queued.promise;
}; };
@ -97,25 +102,46 @@ EPUBJS.Queue.prototype.dump = function(){
// Run all sequentially, at convince // Run all sequentially, at convince
EPUBJS.Queue.prototype.run = function(){ EPUBJS.Queue.prototype.run = function(){
if(!this.running && this._q.length) {
if(!this.running){
this.running = true; this.running = true;
this.dequeue().then(function(){ this.defered = new RSVP.defer();
this.running = false;
}.bind(this));
} }
this.tick.call(window, this.run.bind(this)); this.tick.call(window, function() {
if(this._q.length) {
this.dequeue()
.then(function(){
this.run();
}.bind(this));
} else {
this.defered.resolve();
this.running = undefined;
}
}.bind(this));
// Unpause
if(this.paused == true) {
this.paused = false;
}
return this.defered.promise;
}; };
// Flush all, as quickly as possible // Flush all, as quickly as possible
EPUBJS.Queue.prototype.flush = function(){ EPUBJS.Queue.prototype.flush = function(){
if(this.running){ if(this.running){
return this.running; return this.running;
} }
if(this._q.length) { if(this._q.length) {
this.running = this.dequeue(). this.running = this.dequeue()
then(function(){ .then(function(){
this.running = undefined; this.running = undefined;
return this.flush(); return this.flush();
}.bind(this)); }.bind(this));
@ -135,6 +161,10 @@ EPUBJS.Queue.prototype.length = function(){
return this._q.length; return this._q.length;
}; };
EPUBJS.Queue.prototype.pause = function(){
this.paused = true;
};
// Create a new task from a callback // Create a new task from a callback
EPUBJS.Task = function(task, args, context){ EPUBJS.Task = function(task, args, context){

View file

@ -126,3 +126,7 @@ EPUBJS.Section.prototype.reconcileLayoutSettings = function(global){
EPUBJS.Section.prototype.cfiFromRange = function(_range) { EPUBJS.Section.prototype.cfiFromRange = function(_range) {
return this.epubcfi.generateCfiFromRange(_range, this.cfiBase); return this.epubcfi.generateCfiFromRange(_range, this.cfiBase);
}; };
EPUBJS.Section.prototype.cfiFromElement = function(el) {
return this.epubcfi.generateCfiFromElement(el, this.cfiBase);
};

View file

@ -109,3 +109,7 @@ EPUBJS.Spine.prototype.remove = function(section) {
return this.spineItems.splice(index, 1); return this.spineItems.splice(index, 1);
} }
}; };
EPUBJS.Spine.prototype.each = function() {
return this.spineItems.forEach.apply(this.spineItems, arguments);
};