1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-05 15:32:55 +02:00

New book / renderTo methods, added promises, new render, cfi parsing, seperate package parsing, added settings, removed modernizr, disabled offline storage until it can return apromise

This commit is contained in:
Fred Chasen 2013-06-25 00:22:49 -07:00
parent 0780411e0c
commit 751a87ca4b
24 changed files with 5038 additions and 1745 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,337 +1,43 @@
EPUBJS.Chapter = function(book, pos){
this.book = book;
this.iframe = this.book.iframe;
this.pos = pos || this.book.spinePos
this.chapInfo = this.book.spine[this.pos];
//-- Get the url to the book from the spine
this.path = this.chapInfo.href;
this.ID = this.chapInfo.id;
this.chapterPos = 1;
this.leftPos = 0;
localStorage.setItem("chapterPos", this.chapterPos);
this.book.registerHook("beforeChapterDisplay",
[this.replaceLinks.bind(this), this.replaceResources.bind(this)]);
this.load();
return this;
EPUBJS.Chapter = function(spineObject){
this.href = spineObject.href;
this.id = spineObject.id;
this.spinePos = spineObject.index;
this.properties = spineObject.properties;
this.linear = spineObject.linear;
this.pages = 1;
}
EPUBJS.Chapter.prototype.load = function(){
var path = this.path;
if(this.book.online && !this.book.contained){
this.setIframeSrc(path);
EPUBJS.Chapter.prototype.contents = function(store){
// if(this.store && (!this.book.online || this.book.contained))
if(store){
return store.get(href);
}else{
this.loadFromStorage(path);
}
}
EPUBJS.Chapter.prototype.loadFromStorage = function(path){
var file = EPUBJS.storage.get(path, this.setIframeSrc.bind(this));
}
EPUBJS.Chapter.prototype.setIframeSrc = function(url){
var that = this;
this.visible(false);
this.iframe.src = url;
this.iframe.onload = function() {
that.doc = that.iframe.contentDocument;
that.bodyEl = that.doc.body;
that.formatSpread();
//-- Trigger registered hooks before displaying
that.beforeDisplay(function(){
that.calcPages();
that.book.tell("book:chapterDisplayed");
that.visible(true);
});
that.afterLoaded(that);
that.book.listen("book:resized", that.formatSpread, that);
}
}
EPUBJS.Chapter.prototype.afterLoaded = function(chapter){
//-- This is overwritten by the book object
}
EPUBJS.Chapter.prototype.error = function(err){
console.log("error", error)
}
EPUBJS.Chapter.prototype.formatSpread = function(){
var divisor = 2,
cutoff = 800;
if(this.colWidth){
this.OldcolWidth = this.colWidth;
this.OldspreadWidth = this.spreadWidth;
return EPUBJS.core.request(href, 'xml');
}
//-- Check the width and decied on columns
//-- Todo: a better place for this?
this.elWidth = this.iframe.width;
}
this.gap = this.gap || Math.ceil(this.elWidth / 8);
if(this.elWidth < cutoff || this.book.single) {
this.spread = false; //-- Single Page
divisor = 1;
this.colWidth = Math.floor(this.elWidth / divisor);
EPUBJS.Chapter.prototype.url = function(store){
var promise = new RSVP.Promise();
if(store){
return store.getUrl(href);
}else{
this.spread = true; //-- Double Page
this.colWidth = Math.floor((this.elWidth - this.gap) / divisor);
/* - Was causing jumps, doesn't seem to be needed anymore
//-- Must be even for firefox
if(this.colWidth % 2 != 0){
this.colWidth -= 1;
}
*/
promise.resolve(this.href); //-- this is less than ideal but keeps it a promise
return promise;
}
this.spreadWidth = (this.colWidth + this.gap) * divisor;
this.bodyEl.style.fontSize = localStorage.getItem("fontSize") || "medium";
//-- Clear Margins
//this.bodyEl.style.visibility = "hidden";
this.bodyEl.style.margin = "0";
this.bodyEl.style.overflow = "hidden";
this.bodyEl.style.width = this.elWidth;
//-- Adjust height
this.bodyEl.style.height = this.book.el.clientHeight + "px";
//-- Add columns
this.bodyEl.style[EPUBJS.core.columnAxis] = "horizontal";
this.bodyEl.style[EPUBJS.core.columnGap] = this.gap+"px";
this.bodyEl.style[EPUBJS.core.columnWidth] = this.colWidth+"px";
//-- Go to current page after resize
if(this.OldcolWidth){
this.setLeft((this.chapterPos - 1 ) * this.spreadWidth);
}
}
EPUBJS.Chapter.prototype.fixedLayout = function(){
this.paginated = false;
console.log("off")
this.setLeft(0);
this.bodyEl.style.width = this.elWidth;
//-- Adjust height
this.bodyEl.style.height = "auto";
//-- Remove columns
this.bodyEl.style[EPUBJS.core.columnWidth] = "auto";
//-- Scroll
this.bodyEl.style.overflow = "auto";
this.displayedPages = 1;
EPUBJS.Chapter.prototype.setPages = function(num){
this.pages = num;
}
EPUBJS.Chapter.prototype.goToChapterEnd = function(){
this.chapterEnd();
}
EPUBJS.Chapter.prototype.visible = function(bool){
if(typeof(bool) == "undefined") {
return this.iframe.style.visibility;
}
if(bool == true){
this.iframe.style.visibility = "visible";
}else if(bool == false){
this.iframe.style.visibility = "hidden";
}
}
EPUBJS.Chapter.prototype.calcPages = function(){
this.totalWidth = this.iframe.contentDocument.documentElement.scrollWidth; //this.bodyEl.scrollWidth;
this.displayedPages = Math.ceil(this.totalWidth / this.spreadWidth);
localStorage.setItem("displayedPages", this.displayedPages);
//console.log("Pages:", this.displayedPages)
}
EPUBJS.Chapter.prototype.nextPage = function(){
if(this.chapterPos < this.displayedPages){
this.chapterPos++;
this.leftPos += this.spreadWidth;
this.setLeft(this.leftPos);
localStorage.setItem("chapterPos", this.chapterPos);
this.book.tell("book:pageChanged", this.chapterPos);
return this.chapterPos;
}else{
return false;
}
}
EPUBJS.Chapter.prototype.prevPage = function(){
if(this.chapterPos > 1){
this.chapterPos--;
this.leftPos -= this.spreadWidth;
this.setLeft(this.leftPos);
localStorage.setItem("chapterPos", this.chapterPos);
this.book.tell("book:pageChanged", this.chapterPos);
return this.chapterPos;
}else{
return false;
}
}
EPUBJS.Chapter.prototype.chapterEnd = function(){
this.page(this.displayedPages);
}
EPUBJS.Chapter.prototype.setLeft = function(leftPos){
this.bodyEl.style.marginLeft = -leftPos + "px";
/*
var left = "transform: " + (-leftPos) + "px";
//-- Need to stardize this
this.bodyEl.style.webkitTransform = left; //Chrome and Safari
this.bodyEl.style.MozTransform = left; //Firefox
this.bodyEl.style.msTransform = left; //IE
this.bodyEl.style.OTransform = left; //Opera
this.bodyEl.style.transform = left;
*/
}
//-- Replaces the relative links within the book to use our internal page changer
EPUBJS.Chapter.prototype.replaceLinks = function(callback){
var hrefs = this.doc.querySelectorAll('[href]'),
links = Array.prototype.slice.call(hrefs),
that = this;
links.forEach(function(link){
var path,
href = link.getAttribute("href"),
relative = href.search("://"),
fragment = href[0] == "#";
if(relative != -1){
link.setAttribute("target", "_blank");
}else{
link.onclick = function(){
if(that.book.useHash){
window.location.hash = "#/"+href;
}else{
that.book.show(href);
}
}
}
});
if(callback) callback();
}
//-- Replaces assets src's to point to stored version if browser is offline
EPUBJS.Chapter.prototype.replaceResources = function(callback){
var srcs, resources, count;
//-- No need to replace if there is network connectivity
//-- also Filesystem api links are relative, so no need to replace them
if((this.book.online && !this.book.contained) || EPUBJS.storage.getStorageType() == "filesystem") {
if(callback) callback();
return false;
}
srcs = this.doc.querySelectorAll('[src]');
resources = Array.prototype.slice.call(srcs);
count = resources.length;
resources.forEach(function(link){
var src = link.getAttribute("src"),
full = this.book.basePath + src;
EPUBJS.storage.get(full, function(url){
link.setAttribute("src", url);
count--;
if(count <= 0 && callback) callback();
});
}.bind(this));
EPUBJS.Chapter.prototype.getPages = function(num){
return this.pages;
}
EPUBJS.Chapter.prototype.getID = function(){
return this.ID;
}
EPUBJS.Chapter.prototype.page = function(pg){
if(pg >= 1 && pg <= this.displayedPages){
this.chapterPos = pg;
this.leftPos = this.spreadWidth * (pg-1); //-- pages start at 1
this.setLeft(this.leftPos);
localStorage.setItem("chapterPos", pg);
return true;
}
//-- Return false if page is greater than the total
return false;
}
//-- Find a section by fragement id
EPUBJS.Chapter.prototype.section = function(fragment){
var el = this.doc.getElementById(fragment),
left, pg;
if(el){
left = this.leftPos + el.getBoundingClientRect().left, //-- Calculate left offset compaired to scrolled position
pg = Math.floor(left / this.spreadWidth) + 1; //-- pages start at 1
this.page(pg);
}
}
EPUBJS.Chapter.prototype.beforeDisplay = function(callback){
this.book.triggerHooks("beforeChapterDisplay", callback.bind(this), this);
}
}

View file

@ -12,19 +12,65 @@ EPUBJS.core.getEls = function(classes) {
}
EPUBJS.core.loadXML = function(url, callback){
EPUBJS.core.request = function(url, type) {
var promise = new RSVP.Promise();
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.overrideMimeType('text/xml');
xhr.onload = function(e) {
if (this.status == 200) {
callback(this.responseXML);
}
};
xhr.open("GET", url);
xhr.onreadystatechange = handler;
if(type == 'blob'){
xhr.responseType = type;
}
if(type == "json") {
xhr.setRequestHeader("Accept", "application/json");
}
if(type == 'xml') {
xhr.overrideMimeType('text/xml');
}
xhr.send();
}
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
var r;
if(type == 'xml'){
r = this.responseXML;
}else
if(type == 'json'){
r = JSON.parse(this.response);
}else{
r = this.response;
}
promise.resolve(r);
}
else { promise.reject(this); }
}
};
return promise;
};
// EPUBJS.core.loadXML = function(url, callback){
// var xhr = new XMLHttpRequest();
// xhr.open('GET', url, true);
// xhr.overrideMimeType('text/xml');
//
// xhr.onload = function(e) {
// if (this.status == 200) {
// callback(this.responseXML);
// }
// };
//
// xhr.send();
// }
// EPUBJS.core.loadFile = function(url){
// var xhr = new XMLHttpRequest(),
@ -63,66 +109,47 @@ EPUBJS.core.loadXML = function(url, callback){
// "error" : failed
// }
// }
//
// EPUBJS.core.loadFile = function(url, callback){
// var xhr = new XMLHttpRequest();
//
// this.succeeded = function(response){
// if(callback){
// callback(response);
// }
// }
//
// this.failed = function(err){
// console.log("Error:", err);
// }
//
// this.start = function(){
// var that = this;
//
// xhr.open('GET', url, true);
// xhr.responseType = 'blob';
//
// xhr.onload = function(e) {
// if (this.status == 200) {
// that.succeeded(this.response);
// }
// };
//
// xhr.onerror = function(e) {
// that.failed(this.status); //-- TODO: better error message
// };
//
// xhr.send();
// }
//
// return {
// "start": this.start,
// "succeeded" : this.succeeded,
// "failed" : this.failed
// }
// }
EPUBJS.core.loadFile = function(url, callback){
var xhr = new XMLHttpRequest();
this.succeeded = function(response){
if(callback){
callback(response);
}
}
this.failed = function(err){
console.log("Error:", err);
}
this.start = function(){
var that = this;
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
that.succeeded(this.response);
}
};
xhr.onerror = function(e) {
that.failed(this.status); //-- TODO: better error message
};
xhr.send();
}
return {
"start": this.start,
"succeeded" : this.succeeded,
"failed" : this.failed
}
}
EPUBJS.core.crossBrowserColumnCss = function(){
//-- From Readium: reflowable_pagination_view.js
var cssIfy = function(str) {
return str.replace(/([A-Z])/g, function(str,m1){
return '-' + m1.toLowerCase();
}).replace(/^ms-/,'-ms-');
};
// ask modernizr for the vendor prefixed version
EPUBJS.core.columnAxis = Modernizr.prefixed('columnAxis') || 'columnAxis';
EPUBJS.core.columnGap = Modernizr.prefixed('columnGap') || 'columnGap';
EPUBJS.core.columnWidth = Modernizr.prefixed('columnWidth') || 'columnWidth';
// we are interested in the css prefixed version
// EPUBJS.core.columnAxis = cssIfy(EPUBJS.core.columnAxis);
// EPUBJS.core.columnGap = cssIfy(EPUBJS.core.columnGap);
// EPUBJS.core.columnWidth = cssIfy(EPUBJS.core.columnWidth);
}
EPUBJS.core.toArray = function(obj) {
var arr = [];
@ -139,6 +166,16 @@ EPUBJS.core.toArray = function(obj) {
return arr;
};
//-- Parse out the folder
EPUBJS.core.folder = function(url){
var slash = url.lastIndexOf('/'),
folder = url.slice(0, slash + 1);
return folder;
};
//-- https://github.com/ebidel/filer.js/blob/master/src/filer.js#L128
EPUBJS.core.dataURLToBlob = function(dataURL) {
var BASE64_MARKER = ';base64,';
@ -220,3 +257,25 @@ EPUBJS.core.addScript = function(src, callback, target) {
target = target || document.body;
target.appendChild(s);
}
EPUBJS.core.prefixed = function(unprefixed) {
var vendors = ["Webkit", "Moz", "O", "ms" ],
prefixes = ['-Webkit-', '-moz-', '-o-', '-ms-'],
upper = unprefixed[0].toUpperCase() + unprefixed.slice(1),
length = vendors.length,
i = 0;
if (typeof(document.body.style[unprefixed]) != 'undefined') {
return unprefixed;
}
for ( ; i < length; i++ ) {
if (typeof(document.body.style[vendors[i] + upper]) != 'undefined') {
return vendors[i] + upper;
}
}
return false;
}

170
src/epubcfi.js Normal file
View file

@ -0,0 +1,170 @@
EPUBJS.EpubCFI = function(cfiStr){
if(cfiStr) return this.parse(cfiStr);
}
EPUBJS.EpubCFI.prototype.generateChapter = function(spineNodeIndex, pos, id) {
var spineNodeIndex = spineNodeIndex + 1,
cfi = '/'+spineNodeIndex+'/';
cfi += (pos + 1) * 2;
if(id) cfi += "[" + id + "]";
cfi += "!";
return cfi;
}
EPUBJS.EpubCFI.prototype.generateFragment = function(element, chapter) {
var path = this.pathTo(element),
parts = [];
if(chapter) parts.push(chapter);
path.forEach(function(part){
parts.push((part.index + 1) * 2);
if(part.id &&
part.id.slice(0, 7) != "@EPUBJS") { //-- ignore internal @EPUBJS ids
parts.push("[" + part.id + "]");
}
});
return parts.join('/');
}
EPUBJS.EpubCFI.prototype.pathTo = function(node) {
var stack = [],
children;
while(node && node.parentNode !== null) {
children = node.parentNode.children;
stack.unshift({
'id' : node.id,
// 'classList' : node.classList,
'tagName' : node.tagName,
'index' : children ? Array.prototype.indexOf.call(children, node) : 0
});
node = node.parentNode;
}
return stack;
}
EPUBJS.EpubCFI.prototype.getChapter = function(cfiStr) {
var splitStr = cfiStr.split("!");
return splitStr[0];
}
EPUBJS.EpubCFI.prototype.getFragment = function(cfiStr) {
var splitStr = cfiStr.split("!");
return splitStr[1];
}
EPUBJS.EpubCFI.prototype.getOffset = function(cfiStr) {
var splitStr = cfiStr.split(":");
return [splitStr[0], splitStr[1]];
}
EPUBJS.EpubCFI.prototype.parse = function(cfiStr) {
var cfi = {},
chapId,
path,
end,
text;
cfi.chapter = this.getChapter(cfiStr);
cfi.fragment = this.getFragment(cfiStr);
cfi.spinePos = (parseInt(cfi.chapter.split("/")[2]) / 2 - 1 ) || false;
chapId = cfi.chapter.match(/\[(.*)\]/);
cfi.spineId = chapId[1] || false;
path = cfi.fragment.split('/');
end = path[path.length-1];
cfi.sections = [];
//-- Check for Character Offset
if(parseInt(end) % 2){
text = this.getOffset();
cfi.text = parseInt(text[0]);
cfi.character = parseInt(text[1]);
path.pop(); //-- remove from path to element
}
path.forEach(function(part){
var index, has_id, id;
if(!part) return;
index = parseInt(part) / 2 - 1;
has_id = part.match(/\[(.*)\]/);
if(has_id && has_id[1]){
id = has_id[1];
}
cfi.sections.push({
'index' : index,
'id' : id || false
});
});
return cfi;
}
EPUBJS.EpubCFI.prototype.getElement = function(cfi, doc) {
var doc = doc || document,
sections = cfi.sections,
element = doc.getElementsByTagName('html')[0],
children = Array.prototype.slice.call(element.children),
num, index, part,
has_id, id;
sections.shift() //-- html
while(sections.length > 0) {
part = sections.shift();
if(part.id){
element = cfi.doc.querySelector("#" + part.id);
}else{
element = children[part.index];
if(!children) console.error("No Kids", element);
}
if(!element) console.error("No Element For", part);
children = Array.prototype.slice.call(element.children);
}
return element;
}
//-- Todo: function to remove IDs to sort

229
src/parser.js Normal file
View file

@ -0,0 +1,229 @@
EPUBJS.Parser = function(baseUrl){
this.baseUrl = baseUrl || '';
}
EPUBJS.Parser.prototype.container = function(containerXml){
//-- <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/>
var rootfile = containerXml.querySelector("rootfile"),
fullpath = rootfile.getAttribute('full-path'),
folder = EPUBJS.core.folder(fullpath);
//-- Now that we have the path we can parse the contents
return {
'packagePath' : fullpath,
'basePath' : folder
};
// localStorage.setItem("basePath", that.basePath);
// localStorage.setItem("contentsPath", that.contentsPath);
}
EPUBJS.Parser.prototype.package = function(packageXml, baseUrl){
var parse = this;
if(baseUrl) this.baseUrl = baseUrl;
var metadataNode = packageXml.querySelector("metadata"),
manifestNode = packageXml.querySelector("manifest"),
spineNode = packageXml.querySelector("spine");
var manifest = parse.manifest(manifestNode),
tocPath = parse.findTocPath(manifestNode),
coverPath = parse.findCoverPath(manifestNode);
var spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);
var spine = parse.spine(spineNode, manifest);
var spineIndexByURL = {};
spine.forEach(function(item){
spineIndexByURL[item.href] = item.index;
});
return {
'metadata' : parse.metadata(metadataNode),
'spine' : spine,
'manifest' : manifest,
'tocPath' : tocPath,
'coverPath': coverPath,
'spineNodeIndex' : spineNodeIndex,
'spineIndexByURL' : spineIndexByURL
};
}
//-- Find TOC NCX: media-type="application/x-dtbncx+xml" href="toc.ncx"
EPUBJS.Parser.prototype.findTocPath = function(manifestNode){
var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']");
return node.getAttribute('href');
}
//-- Find Cover: <item properties="cover-image" id="ci" href="cover.svg" media-type="image/svg+xml" />
EPUBJS.Parser.prototype.findCoverPath = function(manifestNode){
var node = manifestNode.querySelector("item[properties='cover-image']");
return node.getAttribute('href');
}
// EPUBJS.Parser.prototype.findCover = function(manifest){
// var leng = manifest.length,
// i = 0
// tocPath = false;
//
// while(found == false & i < leng) {
// if(manifest[i].type == "application/x-dtbncx+xml"){
// tocPath = manifest[i].href;
// found = true;
// }
// i++;
// }
//
// return tocPath;
// }
EPUBJS.Parser.prototype.metadata = function(metadataXml){
var metadata = {};
var title = metadataXml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/","title")[0]
creator = metadataXml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/","creator")[0];
metadata["bookTitle"] = title ? title.childNodes[0].nodeValue : "";
metadata["creator"] = creator ? creator.childNodes[0].nodeValue : "";
//-- TODO: add more meta data items, such as ISBN
// localStorage.setItem("metadata", JSON.stringify(this.metadata));
return metadata;
}
EPUBJS.Parser.prototype.manifest = function(manifestXml){
var baseUrl = this.baseUrl,
manifest = {};
//-- Turn items into an array
var selected = manifestXml.querySelectorAll("item"),
items = Array.prototype.slice.call(selected);
//-- Create an object with the id as key
items.forEach(function(item){
var id = item.getAttribute('id'),
href = item.getAttribute('href') || '',
type = item.getAttribute('media-type') || '';
manifest[id] = {
'href' : baseUrl + href, //-- Absolute URL for loading with a web worker
'type' : type
};
});
return manifest;
// localStorage.setItem("assets", JSON.stringify(this.assets));
}
EPUBJS.Parser.prototype.spine = function(spineXml, manifest){
var spine = [];
var selected = spineXml.getElementsByTagName("itemref"),
items = Array.prototype.slice.call(selected);
//-- Add to array to mantain ordering and cross reference with manifest
items.forEach(function(item, index){
var Id = item.getAttribute('idref');
var vert = {
'id' : Id,
'linear' : item.getAttribute('linear') || '',
'properties' : item.getAttribute('properties') || '',
'href' : manifest[Id].href,
'index' : index
}
spine.push(vert);
});
// localStorage.setItem("spine", JSON.stringify(this.spine));
// localStorage.setItem("spineIndexByURL", JSON.stringify(this.spineIndexByURL));
return spine;
}
EPUBJS.Parser.prototype.toc = function(tocXml){
var toc = [];
var navMap = tocXml.querySelector("navMap");
//cover = contents.querySelector("meta[name='cover']"),
//coverID;
//-- Add cover
/*
if(cover){
coverID = cover.getAttribute("content");
that.toc.push({
"id": coverID,
"href": that.assets[coverID],
"label": coverID
});
}
*/
function getTOC(nodes, parent, list){
var list = list || [];
items = Array.prototype.slice.call(nodes);
items.forEach(function(item){
var id = item.getAttribute('id'),
content = item.querySelector("content"),
src = content.getAttribute('src'),
split = src.split("#"),
navLabel = item.querySelector("navLabel"),
text = navLabel.textContent ? navLabel.textContent : "",
subitems = item.querySelectorAll("navPoint");
// subs = false,
// childof = (item.parentNode == parent);
//if(!childof) return; //-- Only get direct children, should xpath for this eventually?
// if(item.hasChildNodes()){
// subs = getTOC(subitems, item)
// }
list.push({
"id": id,
"href": src,
"label": text,
"subitems" : subitems.length ? getTOC(item.querySelectorAll("navPoint"), item, list) : false
});
});
return list;
}
return getTOC(navMap.querySelectorAll("navPoint"), navMap);
// localStorage.setItem("toc", JSON.stringify(that.toc));
// that.tell("book:tocReady");
/*
<navPoint class="chapter" id="xtitlepage" playOrder="1">
<navLabel><text>Moby-Dick</text></navLabel>
<content src="titlepage.xhtml"/>
</navPoint>
*/
}

566
src/renderer.js Normal file
View file

@ -0,0 +1,566 @@
EPUBJS.Renderer = function(book) {
var elem = book.settings.element;
this.book = book;
this.settings = book.settings;
//-- Takes a string or a element
if(_.isElement(elem)) {
this.el = elem;
} else if (typeof elem == "string") {
this.el = EPUBJS.core.getEl(elem);
} else {
console.error("Not an Element");
return;
}
book.registerHook("beforeChapterDisplay",
[this.replaceLinks.bind(this), this.replaceResources.bind(this)]);
this.crossBrowserColumnCss();
this.epubcfi = new EPUBJS.EpubCFI();
this.initialize();
this.listeners();
}
//-- Build up any html needed
EPUBJS.Renderer.prototype.initialize = function(){
this.iframe = document.createElement('iframe');
//this.iframe.id = "epubjs-iframe";
this.resizeIframe(false, this.el.clientWidth, this.el.clientHeight);
this.on("book:resized", this.resizeIframe, this);
this.el.appendChild(this.iframe);
}
//-- Listeners for browser events
EPUBJS.Renderer.prototype.listeners = function(){
this.resized = _.debounce(this.onResized.bind(this), 10);
window.addEventListener("resize", this.resized, false);
// window.addEventListener("hashchange", book.route.bind(this), false);
}
EPUBJS.Renderer.prototype.chapter = function(chapter){
var renderer = this,
store = this.settings.stored ? this.store : false;
this.currentChapter = chapter;
this.chapterPos = 1;
this.pageIds = {};
this.leftPos = 0;
this.currentChapterCfi = this.epubcfi.generateChapter(this.book.spineNodeIndex, chapter.spinePos, chapter.id);
this.visibileEl = false;
return chapter.url(store).
then(function(url) {
return renderer.setIframeSrc(url);
});
}
/*
EPUBJS.Renderer.prototype.route = function(hash, callback){
var location = window.location.hash.replace('#/', '');
if(this.useHash && location.length && location != this.prevLocation){
this.show(location, callback);
this.prevLocation = location;
return true;
}
return false;
}
EPUBJS.Renderer.prototype.hideHashChanges = function(){
this.useHash = false;
}
*/
EPUBJS.Renderer.prototype.onResized = function(){
this.trigger("book:resized", {
width: this.el.clientWidth,
height: this.el.clientHeight
});
this.reformat();
}
EPUBJS.Renderer.prototype.reformat = function(){
var renderer = this;
//-- reformat
this.formatSpread();
setTimeout(function(){
//-- re-calc number of pages
renderer.calcPages();
//-- Go to current page after resize
if(renderer.currentLocationCfi){
renderer.gotoCfiFragment(renderer.currentLocationCfi);
}
}, 10);
}
EPUBJS.Renderer.prototype.destroy = function(){
window.removeEventListener("resize", this.resized, false);
}
EPUBJS.Renderer.prototype.resizeIframe = function(e, cWidth, cHeight){
var width, height;
//-- Can be resized by the window resize event, or by passed height
if(!e){
width = cWidth;
height = cHeight;
}else{
width = e.width;
height = e.height;
}
this.iframe.height = height;
if(width % 2 != 0){
width += 1; //-- Prevent cutting off edges of text in columns
}
this.iframe.width = width;
}
EPUBJS.Renderer.prototype.crossBrowserColumnCss = function(){
EPUBJS.Renderer.columnAxis = EPUBJS.core.prefixed('columnAxis') || 'columnAxis';
EPUBJS.Renderer.columnGap = EPUBJS.core.prefixed('columnGap') || 'columnGap';
EPUBJS.Renderer.columnWidth = EPUBJS.core.prefixed('columnWidth') || 'columnWidth';
}
EPUBJS.Renderer.prototype.setIframeSrc = function(url){
var renderer = this,
promise = new RSVP.Promise();
this.visible(false);
this.iframe.src = url;
this.iframe.onload = function() {
renderer.doc = renderer.iframe.contentDocument;
renderer.docEl = renderer.doc.documentElement;
renderer.bodyEl = renderer.doc.body;
renderer.formatSpread();
//-- Trigger registered hooks before displaying
renderer.beforeDisplay(function(){
renderer.calcPages();
renderer.currentLocationCfi = renderer.getPageCfi();
renderer.trigger("book:chapterDisplayed");
renderer.visible(true);
});
promise.resolve(renderer);
// that.afterLoaded(that);
}
return promise;
}
EPUBJS.Renderer.prototype.formatSpread = function(){
var divisor = 2,
cutoff = 800;
if(this.colWidth){
this.OldcolWidth = this.colWidth;
this.OldspreadWidth = this.spreadWidth;
}
//-- Check the width and decied on columns
//-- Todo: a better place for this?
this.elWidth = this.iframe.width;
this.gap = this.gap || Math.ceil(this.elWidth / 8);
if(this.elWidth < cutoff || this.settings.single) {
this.spread = false; //-- Single Page
divisor = 1;
this.colWidth = Math.floor(this.elWidth / divisor);
}else{
this.spread = true; //-- Double Page
this.colWidth = Math.floor((this.elWidth - this.gap) / divisor);
/* - Was causing jumps, doesn't seem to be needed anymore
//-- Must be even for firefox
if(this.colWidth % 2 != 0){
this.colWidth -= 1;
}
*/
}
this.spreadWidth = (this.colWidth + this.gap) * divisor;
// this.bodyEl.style.fontSize = localStorage.getItem("fontSize") || "medium";
//-- Clear Margins
// this.bodyEl.style.margin = "0";
this.docEl.style.overflow = "hidden";
this.docEl.style.width = this.elWidth;
//-- Adjust height
this.docEl.style.height = this.el.clientHeight + "px";
//-- Add columns
this.docEl.style[EPUBJS.Renderer.columnAxis] = "horizontal";
this.docEl.style[EPUBJS.Renderer.columnGap] = this.gap+"px";
this.docEl.style[EPUBJS.Renderer.columnWidth] = this.colWidth+"px";
}
EPUBJS.Renderer.prototype.fixedLayout = function(){
this.paginated = false;
this.setLeft(0);
this.docEl.style.width = this.elWidth;
//-- Adjust height
this.docEl.style.height = "auto";
//-- Remove columns
this.docEl.style[EPUBJS.core.columnWidth] = "auto";
//-- Scroll
this.docEl.style.overflow = "auto";
this.displayedPages = 1;
}
EPUBJS.Renderer.prototype.gotoChapterEnd = function(){
this.chapterEnd();
}
EPUBJS.Renderer.prototype.visible = function(bool){
if(typeof(bool) == "undefined") {
return this.iframe.style.visibility;
}
if(bool == true){
this.iframe.style.visibility = "visible";
}else if(bool == false){
this.iframe.style.visibility = "hidden";
}
}
EPUBJS.Renderer.prototype.calcPages = function() {
this.totalWidth = this.docEl.scrollWidth;
this.displayedPages = Math.ceil(this.totalWidth / this.spreadWidth);
this.currentChapter.pages = this.displayedPages;
}
EPUBJS.Renderer.prototype.nextPage = function(){
if(this.chapterPos < this.displayedPages){
this.chapterPos++;
this.leftPos += this.spreadWidth;
this.setLeft(this.leftPos);
this.currentLocationCfi = this.getPageCfi();
this.trigger("book:pageChanged", this.currentLocationCfi);
return this.chapterPos;
}else{
return false;
}
}
EPUBJS.Renderer.prototype.prevPage = function(){
if(this.chapterPos > 1){
this.chapterPos--;
this.leftPos -= this.spreadWidth;
this.setLeft(this.leftPos);
this.currentLocationCfi = this.getPageCfi();
this.trigger("book:pageChanged", this.currentLocationCfi);
return this.chapterPos;
}else{
return false;
}
}
EPUBJS.Renderer.prototype.chapterEnd = function(){
this.page(this.displayedPages);
}
EPUBJS.Renderer.prototype.setLeft = function(leftPos){
// this.bodyEl.style.marginLeft = -leftPos + "px";
this.doc.defaultView.scrollTo(leftPos, 0)
}
//-- Replaces the relative links within the book to use our internal page changer
EPUBJS.Renderer.prototype.replaceLinks = function(callback){
var hrefs = this.doc.querySelectorAll('[href]'),
links = Array.prototype.slice.call(hrefs),
that = this;
links.forEach(function(link){
var path,
href = link.getAttribute("href"),
relative = href.search("://"),
fragment = href[0] == "#";
if(relative != -1){
link.setAttribute("target", "_blank");
}else{
link.onclick = function(){
that.book.goto(href);
}
}
});
if(callback) callback();
}
//-- Replaces assets src's to point to stored version if browser is offline
EPUBJS.Renderer.prototype.replaceResources = function(callback){
var srcs, resources, count;
//-- No need to replace if there is network connectivity
//-- also Filesystem api links are relative, so no need to replace them
if((this.book.online && !this.book.contained) || EPUBJS.storage.getStorageType() == "filesystem") {
if(callback) callback();
return false;
}
srcs = this.doc.querySelectorAll('[src]');
resources = Array.prototype.slice.call(srcs);
count = resources.length;
resources.forEach(function(link){
var src = link.getAttribute("src"),
full = this.book.basePath + src;
EPUBJS.storage.get(full, function(url){
link.setAttribute("src", url);
count--;
if(count <= 0 && callback) callback();
});
}.bind(this));
}
EPUBJS.Renderer.prototype.page = function(pg){
if(pg >= 1 && pg <= this.displayedPages){
this.chapterPos = pg;
this.leftPos = this.spreadWidth * (pg-1); //-- pages start at 1
this.setLeft(this.leftPos);
// localStorage.setItem("chapterPos", pg);
return true;
}
console.log("false", pg, this.displayedPages)
//-- Return false if page is greater than the total
return false;
}
//-- Find a section by fragement id
EPUBJS.Renderer.prototype.section = function(fragment){
var el = this.doc.getElementById(fragment),
left, pg;
if(el){
this.pageByElement(el);
}
}
//-- Show the page containing an Element
EPUBJS.Renderer.prototype.pageByElement = function(el){
var left, pg;
if(!el) return;
left = this.leftPos + el.getBoundingClientRect().left, //-- Calculate left offset compaired to scrolled position
pg = Math.floor(left / this.spreadWidth) + 1; //-- pages start at 1
this.page(pg);
}
EPUBJS.Renderer.prototype.beforeDisplay = function(callback){
this.book.triggerHooks("beforeChapterDisplay", callback.bind(this), this);
}
EPUBJS.Renderer.prototype.walk = function(node) {
var r,
node, children, leng,
startNode = node,
prevNode,
stack = [startNode];
var STOP = 10000, ITER=0;
while(!r && stack.length) {
node = stack.shift();
if( this.isElementVisible(node) ) {
r = node;
}
if(!r && node && node.childElementCount > 0){
children = node.children;
leng = children.length;
for (var i = 0; i < leng; i++) {
if(children[i] != prevNode) stack.push(children[i]);
}
}
if(!r && stack.length == 0 && startNode && startNode.parentNode !== null){
stack.push(startNode.parentNode);
prevNode = startNode;
startNode = startNode.parentNode;
}
ITER++;
if(ITER > STOP) {
console.error("ENDLESS LOOP");
break;
}
}
return r;
}
EPUBJS.Renderer.prototype.getPageCfi = function(){
var prevEl = this.visibileEl;
this.visibileEl = this.findFirstVisible(prevEl);
if(!this.visibileEl.id) {
this.visibileEl.id = "@EPUBJS-PAGE-" + this.chapterPos;
}
this.pageIds[this.chapterPos] = this.visibileEl.id;
return this.epubcfi.generateFragment(this.visibileEl, this.currentChapterCfi);
}
EPUBJS.Renderer.prototype.gotoCfiFragment = function(cfi){
var element;
if(_.isString(cfi)){
cfi = this.epubcfi.parse(cfi);
}
element = this.epubcfi.getElement(cfi, this.doc);
this.pageByElement(element);
}
EPUBJS.Renderer.prototype.findFirstVisible = function(startEl){
var el = startEl || this.bodyEl,
found;
found = this.walk(el);
if(found) {
return found;
}else{
return startEl;
}
}
EPUBJS.Renderer.prototype.isElementVisible = function(el){
var left;
if(el){
left = el.getBoundingClientRect().left;
if( left >= 0 &&
left < this.spreadWidth ) {
return true;
}
}
return false;
}
//-- Enable binding events to parser
RSVP.EventTarget.mixin(EPUBJS.Renderer.prototype);