mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
initial pagination features
This commit is contained in:
parent
73ac66ba65
commit
93a0cd772d
19 changed files with 970 additions and 104 deletions
359
build/epub.js
359
build/epub.js
|
@ -1839,7 +1839,8 @@ EPUBJS.Book = function(options){
|
|||
spine: new RSVP.defer(),
|
||||
metadata: new RSVP.defer(),
|
||||
cover: new RSVP.defer(),
|
||||
toc: new RSVP.defer()
|
||||
toc: new RSVP.defer(),
|
||||
pageList: new RSVP.defer()
|
||||
};
|
||||
|
||||
this.readyPromises = [
|
||||
|
@ -1849,6 +1850,7 @@ EPUBJS.Book = function(options){
|
|||
this.ready.cover.promise,
|
||||
this.ready.toc.promise
|
||||
];
|
||||
this.pageListReady = this.ready.pageList.promise;
|
||||
|
||||
this.ready.all = RSVP.all(this.readyPromises);
|
||||
|
||||
|
@ -1937,7 +1939,7 @@ EPUBJS.Book.prototype.open = function(bookPath, forceReload){
|
|||
if(!this.settings.stored) opened.then(book.storeOffline());
|
||||
}
|
||||
|
||||
this._registerReplacements();
|
||||
this._registerReplacements(this.renderer);
|
||||
|
||||
return opened.promise;
|
||||
|
||||
|
@ -2015,6 +2017,21 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
}, function(error) {
|
||||
book.ready.toc.resolve(false);
|
||||
});
|
||||
|
||||
// Load the optional pageList
|
||||
book.loadXml(book.settings.navUrl).
|
||||
then(function(navHtml){
|
||||
return parse.pageList(navHtml, book.spineIndexByURL, book.spine);
|
||||
}).then(function(pageList){
|
||||
book.pageList = book.contents.pageList = pageList;
|
||||
book.pagination = new EPUBJS.Pagination();
|
||||
if(pageList.length) {
|
||||
book.pagination.process(book.pageList);
|
||||
book.ready.pageList.resolve(book.pageList);
|
||||
}
|
||||
}, function(error) {
|
||||
// book.ready.pageList.resolve(false);
|
||||
});
|
||||
} else if(book.contents.tocPath) {
|
||||
book.settings.tocUrl = book.settings.contentsPath + book.contents.tocPath;
|
||||
|
||||
|
@ -2034,6 +2051,106 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.createHiddenRender = function(renderer, _width, _height) {
|
||||
var box = this.element.getBoundingClientRect();
|
||||
var width = _width || this.settings.width || box.width;
|
||||
var height = _height || this.settings.height || box.height;
|
||||
var hiddenEl;
|
||||
|
||||
renderer.setMinSpreadWidth(this.settings.minSpreadWidth);
|
||||
this._registerReplacements(renderer);
|
||||
|
||||
hiddenEl = document.createElement("div");
|
||||
hiddenEl.style.visibility = "hidden";
|
||||
this.element.appendChild(hiddenEl);
|
||||
|
||||
renderer.initialize(hiddenEl, width, height);
|
||||
return hiddenEl;
|
||||
};
|
||||
|
||||
// Generates the pageList array by loading every chapter and paging through them
|
||||
EPUBJS.Book.prototype.generatePageList = function(width, height){
|
||||
var pageList = [];
|
||||
var pager = new EPUBJS.Renderer(this.settings.render_method);
|
||||
var hiddenElement = this.createHiddenRender(pager, width, height);
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var totalPages = 0;
|
||||
var currentPage = 1;
|
||||
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);
|
||||
|
||||
pager.displayChapter(chapter, this.globalLayoutProperties).then(function(){
|
||||
var nextPage = pager.nextPage();
|
||||
currentPage += 1;
|
||||
// Page though the entire chapter
|
||||
while (nextPage) {
|
||||
nextPage = pager.nextPage();
|
||||
}
|
||||
// Load up the next chapter
|
||||
nextChapter(done);
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
pager.remove();
|
||||
this.element.removeChild(hiddenElement);
|
||||
deferred.resolve(pageList);
|
||||
}.bind(this));
|
||||
|
||||
pager.on("renderer:locationChanged", function(cfi){
|
||||
pageList.push({
|
||||
"cfi" : cfi,
|
||||
"page" : currentPage
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
// Render out entire book and generate the pagination
|
||||
// Width and Height are optional and will default to the current dimensions
|
||||
EPUBJS.Book.prototype.generatePagination = function(width, height) {
|
||||
var book = this;
|
||||
var pageListReady;
|
||||
|
||||
this.ready.spine.promise.then(function(){
|
||||
pageListReady = book.generatePageList(width, height).then(function(pageList){
|
||||
book.pageList = book.contents.pageList = pageList;
|
||||
book.pagination.process(pageList);
|
||||
book.ready.pageList.resolve(book.pageList);
|
||||
});
|
||||
});
|
||||
return pageListReady;
|
||||
};
|
||||
|
||||
// Process the pagination from a JSON array containing the pagelist
|
||||
EPUBJS.Book.prototype.loadPagination = function(pagelistJSON) {
|
||||
var pageList = JSON.parse(jsonArray);
|
||||
if(pageList && pageList.length) {
|
||||
this.pageList = this.contents.pageList = pageList;
|
||||
this.pagination.process(this.pageList);
|
||||
this.ready.pageList.resolve(this.pageList);
|
||||
}
|
||||
return this.pageList;
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.getPageList = function() {
|
||||
return this.ready.pageList.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.getMetadata = function() {
|
||||
return this.ready.metadata.promise;
|
||||
};
|
||||
|
@ -2068,6 +2185,19 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
book.trigger(eventName, e);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
renderer.on("renderer:locationChanged", function(cfi) {
|
||||
var page, percent;
|
||||
if(this.pageList.length > 0) {
|
||||
page = this.pagination.pageFromCfi(cfi);
|
||||
percent = this.pagination.percentageFromPage(page);
|
||||
this.trigger("book:pageChanged", {
|
||||
"page": page,
|
||||
"percentage": percent
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.unlistenToRenderer = function(renderer){
|
||||
|
@ -2613,14 +2743,14 @@ EPUBJS.Book.prototype.applyHeadTags = function(callback){
|
|||
callback();
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype._registerReplacements = function(){
|
||||
this.renderer.registerHook("beforeChapterDisplay", this.applyStyles.bind(this), true);
|
||||
this.renderer.registerHook("beforeChapterDisplay", this.applyHeadTags.bind(this), true);
|
||||
this.renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs, true);
|
||||
EPUBJS.Book.prototype._registerReplacements = function(renderer){
|
||||
renderer.registerHook("beforeChapterDisplay", this.applyStyles.bind(this), true);
|
||||
renderer.registerHook("beforeChapterDisplay", this.applyHeadTags.bind(this), true);
|
||||
renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs, true);
|
||||
|
||||
if(this._needsAssetReplacement()) {
|
||||
|
||||
this.renderer.registerHook("beforeChapterDisplay", [
|
||||
renderer.registerHook("beforeChapterDisplay", [
|
||||
EPUBJS.replace.head,
|
||||
EPUBJS.replace.resources,
|
||||
EPUBJS.replace.svg
|
||||
|
@ -3057,6 +3187,36 @@ EPUBJS.core.uuid = function() {
|
|||
});
|
||||
return uuid;
|
||||
};
|
||||
|
||||
// Fast quicksort insert for sorted array -- based on:
|
||||
// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers
|
||||
EPUBJS.core.insert = function(item, array, compareFunction) {
|
||||
var location = EPUBJS.core.locationOf(item, array, compareFunction);
|
||||
array.splice(location+1, 0, item);
|
||||
|
||||
return location+1;
|
||||
};
|
||||
|
||||
EPUBJS.core.locationOf = function(item, array, compareFunction, _start, _end) {
|
||||
var start = _start || 0;
|
||||
var end = _end || array.length;
|
||||
var pivot = parseInt(start + (end - start) / 2);
|
||||
if(!compareFunction){
|
||||
compareFunction = function(a, b) {
|
||||
if(a > b) return 1;
|
||||
if(a < b) return -1;
|
||||
if(a = b) return 0;
|
||||
};
|
||||
}
|
||||
if(end-start <= 1 || compareFunction(array[pivot], item) === 0) {
|
||||
return pivot;
|
||||
}
|
||||
if(compareFunction(array[pivot], item) === -1) {
|
||||
return EPUBJS.core.locationOf(item, array, compareFunction, pivot, end);
|
||||
} else{
|
||||
return EPUBJS.core.locationOf(item, array, compareFunction, start, pivot);
|
||||
}
|
||||
};
|
||||
EPUBJS.EpubCFI = function(cfiStr){
|
||||
if(cfiStr) return this.parse(cfiStr);
|
||||
};
|
||||
|
@ -3099,7 +3259,7 @@ EPUBJS.EpubCFI.prototype.generateCfiFromElement = function(element, chapter) {
|
|||
var steps = this.pathTo(element);
|
||||
var path = this.generatePathComponent(steps);
|
||||
|
||||
return "epubcfi(" + chapter + "!" + path + ")";
|
||||
return "epubcfi(" + chapter + "!" + path + "/1:0)";
|
||||
};
|
||||
|
||||
EPUBJS.EpubCFI.prototype.pathTo = function(node) {
|
||||
|
@ -3280,10 +3440,10 @@ EPUBJS.EpubCFI.prototype.getElement = function(cfi, _doc) {
|
|||
|
||||
EPUBJS.EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
|
||||
if(typeof cfiOne === 'string') {
|
||||
cfiOne = this.parse(cfiOne);
|
||||
cfiOne = new EPUBJS.EpubCFI(cfiOne);
|
||||
}
|
||||
if(typeof cfiTwo === 'string') {
|
||||
cfiTwo = this.parse(cfiTwo);
|
||||
cfiTwo = new EPUBJS.EpubCFI(cfiTwo);
|
||||
}
|
||||
// Compare Spine Positions
|
||||
if(cfiOne.spinePos > cfiTwo.spinePos) {
|
||||
|
@ -3441,6 +3601,11 @@ EPUBJS.Hooks = (function(){
|
|||
hooks = this.hooks[type];
|
||||
|
||||
count = hooks.length;
|
||||
|
||||
if(count === 0 && callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
function countdown(){
|
||||
count--;
|
||||
if(count <= 0 && callback) callback();
|
||||
|
@ -3501,7 +3666,6 @@ EPUBJS.Layout.Reflowable.prototype.format = function(documentElement, _width, _h
|
|||
documentElement.style[columnWidth] = width+"px";
|
||||
|
||||
documentElement.style.width = width + "px";
|
||||
|
||||
return {
|
||||
pageWidth : this.spreadWidth,
|
||||
pageHeight : _height
|
||||
|
@ -3513,7 +3677,7 @@ EPUBJS.Layout.Reflowable.prototype.calculatePages = function() {
|
|||
this.documentElement.style.width = "auto"; //-- reset width for calculations
|
||||
totalWidth = this.documentElement.scrollWidth;
|
||||
displayedPages = Math.round(totalWidth / this.spreadWidth);
|
||||
|
||||
// console.log(totalWidth, this.spreadWidth)
|
||||
return {
|
||||
displayedPages : displayedPages,
|
||||
pageCount : displayedPages
|
||||
|
@ -3629,11 +3793,83 @@ EPUBJS.Layout.Fixed.prototype.calculatePages = function(){
|
|||
pageCount : 1
|
||||
};
|
||||
};
|
||||
EPUBJS.Navigation = function() {
|
||||
EPUBJS.Pagination = function(pageList) {
|
||||
this.pageList = pageList;
|
||||
this.pages = [];
|
||||
this.locations = [];
|
||||
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
};
|
||||
|
||||
// percentage at cfi, nearest page to Cfi, total pages and goto page.
|
||||
EPUBJS.Pagination.prototype.process = function(pageList){
|
||||
pageList.forEach(function(item){
|
||||
this.pages.push(item.page);
|
||||
this.locations.push(item.cfi);
|
||||
}, this);
|
||||
|
||||
this.firstPage = parseInt(this.pages[0]);
|
||||
this.lastPage = parseInt(this.pages[this.pages.length-1]);
|
||||
this.totalPages = this.lastPage - this.firstPage;
|
||||
};
|
||||
|
||||
EPUBJS.Pagination.prototype.pageFromCfi = function(cfi){
|
||||
var pg;
|
||||
// check if the cfi is in the location list
|
||||
var index = this.locations.indexOf(cfi);
|
||||
if(index != -1 && index < (this.pages.length-1) ) {
|
||||
pg = this.pages[index];
|
||||
} else {
|
||||
// Otherwise add it to the list of locations
|
||||
// Insert it in the correct position in the locations page
|
||||
index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare);
|
||||
// Get the page at the location just before the new one
|
||||
pg = this.pages[index-1];
|
||||
// Add the new page in so that the locations and page array match up
|
||||
this.pages.splice(index, 0, pg);
|
||||
}
|
||||
|
||||
return pg;
|
||||
};
|
||||
|
||||
EPUBJS.Pagination.prototype.cfiFromPage = function(pg){
|
||||
var cfi;
|
||||
// check if the cfi is in the page list
|
||||
var index = this.pages.indexOf(pg);
|
||||
if(index != -1) {
|
||||
cfi = this.locations[index];
|
||||
}
|
||||
// TODO: handle pages not in the list
|
||||
return cfi;
|
||||
};
|
||||
|
||||
EPUBJS.Pagination.prototype.pageFromPercentage = function(percent){
|
||||
var pg = Math.round(this.totalPages * percent);
|
||||
return pg;
|
||||
};
|
||||
|
||||
// Returns a value between 0 - 1 corresponding to the location of a page
|
||||
EPUBJS.Pagination.prototype.percentageFromPage = function(pg){
|
||||
var percentage = (pg - this.firstPage) / this.totalPages;
|
||||
return Math.round(percentage * 100) / 100;
|
||||
};
|
||||
|
||||
// Returns a value between 0 - 1 corresponding to the location of a cfi
|
||||
EPUBJS.Pagination.prototype.percentageFromCfi = function(cfi){
|
||||
var pg = this.pageFromCfi(cfi);
|
||||
var percentage = this.percentageFromPage(pg);
|
||||
return percentage;
|
||||
};
|
||||
|
||||
// TODO: move these
|
||||
EPUBJS.Book.prototype.gotoPage = function(pg){
|
||||
var cfi = this.pagination.cfiFromPage(pg);
|
||||
this.gotoCfi(cfi);
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.gotoPercentage = function(percent){
|
||||
var pg = this.pagination.pageFromPercentage(percent);
|
||||
this.gotoCfi(pg);
|
||||
};
|
||||
|
||||
EPUBJS.Parser = function(baseUrl){
|
||||
this.baseUrl = baseUrl || '';
|
||||
|
@ -3877,7 +4113,7 @@ EPUBJS.Parser.prototype.spine = function(spineXml, manifest){
|
|||
};
|
||||
|
||||
EPUBJS.Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navEl = navHtml.querySelector('nav'), //-- [*|type="toc"] * Doesn't seem to work
|
||||
var navEl = navHtml.querySelector('nav[*|type="toc"]'), //-- [*|type="toc"] * Doesn't seem to work
|
||||
idCounter = 0;
|
||||
|
||||
if(!navEl) return [];
|
||||
|
@ -4010,6 +4246,78 @@ EPUBJS.Parser.prototype.toc = function(tocXml, spineIndexByURL, bookSpine){
|
|||
|
||||
return getTOC(navMap);
|
||||
};
|
||||
|
||||
EPUBJS.Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navEl = navHtml.querySelector('nav[*|type="page-list"]'),
|
||||
idCounter = 0;
|
||||
|
||||
if(!navEl) return [];
|
||||
|
||||
// Implements `> ol > li`
|
||||
function findListItems(parent){
|
||||
var items = [];
|
||||
|
||||
Array.prototype.slice.call(parent.childNodes).forEach(function(node){
|
||||
if('ol' == node.tagName){
|
||||
Array.prototype.slice.call(node.childNodes).forEach(function(item){
|
||||
if('li' == item.tagName){
|
||||
items.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return items;
|
||||
|
||||
}
|
||||
|
||||
// Implements `> a, > span`
|
||||
function findAnchorOrSpan(parent){
|
||||
var item = null;
|
||||
|
||||
Array.prototype.slice.call(parent.childNodes).forEach(function(node){
|
||||
if('a' == node.tagName || 'span' == node.tagName){
|
||||
item = node;
|
||||
}
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
function getPages(parent){
|
||||
var list = [],
|
||||
nodes = findListItems(parent),
|
||||
items = Array.prototype.slice.call(nodes),
|
||||
length = items.length,
|
||||
node;
|
||||
|
||||
if(length === 0) return false;
|
||||
|
||||
items.forEach(function(item){
|
||||
var id = item.getAttribute('id') || false,
|
||||
content = findAnchorOrSpan(item),
|
||||
href = content.getAttribute('href') || '',
|
||||
text = content.textContent || "",
|
||||
split = href.split("#"),
|
||||
packageUrl = split[0],
|
||||
cfi = split.length > 1 ? split[1] : false;
|
||||
|
||||
if(cfi) {
|
||||
list.push({
|
||||
"cfi" : cfi,
|
||||
"packageUrl" : packageUrl,
|
||||
"page" : text
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return getPages(navEl);
|
||||
};
|
||||
|
||||
EPUBJS.Render.Iframe = function() {
|
||||
this.iframe = null;
|
||||
this.document = null;
|
||||
|
@ -4024,7 +4332,7 @@ EPUBJS.Render.Iframe = function() {
|
|||
//-- Build up any html needed
|
||||
EPUBJS.Render.Iframe.prototype.create = function(){
|
||||
this.iframe = document.createElement('iframe');
|
||||
this.iframe.id = "epubjs-iframe";
|
||||
this.iframe.id = "epubjs-iframe:" + EPUBJS.core.uuid();
|
||||
this.iframe.scrolling = "no";
|
||||
|
||||
return this.iframe;
|
||||
|
@ -4088,8 +4396,9 @@ EPUBJS.Render.Iframe.prototype.resize = function(width, height){
|
|||
|
||||
this.iframe.width = width;
|
||||
// Get the fractional height and width of the iframe
|
||||
this.width = this.iframe.getBoundingClientRect().width;
|
||||
this.height = this.iframe.getBoundingClientRect().height;
|
||||
// Default to orginal if bounding rect is 0
|
||||
this.width = this.iframe.getBoundingClientRect().width || width;
|
||||
this.height = this.iframe.getBoundingClientRect().height || height;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4241,7 +4550,7 @@ EPUBJS.Renderer.prototype.Events = [
|
|||
"renderer:selected",
|
||||
"renderer:chapterUnloaded",
|
||||
"renderer:chapterDisplayed",
|
||||
"renderer:pageChanged",
|
||||
"renderer:locationChanged",
|
||||
"renderer:resized",
|
||||
"renderer:spreads"
|
||||
];
|
||||
|
@ -4343,12 +4652,12 @@ EPUBJS.Renderer.prototype.load = function(url){
|
|||
var pages = this.layout.calculatePages();
|
||||
var msg = this.currentChapter;
|
||||
|
||||
this.updatePages(pages);
|
||||
|
||||
msg.cfi = this.currentLocationCfi = this.getPageCfi();
|
||||
|
||||
this.trigger("renderer:chapterDisplayed", msg);
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
|
||||
this.updatePages(pages);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
this.visible(true);
|
||||
|
||||
|
@ -4478,7 +4787,7 @@ EPUBJS.Renderer.prototype.visible = function(bool){
|
|||
|
||||
// Remove the render element and clean up listeners
|
||||
EPUBJS.Renderer.prototype.remove = function() {
|
||||
if(this.renderer.window) {
|
||||
if(this.render.window) {
|
||||
this.render.unload();
|
||||
this.render.window.removeEventListener("resize", this.resized);
|
||||
this.removeEventListeners();
|
||||
|
@ -4520,7 +4829,7 @@ EPUBJS.Renderer.prototype.page = function(pg){
|
|||
this.render.page(pg);
|
||||
|
||||
this.currentLocationCfi = this.getPageCfi();
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4537,7 +4846,7 @@ EPUBJS.Renderer.prototype.nextPage = function(){
|
|||
this.render.page(pg);
|
||||
|
||||
this.currentLocationCfi = this.getPageCfi(this.visibileEl);
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
6
build/epub.min.js
vendored
6
build/epub.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1838,7 +1838,8 @@ EPUBJS.Book = function(options){
|
|||
spine: new RSVP.defer(),
|
||||
metadata: new RSVP.defer(),
|
||||
cover: new RSVP.defer(),
|
||||
toc: new RSVP.defer()
|
||||
toc: new RSVP.defer(),
|
||||
pageList: new RSVP.defer()
|
||||
};
|
||||
|
||||
this.readyPromises = [
|
||||
|
@ -1848,6 +1849,7 @@ EPUBJS.Book = function(options){
|
|||
this.ready.cover.promise,
|
||||
this.ready.toc.promise
|
||||
];
|
||||
this.pageListReady = this.ready.pageList.promise;
|
||||
|
||||
this.ready.all = RSVP.all(this.readyPromises);
|
||||
|
||||
|
@ -1936,7 +1938,7 @@ EPUBJS.Book.prototype.open = function(bookPath, forceReload){
|
|||
if(!this.settings.stored) opened.then(book.storeOffline());
|
||||
}
|
||||
|
||||
this._registerReplacements();
|
||||
this._registerReplacements(this.renderer);
|
||||
|
||||
return opened.promise;
|
||||
|
||||
|
@ -2014,6 +2016,21 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
}, function(error) {
|
||||
book.ready.toc.resolve(false);
|
||||
});
|
||||
|
||||
// Load the optional pageList
|
||||
book.loadXml(book.settings.navUrl).
|
||||
then(function(navHtml){
|
||||
return parse.pageList(navHtml, book.spineIndexByURL, book.spine);
|
||||
}).then(function(pageList){
|
||||
book.pageList = book.contents.pageList = pageList;
|
||||
book.pagination = new EPUBJS.Pagination();
|
||||
if(pageList.length) {
|
||||
book.pagination.process(book.pageList);
|
||||
book.ready.pageList.resolve(book.pageList);
|
||||
}
|
||||
}, function(error) {
|
||||
// book.ready.pageList.resolve(false);
|
||||
});
|
||||
} else if(book.contents.tocPath) {
|
||||
book.settings.tocUrl = book.settings.contentsPath + book.contents.tocPath;
|
||||
|
||||
|
@ -2033,6 +2050,106 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.createHiddenRender = function(renderer, _width, _height) {
|
||||
var box = this.element.getBoundingClientRect();
|
||||
var width = _width || this.settings.width || box.width;
|
||||
var height = _height || this.settings.height || box.height;
|
||||
var hiddenEl;
|
||||
|
||||
renderer.setMinSpreadWidth(this.settings.minSpreadWidth);
|
||||
this._registerReplacements(renderer);
|
||||
|
||||
hiddenEl = document.createElement("div");
|
||||
hiddenEl.style.visibility = "hidden";
|
||||
this.element.appendChild(hiddenEl);
|
||||
|
||||
renderer.initialize(hiddenEl, width, height);
|
||||
return hiddenEl;
|
||||
};
|
||||
|
||||
// Generates the pageList array by loading every chapter and paging through them
|
||||
EPUBJS.Book.prototype.generatePageList = function(width, height){
|
||||
var pageList = [];
|
||||
var pager = new EPUBJS.Renderer(this.settings.render_method);
|
||||
var hiddenElement = this.createHiddenRender(pager, width, height);
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var totalPages = 0;
|
||||
var currentPage = 1;
|
||||
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);
|
||||
|
||||
pager.displayChapter(chapter, this.globalLayoutProperties).then(function(){
|
||||
var nextPage = pager.nextPage();
|
||||
currentPage += 1;
|
||||
// Page though the entire chapter
|
||||
while (nextPage) {
|
||||
nextPage = pager.nextPage();
|
||||
}
|
||||
// Load up the next chapter
|
||||
nextChapter(done);
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
pager.remove();
|
||||
this.element.removeChild(hiddenElement);
|
||||
deferred.resolve(pageList);
|
||||
}.bind(this));
|
||||
|
||||
pager.on("renderer:locationChanged", function(cfi){
|
||||
pageList.push({
|
||||
"cfi" : cfi,
|
||||
"page" : currentPage
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
// Render out entire book and generate the pagination
|
||||
// Width and Height are optional and will default to the current dimensions
|
||||
EPUBJS.Book.prototype.generatePagination = function(width, height) {
|
||||
var book = this;
|
||||
var pageListReady;
|
||||
|
||||
this.ready.spine.promise.then(function(){
|
||||
pageListReady = book.generatePageList(width, height).then(function(pageList){
|
||||
book.pageList = book.contents.pageList = pageList;
|
||||
book.pagination.process(pageList);
|
||||
book.ready.pageList.resolve(book.pageList);
|
||||
});
|
||||
});
|
||||
return pageListReady;
|
||||
};
|
||||
|
||||
// Process the pagination from a JSON array containing the pagelist
|
||||
EPUBJS.Book.prototype.loadPagination = function(pagelistJSON) {
|
||||
var pageList = JSON.parse(jsonArray);
|
||||
if(pageList && pageList.length) {
|
||||
this.pageList = this.contents.pageList = pageList;
|
||||
this.pagination.process(this.pageList);
|
||||
this.ready.pageList.resolve(this.pageList);
|
||||
}
|
||||
return this.pageList;
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.getPageList = function() {
|
||||
return this.ready.pageList.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.getMetadata = function() {
|
||||
return this.ready.metadata.promise;
|
||||
};
|
||||
|
@ -2067,6 +2184,19 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
book.trigger(eventName, e);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
renderer.on("renderer:locationChanged", function(cfi) {
|
||||
var page, percent;
|
||||
if(this.pageList.length > 0) {
|
||||
page = this.pagination.pageFromCfi(cfi);
|
||||
percent = this.pagination.percentageFromPage(page);
|
||||
this.trigger("book:pageChanged", {
|
||||
"page": page,
|
||||
"percentage": percent
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.unlistenToRenderer = function(renderer){
|
||||
|
@ -2612,14 +2742,14 @@ EPUBJS.Book.prototype.applyHeadTags = function(callback){
|
|||
callback();
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype._registerReplacements = function(){
|
||||
this.renderer.registerHook("beforeChapterDisplay", this.applyStyles.bind(this), true);
|
||||
this.renderer.registerHook("beforeChapterDisplay", this.applyHeadTags.bind(this), true);
|
||||
this.renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs, true);
|
||||
EPUBJS.Book.prototype._registerReplacements = function(renderer){
|
||||
renderer.registerHook("beforeChapterDisplay", this.applyStyles.bind(this), true);
|
||||
renderer.registerHook("beforeChapterDisplay", this.applyHeadTags.bind(this), true);
|
||||
renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs, true);
|
||||
|
||||
if(this._needsAssetReplacement()) {
|
||||
|
||||
this.renderer.registerHook("beforeChapterDisplay", [
|
||||
renderer.registerHook("beforeChapterDisplay", [
|
||||
EPUBJS.replace.head,
|
||||
EPUBJS.replace.resources,
|
||||
EPUBJS.replace.svg
|
||||
|
@ -3056,6 +3186,36 @@ EPUBJS.core.uuid = function() {
|
|||
});
|
||||
return uuid;
|
||||
};
|
||||
|
||||
// Fast quicksort insert for sorted array -- based on:
|
||||
// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers
|
||||
EPUBJS.core.insert = function(item, array, compareFunction) {
|
||||
var location = EPUBJS.core.locationOf(item, array, compareFunction);
|
||||
array.splice(location+1, 0, item);
|
||||
|
||||
return location+1;
|
||||
};
|
||||
|
||||
EPUBJS.core.locationOf = function(item, array, compareFunction, _start, _end) {
|
||||
var start = _start || 0;
|
||||
var end = _end || array.length;
|
||||
var pivot = parseInt(start + (end - start) / 2);
|
||||
if(!compareFunction){
|
||||
compareFunction = function(a, b) {
|
||||
if(a > b) return 1;
|
||||
if(a < b) return -1;
|
||||
if(a = b) return 0;
|
||||
};
|
||||
}
|
||||
if(end-start <= 1 || compareFunction(array[pivot], item) === 0) {
|
||||
return pivot;
|
||||
}
|
||||
if(compareFunction(array[pivot], item) === -1) {
|
||||
return EPUBJS.core.locationOf(item, array, compareFunction, pivot, end);
|
||||
} else{
|
||||
return EPUBJS.core.locationOf(item, array, compareFunction, start, pivot);
|
||||
}
|
||||
};
|
||||
EPUBJS.EpubCFI = function(cfiStr){
|
||||
if(cfiStr) return this.parse(cfiStr);
|
||||
};
|
||||
|
@ -3098,7 +3258,7 @@ EPUBJS.EpubCFI.prototype.generateCfiFromElement = function(element, chapter) {
|
|||
var steps = this.pathTo(element);
|
||||
var path = this.generatePathComponent(steps);
|
||||
|
||||
return "epubcfi(" + chapter + "!" + path + ")";
|
||||
return "epubcfi(" + chapter + "!" + path + "/1:0)";
|
||||
};
|
||||
|
||||
EPUBJS.EpubCFI.prototype.pathTo = function(node) {
|
||||
|
@ -3279,10 +3439,10 @@ EPUBJS.EpubCFI.prototype.getElement = function(cfi, _doc) {
|
|||
|
||||
EPUBJS.EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
|
||||
if(typeof cfiOne === 'string') {
|
||||
cfiOne = this.parse(cfiOne);
|
||||
cfiOne = new EPUBJS.EpubCFI(cfiOne);
|
||||
}
|
||||
if(typeof cfiTwo === 'string') {
|
||||
cfiTwo = this.parse(cfiTwo);
|
||||
cfiTwo = new EPUBJS.EpubCFI(cfiTwo);
|
||||
}
|
||||
// Compare Spine Positions
|
||||
if(cfiOne.spinePos > cfiTwo.spinePos) {
|
||||
|
@ -3440,6 +3600,11 @@ EPUBJS.Hooks = (function(){
|
|||
hooks = this.hooks[type];
|
||||
|
||||
count = hooks.length;
|
||||
|
||||
if(count === 0 && callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
function countdown(){
|
||||
count--;
|
||||
if(count <= 0 && callback) callback();
|
||||
|
@ -3500,7 +3665,6 @@ EPUBJS.Layout.Reflowable.prototype.format = function(documentElement, _width, _h
|
|||
documentElement.style[columnWidth] = width+"px";
|
||||
|
||||
documentElement.style.width = width + "px";
|
||||
|
||||
return {
|
||||
pageWidth : this.spreadWidth,
|
||||
pageHeight : _height
|
||||
|
@ -3512,7 +3676,7 @@ EPUBJS.Layout.Reflowable.prototype.calculatePages = function() {
|
|||
this.documentElement.style.width = "auto"; //-- reset width for calculations
|
||||
totalWidth = this.documentElement.scrollWidth;
|
||||
displayedPages = Math.round(totalWidth / this.spreadWidth);
|
||||
|
||||
// console.log(totalWidth, this.spreadWidth)
|
||||
return {
|
||||
displayedPages : displayedPages,
|
||||
pageCount : displayedPages
|
||||
|
@ -3628,11 +3792,83 @@ EPUBJS.Layout.Fixed.prototype.calculatePages = function(){
|
|||
pageCount : 1
|
||||
};
|
||||
};
|
||||
EPUBJS.Navigation = function() {
|
||||
EPUBJS.Pagination = function(pageList) {
|
||||
this.pageList = pageList;
|
||||
this.pages = [];
|
||||
this.locations = [];
|
||||
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
};
|
||||
|
||||
// percentage at cfi, nearest page to Cfi, total pages and goto page.
|
||||
EPUBJS.Pagination.prototype.process = function(pageList){
|
||||
pageList.forEach(function(item){
|
||||
this.pages.push(item.page);
|
||||
this.locations.push(item.cfi);
|
||||
}, this);
|
||||
|
||||
this.firstPage = parseInt(this.pages[0]);
|
||||
this.lastPage = parseInt(this.pages[this.pages.length-1]);
|
||||
this.totalPages = this.lastPage - this.firstPage;
|
||||
};
|
||||
|
||||
EPUBJS.Pagination.prototype.pageFromCfi = function(cfi){
|
||||
var pg;
|
||||
// check if the cfi is in the location list
|
||||
var index = this.locations.indexOf(cfi);
|
||||
if(index != -1 && index < (this.pages.length-1) ) {
|
||||
pg = this.pages[index];
|
||||
} else {
|
||||
// Otherwise add it to the list of locations
|
||||
// Insert it in the correct position in the locations page
|
||||
index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare);
|
||||
// Get the page at the location just before the new one
|
||||
pg = this.pages[index-1];
|
||||
// Add the new page in so that the locations and page array match up
|
||||
this.pages.splice(index, 0, pg);
|
||||
}
|
||||
|
||||
return pg;
|
||||
};
|
||||
|
||||
EPUBJS.Pagination.prototype.cfiFromPage = function(pg){
|
||||
var cfi;
|
||||
// check if the cfi is in the page list
|
||||
var index = this.pages.indexOf(pg);
|
||||
if(index != -1) {
|
||||
cfi = this.locations[index];
|
||||
}
|
||||
// TODO: handle pages not in the list
|
||||
return cfi;
|
||||
};
|
||||
|
||||
EPUBJS.Pagination.prototype.pageFromPercentage = function(percent){
|
||||
var pg = Math.round(this.totalPages * percent);
|
||||
return pg;
|
||||
};
|
||||
|
||||
// Returns a value between 0 - 1 corresponding to the location of a page
|
||||
EPUBJS.Pagination.prototype.percentageFromPage = function(pg){
|
||||
var percentage = (pg - this.firstPage) / this.totalPages;
|
||||
return Math.round(percentage * 100) / 100;
|
||||
};
|
||||
|
||||
// Returns a value between 0 - 1 corresponding to the location of a cfi
|
||||
EPUBJS.Pagination.prototype.percentageFromCfi = function(cfi){
|
||||
var pg = this.pageFromCfi(cfi);
|
||||
var percentage = this.percentageFromPage(pg);
|
||||
return percentage;
|
||||
};
|
||||
|
||||
// TODO: move these
|
||||
EPUBJS.Book.prototype.gotoPage = function(pg){
|
||||
var cfi = this.pagination.cfiFromPage(pg);
|
||||
this.gotoCfi(cfi);
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.gotoPercentage = function(percent){
|
||||
var pg = this.pagination.pageFromPercentage(percent);
|
||||
this.gotoCfi(pg);
|
||||
};
|
||||
|
||||
EPUBJS.Parser = function(baseUrl){
|
||||
this.baseUrl = baseUrl || '';
|
||||
|
@ -3876,7 +4112,7 @@ EPUBJS.Parser.prototype.spine = function(spineXml, manifest){
|
|||
};
|
||||
|
||||
EPUBJS.Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navEl = navHtml.querySelector('nav'), //-- [*|type="toc"] * Doesn't seem to work
|
||||
var navEl = navHtml.querySelector('nav[*|type="toc"]'), //-- [*|type="toc"] * Doesn't seem to work
|
||||
idCounter = 0;
|
||||
|
||||
if(!navEl) return [];
|
||||
|
@ -4009,6 +4245,78 @@ EPUBJS.Parser.prototype.toc = function(tocXml, spineIndexByURL, bookSpine){
|
|||
|
||||
return getTOC(navMap);
|
||||
};
|
||||
|
||||
EPUBJS.Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navEl = navHtml.querySelector('nav[*|type="page-list"]'),
|
||||
idCounter = 0;
|
||||
|
||||
if(!navEl) return [];
|
||||
|
||||
// Implements `> ol > li`
|
||||
function findListItems(parent){
|
||||
var items = [];
|
||||
|
||||
Array.prototype.slice.call(parent.childNodes).forEach(function(node){
|
||||
if('ol' == node.tagName){
|
||||
Array.prototype.slice.call(node.childNodes).forEach(function(item){
|
||||
if('li' == item.tagName){
|
||||
items.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return items;
|
||||
|
||||
}
|
||||
|
||||
// Implements `> a, > span`
|
||||
function findAnchorOrSpan(parent){
|
||||
var item = null;
|
||||
|
||||
Array.prototype.slice.call(parent.childNodes).forEach(function(node){
|
||||
if('a' == node.tagName || 'span' == node.tagName){
|
||||
item = node;
|
||||
}
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
function getPages(parent){
|
||||
var list = [],
|
||||
nodes = findListItems(parent),
|
||||
items = Array.prototype.slice.call(nodes),
|
||||
length = items.length,
|
||||
node;
|
||||
|
||||
if(length === 0) return false;
|
||||
|
||||
items.forEach(function(item){
|
||||
var id = item.getAttribute('id') || false,
|
||||
content = findAnchorOrSpan(item),
|
||||
href = content.getAttribute('href') || '',
|
||||
text = content.textContent || "",
|
||||
split = href.split("#"),
|
||||
packageUrl = split[0],
|
||||
cfi = split.length > 1 ? split[1] : false;
|
||||
|
||||
if(cfi) {
|
||||
list.push({
|
||||
"cfi" : cfi,
|
||||
"packageUrl" : packageUrl,
|
||||
"page" : text
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return getPages(navEl);
|
||||
};
|
||||
|
||||
EPUBJS.Render.Iframe = function() {
|
||||
this.iframe = null;
|
||||
this.document = null;
|
||||
|
@ -4023,7 +4331,7 @@ EPUBJS.Render.Iframe = function() {
|
|||
//-- Build up any html needed
|
||||
EPUBJS.Render.Iframe.prototype.create = function(){
|
||||
this.iframe = document.createElement('iframe');
|
||||
this.iframe.id = "epubjs-iframe";
|
||||
this.iframe.id = "epubjs-iframe:" + EPUBJS.core.uuid();
|
||||
this.iframe.scrolling = "no";
|
||||
|
||||
return this.iframe;
|
||||
|
@ -4087,8 +4395,9 @@ EPUBJS.Render.Iframe.prototype.resize = function(width, height){
|
|||
|
||||
this.iframe.width = width;
|
||||
// Get the fractional height and width of the iframe
|
||||
this.width = this.iframe.getBoundingClientRect().width;
|
||||
this.height = this.iframe.getBoundingClientRect().height;
|
||||
// Default to orginal if bounding rect is 0
|
||||
this.width = this.iframe.getBoundingClientRect().width || width;
|
||||
this.height = this.iframe.getBoundingClientRect().height || height;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4240,7 +4549,7 @@ EPUBJS.Renderer.prototype.Events = [
|
|||
"renderer:selected",
|
||||
"renderer:chapterUnloaded",
|
||||
"renderer:chapterDisplayed",
|
||||
"renderer:pageChanged",
|
||||
"renderer:locationChanged",
|
||||
"renderer:resized",
|
||||
"renderer:spreads"
|
||||
];
|
||||
|
@ -4342,12 +4651,12 @@ EPUBJS.Renderer.prototype.load = function(url){
|
|||
var pages = this.layout.calculatePages();
|
||||
var msg = this.currentChapter;
|
||||
|
||||
this.updatePages(pages);
|
||||
|
||||
msg.cfi = this.currentLocationCfi = this.getPageCfi();
|
||||
|
||||
this.trigger("renderer:chapterDisplayed", msg);
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
|
||||
this.updatePages(pages);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
this.visible(true);
|
||||
|
||||
|
@ -4477,7 +4786,7 @@ EPUBJS.Renderer.prototype.visible = function(bool){
|
|||
|
||||
// Remove the render element and clean up listeners
|
||||
EPUBJS.Renderer.prototype.remove = function() {
|
||||
if(this.renderer.window) {
|
||||
if(this.render.window) {
|
||||
this.render.unload();
|
||||
this.render.window.removeEventListener("resize", this.resized);
|
||||
this.removeEventListeners();
|
||||
|
@ -4519,7 +4828,7 @@ EPUBJS.Renderer.prototype.page = function(pg){
|
|||
this.render.page(pg);
|
||||
|
||||
this.currentLocationCfi = this.getPageCfi();
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -4536,7 +4845,7 @@ EPUBJS.Renderer.prototype.nextPage = function(){
|
|||
this.render.page(pg);
|
||||
|
||||
this.currentLocationCfi = this.getPageCfi(this.visibileEl);
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -381,7 +381,7 @@ EPUBJS.reader.ControlsController = function(book) {
|
|||
|
||||
});
|
||||
|
||||
book.on('renderer:pageChanged', function(cfi){
|
||||
book.on('renderer:locationChanged', function(cfi){
|
||||
//-- Check if bookmarked
|
||||
var bookmarked = reader.isBookmarked(cfi);
|
||||
if(bookmarked === -1) { //-- Not bookmarked
|
||||
|
@ -396,6 +396,10 @@ EPUBJS.reader.ControlsController = function(book) {
|
|||
|
||||
});
|
||||
|
||||
book.on('book:pageChanged', function(location){
|
||||
console.log("page", location.page, location.percentage)
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
};
|
||||
|
|
|
@ -106,7 +106,7 @@ body {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
#viewer #epubjs-iframe {
|
||||
#viewer iframe {
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
@ -663,28 +663,28 @@ input:-moz-placeholder {
|
|||
|
||||
/* For iPad portrait layouts only */
|
||||
@media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: portrait) {
|
||||
#viewer #epubjs-iframe {
|
||||
#viewer iframe {
|
||||
width: 460px;
|
||||
height: 740px;
|
||||
}
|
||||
}
|
||||
/*For iPad landscape layouts only */
|
||||
@media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: landscape) {
|
||||
#viewer #epubjs-iframe {
|
||||
#viewer iframe {
|
||||
width: 460px;
|
||||
height: 415px;
|
||||
}
|
||||
}
|
||||
/* For iPhone portrait layouts only */
|
||||
@media only screen and (max-device-width: 480px) and (orientation: portrait) {
|
||||
#viewer #epubjs-iframe {
|
||||
#viewer iframe {
|
||||
width: 256px;
|
||||
height: 368px;
|
||||
}
|
||||
}
|
||||
/* For iPhone landscape layouts only */
|
||||
@media only screen and (max-device-width: 480px) and (orientation: landscape) {
|
||||
#viewer #epubjs-iframe {
|
||||
#viewer iframe {
|
||||
width: 256px;
|
||||
height: 124px;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
EPUBJS.cssPath = "css/";
|
||||
// fileStorage.filePath = EPUBJS.filePath;
|
||||
|
||||
window.Reader = ePubReader("moby-dick/", { reload: true });
|
||||
window.Reader = ePubReader("../books/georgia-cfi-20120521/", { reload: true });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -58,6 +58,7 @@
|
|||
<script src="../src/epubcfi.js"></script>
|
||||
<script src="../src/render_iframe.js"></script>
|
||||
<script src="../src/layout.js"></script>
|
||||
<script src="../src/pagination.js"></script>
|
||||
|
||||
<!-- Hooks -->
|
||||
<script async src="../hooks/default/transculsions.js"></script>
|
||||
|
|
6
demo/js/epub.min.js
vendored
6
demo/js/epub.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/js/reader.min.js
vendored
2
demo/js/reader.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -79,7 +79,7 @@ EPUBJS.reader.ControlsController = function(book) {
|
|||
|
||||
});
|
||||
|
||||
book.on('renderer:pageChanged', function(cfi){
|
||||
book.on('renderer:locationChanged', function(cfi){
|
||||
//-- Check if bookmarked
|
||||
var bookmarked = reader.isBookmarked(cfi);
|
||||
if(bookmarked === -1) { //-- Not bookmarked
|
||||
|
@ -94,6 +94,10 @@ EPUBJS.reader.ControlsController = function(book) {
|
|||
|
||||
});
|
||||
|
||||
book.on('book:pageChanged', function(location){
|
||||
console.log("page", location.page, location.percentage)
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
};
|
||||
|
|
144
src/book.js
144
src/book.js
|
@ -63,7 +63,8 @@ EPUBJS.Book = function(options){
|
|||
spine: new RSVP.defer(),
|
||||
metadata: new RSVP.defer(),
|
||||
cover: new RSVP.defer(),
|
||||
toc: new RSVP.defer()
|
||||
toc: new RSVP.defer(),
|
||||
pageList: new RSVP.defer()
|
||||
};
|
||||
|
||||
this.readyPromises = [
|
||||
|
@ -73,6 +74,7 @@ EPUBJS.Book = function(options){
|
|||
this.ready.cover.promise,
|
||||
this.ready.toc.promise
|
||||
];
|
||||
this.pageListReady = this.ready.pageList.promise;
|
||||
|
||||
this.ready.all = RSVP.all(this.readyPromises);
|
||||
|
||||
|
@ -161,7 +163,7 @@ EPUBJS.Book.prototype.open = function(bookPath, forceReload){
|
|||
if(!this.settings.stored) opened.then(book.storeOffline());
|
||||
}
|
||||
|
||||
this._registerReplacements();
|
||||
this._registerReplacements(this.renderer);
|
||||
|
||||
return opened.promise;
|
||||
|
||||
|
@ -239,6 +241,21 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
}, function(error) {
|
||||
book.ready.toc.resolve(false);
|
||||
});
|
||||
|
||||
// Load the optional pageList
|
||||
book.loadXml(book.settings.navUrl).
|
||||
then(function(navHtml){
|
||||
return parse.pageList(navHtml, book.spineIndexByURL, book.spine);
|
||||
}).then(function(pageList){
|
||||
book.pageList = book.contents.pageList = pageList;
|
||||
book.pagination = new EPUBJS.Pagination();
|
||||
if(pageList.length) {
|
||||
book.pagination.process(book.pageList);
|
||||
book.ready.pageList.resolve(book.pageList);
|
||||
}
|
||||
}, function(error) {
|
||||
// book.ready.pageList.resolve(false);
|
||||
});
|
||||
} else if(book.contents.tocPath) {
|
||||
book.settings.tocUrl = book.settings.contentsPath + book.contents.tocPath;
|
||||
|
||||
|
@ -258,6 +275,106 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
|
|||
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.createHiddenRender = function(renderer, _width, _height) {
|
||||
var box = this.element.getBoundingClientRect();
|
||||
var width = _width || this.settings.width || box.width;
|
||||
var height = _height || this.settings.height || box.height;
|
||||
var hiddenEl;
|
||||
|
||||
renderer.setMinSpreadWidth(this.settings.minSpreadWidth);
|
||||
this._registerReplacements(renderer);
|
||||
|
||||
hiddenEl = document.createElement("div");
|
||||
hiddenEl.style.visibility = "hidden";
|
||||
this.element.appendChild(hiddenEl);
|
||||
|
||||
renderer.initialize(hiddenEl, width, height);
|
||||
return hiddenEl;
|
||||
};
|
||||
|
||||
// Generates the pageList array by loading every chapter and paging through them
|
||||
EPUBJS.Book.prototype.generatePageList = function(width, height){
|
||||
var pageList = [];
|
||||
var pager = new EPUBJS.Renderer(this.settings.render_method);
|
||||
var hiddenElement = this.createHiddenRender(pager, width, height);
|
||||
var deferred = new RSVP.defer();
|
||||
var spinePos = -1;
|
||||
var spineLength = this.spine.length;
|
||||
var totalPages = 0;
|
||||
var currentPage = 1;
|
||||
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);
|
||||
|
||||
pager.displayChapter(chapter, this.globalLayoutProperties).then(function(){
|
||||
var nextPage = pager.nextPage();
|
||||
currentPage += 1;
|
||||
// Page though the entire chapter
|
||||
while (nextPage) {
|
||||
nextPage = pager.nextPage();
|
||||
}
|
||||
// Load up the next chapter
|
||||
nextChapter(done);
|
||||
});
|
||||
}
|
||||
return done.promise;
|
||||
}.bind(this);
|
||||
|
||||
var finished = nextChapter().then(function(){
|
||||
pager.remove();
|
||||
this.element.removeChild(hiddenElement);
|
||||
deferred.resolve(pageList);
|
||||
}.bind(this));
|
||||
|
||||
pager.on("renderer:locationChanged", function(cfi){
|
||||
pageList.push({
|
||||
"cfi" : cfi,
|
||||
"page" : currentPage
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
// Render out entire book and generate the pagination
|
||||
// Width and Height are optional and will default to the current dimensions
|
||||
EPUBJS.Book.prototype.generatePagination = function(width, height) {
|
||||
var book = this;
|
||||
var pageListReady;
|
||||
|
||||
this.ready.spine.promise.then(function(){
|
||||
pageListReady = book.generatePageList(width, height).then(function(pageList){
|
||||
book.pageList = book.contents.pageList = pageList;
|
||||
book.pagination.process(pageList);
|
||||
book.ready.pageList.resolve(book.pageList);
|
||||
});
|
||||
});
|
||||
return pageListReady;
|
||||
};
|
||||
|
||||
// Process the pagination from a JSON array containing the pagelist
|
||||
EPUBJS.Book.prototype.loadPagination = function(pagelistJSON) {
|
||||
var pageList = JSON.parse(jsonArray);
|
||||
if(pageList && pageList.length) {
|
||||
this.pageList = this.contents.pageList = pageList;
|
||||
this.pagination.process(this.pageList);
|
||||
this.ready.pageList.resolve(this.pageList);
|
||||
}
|
||||
return this.pageList;
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.getPageList = function() {
|
||||
return this.ready.pageList.promise;
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.getMetadata = function() {
|
||||
return this.ready.metadata.promise;
|
||||
};
|
||||
|
@ -292,6 +409,19 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
|
|||
book.trigger(eventName, e);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
renderer.on("renderer:locationChanged", function(cfi) {
|
||||
var page, percent;
|
||||
if(this.pageList.length > 0) {
|
||||
page = this.pagination.pageFromCfi(cfi);
|
||||
percent = this.pagination.percentageFromPage(page);
|
||||
this.trigger("book:pageChanged", {
|
||||
"page": page,
|
||||
"percentage": percent
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype.unlistenToRenderer = function(renderer){
|
||||
|
@ -837,14 +967,14 @@ EPUBJS.Book.prototype.applyHeadTags = function(callback){
|
|||
callback();
|
||||
};
|
||||
|
||||
EPUBJS.Book.prototype._registerReplacements = function(){
|
||||
this.renderer.registerHook("beforeChapterDisplay", this.applyStyles.bind(this), true);
|
||||
this.renderer.registerHook("beforeChapterDisplay", this.applyHeadTags.bind(this), true);
|
||||
this.renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs, true);
|
||||
EPUBJS.Book.prototype._registerReplacements = function(renderer){
|
||||
renderer.registerHook("beforeChapterDisplay", this.applyStyles.bind(this), true);
|
||||
renderer.registerHook("beforeChapterDisplay", this.applyHeadTags.bind(this), true);
|
||||
renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs, true);
|
||||
|
||||
if(this._needsAssetReplacement()) {
|
||||
|
||||
this.renderer.registerHook("beforeChapterDisplay", [
|
||||
renderer.registerHook("beforeChapterDisplay", [
|
||||
EPUBJS.replace.head,
|
||||
EPUBJS.replace.resources,
|
||||
EPUBJS.replace.svg
|
||||
|
|
30
src/core.js
30
src/core.js
|
@ -314,3 +314,33 @@ EPUBJS.core.uuid = function() {
|
|||
});
|
||||
return uuid;
|
||||
};
|
||||
|
||||
// Fast quicksort insert for sorted array -- based on:
|
||||
// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers
|
||||
EPUBJS.core.insert = function(item, array, compareFunction) {
|
||||
var location = EPUBJS.core.locationOf(item, array, compareFunction);
|
||||
array.splice(location+1, 0, item);
|
||||
|
||||
return location+1;
|
||||
};
|
||||
|
||||
EPUBJS.core.locationOf = function(item, array, compareFunction, _start, _end) {
|
||||
var start = _start || 0;
|
||||
var end = _end || array.length;
|
||||
var pivot = parseInt(start + (end - start) / 2);
|
||||
if(!compareFunction){
|
||||
compareFunction = function(a, b) {
|
||||
if(a > b) return 1;
|
||||
if(a < b) return -1;
|
||||
if(a = b) return 0;
|
||||
};
|
||||
}
|
||||
if(end-start <= 1 || compareFunction(array[pivot], item) === 0) {
|
||||
return pivot;
|
||||
}
|
||||
if(compareFunction(array[pivot], item) === -1) {
|
||||
return EPUBJS.core.locationOf(item, array, compareFunction, pivot, end);
|
||||
} else{
|
||||
return EPUBJS.core.locationOf(item, array, compareFunction, start, pivot);
|
||||
}
|
||||
};
|
|
@ -40,7 +40,7 @@ EPUBJS.EpubCFI.prototype.generateCfiFromElement = function(element, chapter) {
|
|||
var steps = this.pathTo(element);
|
||||
var path = this.generatePathComponent(steps);
|
||||
|
||||
return "epubcfi(" + chapter + "!" + path + ")";
|
||||
return "epubcfi(" + chapter + "!" + path + "/1:0)";
|
||||
};
|
||||
|
||||
EPUBJS.EpubCFI.prototype.pathTo = function(node) {
|
||||
|
@ -221,10 +221,10 @@ EPUBJS.EpubCFI.prototype.getElement = function(cfi, _doc) {
|
|||
|
||||
EPUBJS.EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
|
||||
if(typeof cfiOne === 'string') {
|
||||
cfiOne = this.parse(cfiOne);
|
||||
cfiOne = new EPUBJS.EpubCFI(cfiOne);
|
||||
}
|
||||
if(typeof cfiTwo === 'string') {
|
||||
cfiTwo = this.parse(cfiTwo);
|
||||
cfiTwo = new EPUBJS.EpubCFI(cfiTwo);
|
||||
}
|
||||
// Compare Spine Positions
|
||||
if(cfiOne.spinePos > cfiTwo.spinePos) {
|
||||
|
|
|
@ -54,6 +54,11 @@ EPUBJS.Hooks = (function(){
|
|||
hooks = this.hooks[type];
|
||||
|
||||
count = hooks.length;
|
||||
|
||||
if(count === 0 && callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
function countdown(){
|
||||
count--;
|
||||
if(count <= 0 && callback) callback();
|
||||
|
|
|
@ -33,7 +33,6 @@ EPUBJS.Layout.Reflowable.prototype.format = function(documentElement, _width, _h
|
|||
documentElement.style[columnWidth] = width+"px";
|
||||
|
||||
documentElement.style.width = width + "px";
|
||||
|
||||
return {
|
||||
pageWidth : this.spreadWidth,
|
||||
pageHeight : _height
|
||||
|
@ -45,7 +44,7 @@ EPUBJS.Layout.Reflowable.prototype.calculatePages = function() {
|
|||
this.documentElement.style.width = "auto"; //-- reset width for calculations
|
||||
totalWidth = this.documentElement.scrollWidth;
|
||||
displayedPages = Math.round(totalWidth / this.spreadWidth);
|
||||
|
||||
// console.log(totalWidth, this.spreadWidth)
|
||||
return {
|
||||
displayedPages : displayedPages,
|
||||
pageCount : displayedPages
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
EPUBJS.Navigation = function() {
|
||||
|
||||
};
|
||||
|
||||
// percentage at cfi, nearest page to Cfi, total pages and goto page.
|
|
@ -240,7 +240,7 @@ EPUBJS.Parser.prototype.spine = function(spineXml, manifest){
|
|||
};
|
||||
|
||||
EPUBJS.Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navEl = navHtml.querySelector('nav'), //-- [*|type="toc"] * Doesn't seem to work
|
||||
var navEl = navHtml.querySelector('nav[*|type="toc"]'), //-- [*|type="toc"] * Doesn't seem to work
|
||||
idCounter = 0;
|
||||
|
||||
if(!navEl) return [];
|
||||
|
@ -373,3 +373,74 @@ EPUBJS.Parser.prototype.toc = function(tocXml, spineIndexByURL, bookSpine){
|
|||
|
||||
return getTOC(navMap);
|
||||
};
|
||||
|
||||
EPUBJS.Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navEl = navHtml.querySelector('nav[*|type="page-list"]'),
|
||||
idCounter = 0;
|
||||
|
||||
if(!navEl) return [];
|
||||
|
||||
// Implements `> ol > li`
|
||||
function findListItems(parent){
|
||||
var items = [];
|
||||
|
||||
Array.prototype.slice.call(parent.childNodes).forEach(function(node){
|
||||
if('ol' == node.tagName){
|
||||
Array.prototype.slice.call(node.childNodes).forEach(function(item){
|
||||
if('li' == item.tagName){
|
||||
items.push(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return items;
|
||||
|
||||
}
|
||||
|
||||
// Implements `> a, > span`
|
||||
function findAnchorOrSpan(parent){
|
||||
var item = null;
|
||||
|
||||
Array.prototype.slice.call(parent.childNodes).forEach(function(node){
|
||||
if('a' == node.tagName || 'span' == node.tagName){
|
||||
item = node;
|
||||
}
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
function getPages(parent){
|
||||
var list = [],
|
||||
nodes = findListItems(parent),
|
||||
items = Array.prototype.slice.call(nodes),
|
||||
length = items.length,
|
||||
node;
|
||||
|
||||
if(length === 0) return false;
|
||||
|
||||
items.forEach(function(item){
|
||||
var id = item.getAttribute('id') || false,
|
||||
content = findAnchorOrSpan(item),
|
||||
href = content.getAttribute('href') || '',
|
||||
text = content.textContent || "",
|
||||
split = href.split("#"),
|
||||
packageUrl = split[0],
|
||||
cfi = split.length > 1 ? split[1] : false;
|
||||
|
||||
if(cfi) {
|
||||
list.push({
|
||||
"cfi" : cfi,
|
||||
"packageUrl" : packageUrl,
|
||||
"page" : text
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
return getPages(navEl);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ EPUBJS.Render.Iframe = function() {
|
|||
//-- Build up any html needed
|
||||
EPUBJS.Render.Iframe.prototype.create = function(){
|
||||
this.iframe = document.createElement('iframe');
|
||||
this.iframe.id = "epubjs-iframe";
|
||||
this.iframe.id = "epubjs-iframe:" + EPUBJS.core.uuid();
|
||||
this.iframe.scrolling = "no";
|
||||
|
||||
return this.iframe;
|
||||
|
@ -76,8 +76,9 @@ EPUBJS.Render.Iframe.prototype.resize = function(width, height){
|
|||
|
||||
this.iframe.width = width;
|
||||
// Get the fractional height and width of the iframe
|
||||
this.width = this.iframe.getBoundingClientRect().width;
|
||||
this.height = this.iframe.getBoundingClientRect().height;
|
||||
// Default to orginal if bounding rect is 0
|
||||
this.width = this.iframe.getBoundingClientRect().width || width;
|
||||
this.height = this.iframe.getBoundingClientRect().height || height;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ EPUBJS.Renderer.prototype.Events = [
|
|||
"renderer:selected",
|
||||
"renderer:chapterUnloaded",
|
||||
"renderer:chapterDisplayed",
|
||||
"renderer:pageChanged",
|
||||
"renderer:locationChanged",
|
||||
"renderer:resized",
|
||||
"renderer:spreads"
|
||||
];
|
||||
|
@ -144,12 +144,12 @@ EPUBJS.Renderer.prototype.load = function(url){
|
|||
var pages = this.layout.calculatePages();
|
||||
var msg = this.currentChapter;
|
||||
|
||||
this.updatePages(pages);
|
||||
|
||||
msg.cfi = this.currentLocationCfi = this.getPageCfi();
|
||||
|
||||
this.trigger("renderer:chapterDisplayed", msg);
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
|
||||
this.updatePages(pages);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
this.visible(true);
|
||||
|
||||
|
@ -279,7 +279,7 @@ EPUBJS.Renderer.prototype.visible = function(bool){
|
|||
|
||||
// Remove the render element and clean up listeners
|
||||
EPUBJS.Renderer.prototype.remove = function() {
|
||||
if(this.renderer.window) {
|
||||
if(this.render.window) {
|
||||
this.render.unload();
|
||||
this.render.window.removeEventListener("resize", this.resized);
|
||||
this.removeEventListeners();
|
||||
|
@ -321,7 +321,7 @@ EPUBJS.Renderer.prototype.page = function(pg){
|
|||
this.render.page(pg);
|
||||
|
||||
this.currentLocationCfi = this.getPageCfi();
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ EPUBJS.Renderer.prototype.nextPage = function(){
|
|||
this.render.page(pg);
|
||||
|
||||
this.currentLocationCfi = this.getPageCfi(this.visibileEl);
|
||||
this.trigger("renderer:pageChanged", this.currentLocationCfi);
|
||||
this.trigger("renderer:locationChanged", this.currentLocationCfi);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<title>EPUB.js QUnit Tests</title>
|
||||
<link rel="stylesheet" href="qunit/qunit.css">
|
||||
|
||||
<script src="../libs/jquery/jquery-1.9.0.min.js"></script>
|
||||
<script src="../libs/jquery/jquery-2.0.3.js"></script>
|
||||
<script src="qunit/qunit.js"></script>
|
||||
|
||||
<script src="../demo/js/libs/zip.min.js"></script>
|
||||
|
@ -27,7 +27,14 @@
|
|||
<script src="../src/epubcfi.js"></script>
|
||||
<script src="../src/render_iframe.js"></script>
|
||||
<script src="../src/layout.js"></script>
|
||||
<script src="../src/pagination.js"></script>
|
||||
|
||||
<!-- Hooks
|
||||
<script async src="../hooks/default/transculsions.js"></script>
|
||||
<script async src="../hooks/default/endnotes.js"></script>
|
||||
<script async src="../hooks/default/smartimages.js"></script>
|
||||
<script async src="../hooks/default/mathml.js"></script>
|
||||
-->
|
||||
<script>
|
||||
|
||||
EPUBJS.filePath = "../demo/js/libs/";
|
||||
|
@ -42,6 +49,7 @@
|
|||
<script src="core.js"></script>
|
||||
<script src="render.js"></script>
|
||||
<script src="unarchiver.js"></script>
|
||||
<script src="pagination.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue