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

cfi update to exclude markers, back button loaded events

This commit is contained in:
fchasen 2014-02-05 12:17:49 -08:00
parent a544cd63de
commit 964ef192a6
13 changed files with 237 additions and 69 deletions

View file

@ -25,7 +25,7 @@
EPUBJS.cssPath = "css/";
// fileStorage.filePath = EPUBJS.filePath;
window.Reader = ePubReader("moby-dick/", { reload: true, generatePagination: true });
window.Reader = ePubReader("moby-dick/", { reload: true, generatePagination: false });
}
};

View file

@ -57,7 +57,7 @@
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
/* overflow: hidden; */
}
#area {
@ -108,9 +108,10 @@
width: 400px;
margin-left: -200px;
text-align: center;
display: none;
}
#controls > input {
#controls > input[type=range] {
width: 400px;
}
</style>
@ -118,7 +119,7 @@
<script>
"use strict";
var book = ePub("../demo/moby-dick/");
var book = ePub("../demo/moby-dick/", { width: 1076, height: 588 });
</script>
</head>
@ -127,23 +128,27 @@
<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"></div>
<div id="controls">
<input id="currentpg" size="3" maxlength="3"/> / <span id="totalpg">0</span>
</div>
</div>
<script>
var controls = document.getElementById("controls");
var currentPage = document.getElementById("currentpg");
var totalPages = document.getElementById("totalpg");
var slider = document.createElement("input");
var pageList;
var rendered = book.renderTo("area");
// Load in stored pageList from json or local storage
/*
EPUBJS.core.request("page_list.json").then(function(storedPageList){
pageList = storedPageList;
book.loadPagination(pageList);
});
*/
///*
// EPUBJS.core.request("page_list.json").then(function(storedPageList){
// pageList = storedPageList;
// book.loadPagination(pageList);
// });
// Or generate the pageList on the fly
book.ready.all.then(function(){
@ -152,13 +157,16 @@
// Wait for the pageList to be ready and then show slider
book.pageListReady.then(function(pageList){
controls.style.display = "block";
// console.log(JSON.stringify(pageList)); // Save the result
slider.setAttribute("type", "range");
slider.setAttribute("min", book.pagination.firstPage);
slider.setAttribute("max", book.pagination.lastPage);
slider.setAttribute("step", 1);
slider.setAttribute("value", 0);
slider.addEventListener("change", function(value){
console.log(slider.value)
book.gotoPage(slider.value);
}, false);
@ -167,13 +175,21 @@
var currentLocation = book.getCurrentLocationCfi();
var currentPage = book.pagination.pageFromCfi(currentLocation);
slider.value = currentPage;
currentPage.value = currentPage;
});
controls.appendChild(slider);
totalPages.innerText = book.pagination.totalPages;
currentPage.addEventListener("change", function(value){
console.log(currentPage.value)
book.gotoPage(currentPage.value);
}, false);
});
book.on('book:pageChanged', function(location){
slider.value = location.page;
currentPage.value = location.page;
});
</script>
</body>

View file

@ -75,6 +75,7 @@ EPUBJS.Book = function(options){
this.ready.toc.promise
];
this.pageList = [];
this.pagination = new EPUBJS.Pagination();
this.pageListReady = this.ready.pageList.promise;
@ -249,8 +250,8 @@ EPUBJS.Book.prototype.unpack = function(packageXml){
then(function(navHtml){
return parse.pageList(navHtml, book.spineIndexByURL, book.spine);
}).then(function(pageList){
book.pageList = book.contents.pageList = pageList;
if(pageList.length) {
book.pageList = book.contents.pageList = pageList;
book.pagination.process(book.pageList);
book.ready.pageList.resolve(book.pageList);
}
@ -287,6 +288,9 @@ EPUBJS.Book.prototype.createHiddenRender = function(renderer, _width, _height) {
hiddenEl = document.createElement("div");
hiddenEl.style.visibility = "hidden";
hiddenEl.style.overflow = "hidden";
hiddenEl.style.width = "0";
hiddenEl.style.height = "0";
this.element.appendChild(hiddenEl);
renderer.initialize(hiddenEl, width, height);
@ -314,8 +318,8 @@ EPUBJS.Book.prototype.generatePageList = function(width, height){
spinePos = next;
chapter = new EPUBJS.Chapter(this.spine[spinePos], this.store);
pager.displayChapter(chapter, this.globalLayoutProperties).then(function(){
var nextPage = pager.nextPage();
pager.displayChapter(chapter, this.globalLayoutProperties).then(function(chap){
var nextPage = true;//pager.nextPage();
// Page though the entire chapter
while (nextPage) {
nextPage = pager.nextPage();
@ -368,10 +372,7 @@ EPUBJS.Book.prototype.loadPagination = function(pagelistJSON) {
if(pageList && pageList.length) {
this.pageList = pageList;
this.pagination.process(this.pageList);
// Wait for book contents to load before resolving
this.ready.all.then(function(){
this.ready.pageList.resolve(this.pageList);
}.bind(this));
this.ready.pageList.resolve(this.pageList);
}
return this.pageList;
};
@ -425,8 +426,22 @@ EPUBJS.Book.prototype.listenToRenderer = function(renderer){
"page": page,
"percentage": percent
});
// TODO: Add event for first and last page.
// (though last is going to be hard, since it could be several reflowed pages long)
}
}.bind(this));
renderer.on("render:loaded", this.loadChange.bind(this));
};
// Listens for load events from the Renderer and checks against the current chapter
// Prevents the Render from loading a different chapter when back button is pressed
EPUBJS.Book.prototype.loadChange = function(url){
var uri = EPUBJS.core.uri(url);
if(this.currentChapter && uri.path != this.currentChapter.absolute){
this.goto(uri.filename);
}
};
EPUBJS.Book.prototype.unlistenToRenderer = function(renderer){
@ -975,7 +990,7 @@ EPUBJS.Book.prototype.applyHeadTags = function(callback){
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);
renderer.registerHook("beforeChapterDisplay", EPUBJS.replace.hrefs.bind(this), true);
if(this._needsAssetReplacement()) {

View file

@ -39,8 +39,13 @@ EPUBJS.EpubCFI.prototype.generatePathComponent = function(steps) {
EPUBJS.EpubCFI.prototype.generateCfiFromElement = function(element, chapter) {
var steps = this.pathTo(element);
var path = this.generatePathComponent(steps);
return "epubcfi(" + chapter + "!" + path + "/1:0)";
if(!path.length) {
// Start of Chapter
return "epubcfi(" + chapter + ")";
} else {
// First Text Node
return "epubcfi(" + chapter + "!" + path + "/1:0)";
}
};
EPUBJS.EpubCFI.prototype.pathTo = function(node) {
@ -96,18 +101,18 @@ EPUBJS.EpubCFI.prototype.parse = function(cfiStr) {
end,
text;
cfi.str = cfiStr;
if(cfiStr.indexOf("epubcfi(") === 0) {
// Remove intial epubcfi( and ending )
cfiStr = cfiStr.slice(8, cfiStr.length-1);
}
chapterComponent = this.getChapterComponent(cfiStr);
pathComponent = this.getPathComponent(cfiStr);
pathComponent = this.getPathComponent(cfiStr) || '';
charecterOffsetComponent = this.getCharecterOffsetComponent(cfiStr);
// Make sure this is a valid cfi or return
if(!chapterComponent.length || !pathComponent.length) {
if(!chapterComponent) {
return {spinePos: -1};
}
@ -181,18 +186,20 @@ EPUBJS.EpubCFI.prototype.getElement = function(cfi, _doc) {
cfi = this.parse(cfi);
}
sections = cfi.steps;
sections = cfi.steps.slice(0); // Clone steps array
while(sections && sections.length > 0) {
part = sections.shift();
// Wrap text elements in a span and return that new element
if(part.type === "text") {
text = element.childNodes[part.index];
element = doc.createElement('span');
element.id = "EPUBJS-CFI-MARKER:"+ EPUBJS.core.uuid();
element.classList.add("EPUBJS-CFI-MARKER");
if(cfi.characterOffset) {
// TODO: replace with text.splitText(cfi.characterOffset)
// https://developer.mozilla.org/en-US/docs/Web/API/Text.splitText
textBegin = doc.createTextNode(text.textContent.slice(0, cfi.characterOffset));
textEnd = doc.createTextNode(text.textContent.slice(cfi.characterOffset));
text.parentNode.insertBefore(textEnd, text);
@ -200,20 +207,32 @@ EPUBJS.EpubCFI.prototype.getElement = function(cfi, _doc) {
text.parentNode.insertBefore(textBegin, element);
text.parentNode.removeChild(text);
} else {
text.parentNode.insertBefore(element, text);
// If this is the first text node, just return the orginal element
if(part.index === 0){
element = text.parentNode;
} else {
text.parentNode.insertBefore(element, text);
}
}
// sort cut to find element by id
} else if(part.id){
element = doc.getElementById(part.id);
// find element in parent
}else{
if(!children) console.error("No Kids", element);
// if(!children.length) return console.error("No Kids", element);
element = children[part.index];
}
if(!element) console.error("No Element For", part, cfi);
if(!element) return console.error("No Element For", part, cfi, part.index, children, children[part.index]);
children = Array.prototype.slice.call(element.children);
// Remove EPUBJS-CFI-MARKER elements
children.forEach(function(child){
if(child.classList.contains("EPUBJS-CFI-MARKER")){
var index = children.indexOf(child);
children.splice(index, 1);
}
});
// console.log(element, children)
}
return element;

View file

@ -44,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

View file

@ -1,9 +1,10 @@
EPUBJS.Pagination = function(pageList) {
this.pageList = pageList;
this.pages = [];
this.locations = [];
this.epubcfi = new EPUBJS.EpubCFI();
if(pageList && pageList.length) {
this.process(pageList);
}
};
EPUBJS.Pagination.prototype.process = function(pageList){
@ -11,14 +12,15 @@ EPUBJS.Pagination.prototype.process = function(pageList){
this.pages.push(item.page);
this.locations.push(item.cfi);
}, this);
this.pageList = pageList;
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;
var pg = -1;
// check if the cfi is in the location list
var index = this.locations.indexOf(cfi);
if(index != -1 && index < (this.pages.length-1) ) {
@ -32,12 +34,11 @@ EPUBJS.Pagination.prototype.pageFromCfi = function(cfi){
// 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;
var cfi = -1;
// check that pg is an int
if(typeof pg != "number"){
pg = parseInt(pg);
@ -73,10 +74,10 @@ EPUBJS.Pagination.prototype.percentageFromCfi = function(cfi){
// TODO: move these
EPUBJS.Book.prototype.gotoPage = function(pg){
var cfi = this.pagination.cfiFromPage(pg);
this.gotoCfi(cfi);
return this.gotoCfi(cfi);
};
EPUBJS.Book.prototype.gotoPercentage = function(percent){
var pg = this.pagination.pageFromPercentage(percent);
this.gotoCfi(pg);
return this.gotoCfi(pg);
};

View file

@ -14,7 +14,11 @@ EPUBJS.Render.Iframe.prototype.create = function(){
this.iframe = document.createElement('iframe');
this.iframe.id = "epubjs-iframe:" + EPUBJS.core.uuid();
this.iframe.scrolling = "no";
this.iframe.seamless = "seamless";
// Back up if seamless isn't supported
this.iframe.style.border = "none";
this.iframe.addEventListener("load", this.loaded.bind(this), false);
return this.iframe;
};
@ -27,9 +31,11 @@ EPUBJS.Render.Iframe.prototype.load = function(url){
var render = this,
deferred = new RSVP.defer();
this.leftPos = 0;
this.iframe.src = url;
// Reset the scroll position
render.leftPos = 0;
if(this.window) {
this.unload();
}
@ -43,12 +49,12 @@ EPUBJS.Render.Iframe.prototype.load = function(url){
render.window = render.iframe.contentWindow;
render.window.addEventListener("resize", render.resized.bind(render), false);
//-- Clear Margins
if(render.bodyEl) {
render.bodyEl.style.margin = "0";
}
deferred.resolve(render.docEl);
};
@ -62,6 +68,12 @@ EPUBJS.Render.Iframe.prototype.load = function(url){
return deferred.promise;
};
EPUBJS.Render.Iframe.prototype.loaded = function(){
var url = this.iframe.contentWindow.location.href;
this.trigger("render:loaded", url);
};
// Resize the iframe to the given width and height
EPUBJS.Render.Iframe.prototype.resize = function(width, height){
var iframeBox;
@ -159,13 +171,15 @@ EPUBJS.Render.Iframe.prototype.getBaseElement = function(){
// Checks if an element is on the screen
EPUBJS.Render.Iframe.prototype.isElementVisible = function(el){
var rect;
var left;
if(el && typeof el.getBoundingClientRect === 'function'){
rect = el.getBoundingClientRect();
left = rect.left; //+ rect.width;
if( rect.width !== 0 &&
rect.height !== 0 && // Element not visible
rect.left >= 0 &&
rect.left < this.pageWidth ) {
left >= 0 &&
left < this.pageWidth ) {
return true;
}
}
@ -185,4 +199,7 @@ EPUBJS.Render.Iframe.prototype.scroll = function(bool){
// Cleanup event listeners
EPUBJS.Render.Iframe.prototype.unload = function(){
this.window.removeEventListener("resize", this.resized);
};
};
//-- Enable binding events to Render
RSVP.EventTarget.mixin(EPUBJS.Render.Iframe.prototype);

View file

@ -12,6 +12,9 @@ EPUBJS.Renderer = function(renderMethod) {
console.error("Not a Valid Rendering Method");
}
// Listen for load events
this.render.on("render:loaded", this.loaded.bind(this));
// Cached for replacement urls from storage
this.caches = {};
@ -120,9 +123,9 @@ EPUBJS.Renderer.prototype.load = function(url){
this.visible(false);
loaded = this.render.load(url);
render = this.render.load(url);
loaded.then(function(contents) {
render.then(function(contents) {
var formated;
this.contents = contents;
@ -136,6 +139,7 @@ EPUBJS.Renderer.prototype.load = function(url){
this.render.window.addEventListener("resize", this.resized, false);
}
this.addEventListeners();
this.addSelectionListeners();
@ -161,6 +165,13 @@ EPUBJS.Renderer.prototype.load = function(url){
return deferred.promise;
};
EPUBJS.Renderer.prototype.loaded = function(url){
this.trigger("render:loaded", url);
// var uri = EPUBJS.core.uri(url);
// var relative = uri.path.replace(book.bookUrl, '');
// console.log(url, uri, relative);
};
/**
* Reconciles the current chapters layout properies with
* the global layout properities.
@ -189,8 +200,7 @@ EPUBJS.Renderer.prototype.reconcileLayoutSettings = function(global, chapter){
settings[property] = value;
}
});
return settings;
return settings;
};
/**
@ -251,7 +261,7 @@ EPUBJS.Renderer.prototype.reformat = function(){
pages = renderer.layout.calculatePages();
renderer.updatePages(pages);
// Give the css styles time to update
clearTimeout(this.timeoutTillCfi);
this.timeoutTillCfi = setTimeout(function(){
@ -322,7 +332,6 @@ EPUBJS.Renderer.prototype.page = function(pg){
this.currentLocationCfi = this.getPageCfi();
this.trigger("renderer:locationChanged", this.currentLocationCfi);
return true;
}
//-- Return false if page is greater than the total
@ -375,7 +384,20 @@ EPUBJS.Renderer.prototype.section = function(fragment){
};
// Walk the node tree from an element to the root
EPUBJS.Renderer.prototype.firstElementisTextNode = function(node) {
var children = node.childNodes;
var leng = children.length;
if(leng &&
children[0] && // First Child
children[0].nodeType === 3 && // This is a textNodes
children[0].textContent.trim().length) { // With non whitespace or return charecters
return true;
}
return false;
};
// Walk the node tree from a start element to next visible element
EPUBJS.Renderer.prototype.walk = function(node) {
var r, children, leng,
startNode = node,
@ -387,7 +409,7 @@ EPUBJS.Renderer.prototype.walk = function(node) {
while(!r && stack.length) {
node = stack.shift();
if( this.render.isElementVisible(node) ) {
if( this.render.isElementVisible(node) && this.firstElementisTextNode(node)) {
r = node;
}
@ -398,8 +420,8 @@ EPUBJS.Renderer.prototype.walk = function(node) {
} else {
return r;
}
for (var i = 0; i < leng; i++) {
if(children[i] != prevNode) stack.push(children[i]);
for (var i = leng-1; i >= 0; i--) {
if(children[i] != prevNode) stack.unshift(children[i]);
}
}
@ -437,6 +459,7 @@ EPUBJS.Renderer.prototype.gotoCfi = function(cfi){
}
element = this.epubcfi.getElement(cfi, this.doc);
el = element;
this.pageByElement(element);
};
@ -669,4 +692,4 @@ EPUBJS.Renderer.prototype.replaceWithStored = function(query, attr, func, callba
};
//-- Enable binding events to Renderer
RSVP.EventTarget.mixin(EPUBJS.Renderer.prototype);
RSVP.EventTarget.mixin(EPUBJS.Renderer.prototype);

View file

@ -3,6 +3,7 @@ EPUBJS.replace = {};
//-- Replaces the relative links within the book to use our internal page changer
EPUBJS.replace.hrefs = function(callback, renderer){
var book = this;
var replacments = function(link, done){
var href = link.getAttribute("href"),
relative = href.search("://"),
@ -15,7 +16,7 @@ EPUBJS.replace.hrefs = function(callback, renderer){
}else{
link.onclick = function(){
renderer.book.goto(href);
book.goto(href);
return false;
};

35
tests/epubcfi.js Normal file
View file

@ -0,0 +1,35 @@
// /demo/moby-dick/OPS/chapter_006.xhtml
// epubcfi(/6/24[xchapter_006]!4/2/14/1:0)
module('EPUB CFI');
asyncTest("Renderer Updates to new CFI", 1, function() {
var book = ePub('/demo/moby-dick/', { width: 400, height: 600 });
var render = book.renderTo("qunit-fixture");
var result = function(){
var displayed = book.gotoCfi("epubcfi(/6/24[xchapter_006]!4/2/14/1:0)");
displayed.then(function(){
equal( book.getCurrentLocationCfi(), "epubcfi(/6/24[xchapter_006]!4/2/14/1:0)", "Location is correct" );
start();
});
};
render.then(result);
});
// asyncTest("Find Element from cfi", 1, function() {
// var book = ePub('/demo/moby-dick/', { width: 400, height: 600 });
//
// var render = book.renderTo("qunit-fixture");
//
// var result = function(){
// var d = book.gotoCfi("epubcfi(/6/24[xchapter_006]!4/2/14/1:0)");
// console.log(d, book.getCurrentLocationCfi())
// // equal( pg.page, 755, "Page has been parsed" );
// start();
// };
//
// render.then(result);
// });

View file

@ -50,6 +50,7 @@
<script src="render.js"></script>
<script src="unarchiver.js"></script>
<script src="pagination.js"></script>
<script src="epubcfi.js"></script>
</body>
</html>

View file

@ -76,7 +76,7 @@ test("Get Percentage from a cfi present in the pageList", 1, function() {
test("Get Percentage from a cfi NOT present in the pageList", 1, function() {
var pagination = new EPUBJS.Pagination(mockPageList);
var pg = pagination.percentageFromCfi("epubcfi(/6/4[ct]!/4/2[d10e42]/20/12/1:0)");
equal( pg, .17, "Page is found, and correct presentage reported" );
equal( pg, 0.167, "Page is found, and correct presentage reported" );
});
asyncTest("Generate PageList", 4, function() {
@ -95,9 +95,49 @@ asyncTest("Generate PageList", 4, function() {
});
book.pageListReady.then(function(pageList){
equal(pageList.length, 885, "PageList has been generated");
equal(pageList.length, 888, "PageList has been generated");
// fixture seems to be removed by the time this is run
// equal($("#qunit-fixture frame").length, 1, "Hidden Element Removed");
start();
});
});
asyncTest("Load a pageList", 2, function() {
var book = ePub('../books/moby-dick/', { width: 1076, height: 588 });
var render = book.renderTo("qunit-fixture");
EPUBJS.core.request("../examples/page_list.json").then(function(storedPageList){
pageList = storedPageList;
book.loadPagination(pageList);
});
book.pageListReady.then(function(pageList){
equal(pageList.length, 394, "PageList has been generated");
equal(book.pagination.lastPage, 394, "All pages present")
start();
});
});
asyncTest("gotoPage after generating page list", 2, function() {
var book = ePub('../demo/moby-dick/', { width: 1076, height: 588 });
var render = book.renderTo("qunit-fixture");
book.generatePagination();
book.pageListReady.then(function(pageList){
// console.log(JSON.stringify(pageList));
var changed = book.gotoPage(38);
changed.then(function(){
equal(book.getCurrentLocationCfi(), "epubcfi(/6/24[xchapter_006]!4/2/14/1:0)", "Page changed");
start();
});
start();
equal(pageList.length, 394, "PageList has been generated");
stop();
});
});

View file

@ -63,10 +63,10 @@ asyncTest("Go to chapter 1 and advance to next page", 4, function() {
$body = $iframe.contents().find("body");
Book.nextPage();
equal( $body.scrollLeft(), 454, "on page 2");
equal( $body.scrollLeft(), 450, "on page 2");
Book.nextPage();
equal( $body.scrollLeft(), 908, "on page 3");
equal( $body.scrollLeft(), 900, "on page 3");
});
@ -149,11 +149,11 @@ asyncTest("Display end of chapter 20 and go to prev page", 3, function() {
$body = $iframe.contents().find("body");
Book.prevPage();
equal( $body.scrollLeft(), 1362, "on last page");
equal( $body.scrollLeft(), 1350, "on last page");
Book.prevPage();
equal( $body.scrollLeft(), 908, "on second to last page ");
equal( $body.scrollLeft(), 900, "on second to last page ");
});
@ -206,9 +206,9 @@ asyncTest("Switch Spreads to Single", 3, function() {
var result = function(){
equal( Book.renderer.spreads, true, "Use Spreads");
Book.useSpreads(false);
Book.forceSingle(true);
equal( Book.renderer.spreads, false, "Don't Use Spreads");
equal( Book.renderer.contents.style[EPUBJS.core.prefixed('columnWidth')], "352px", "Don't Use Spreads");
equal( Book.renderer.contents.style[EPUBJS.core.prefixed('columnWidth')], "350px", "Don't Use Spreads");
start();
};