1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-04 15:09:16 +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

3
.gitignore vendored
View file

@ -1,4 +1,5 @@
.DS_Store .DS_Store
*/**/.DS_Store */**/.DS_Store
books/ books/
node_modules/ node_modules/
components

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/*! FuturePress - v0.1.0 - 2013-06-04 */ /*! FuturePress - v0.1.0 - 2013-06-25 */
EPUBJS.Hooks.register("beforeChapterDisplay").endnotes = function(callback, chapter){ EPUBJS.Hooks.register("beforeChapterDisplay").endnotes = function(callback, chapter){

View file

@ -1,4 +1,4 @@
/*! FuturePress - v0.1.0 - 2013-06-04 */ /*! FuturePress - v0.1.0 - 2013-06-25 */
var EPUBJSR = EPUBJSR || {}; var EPUBJSR = EPUBJSR || {};
@ -16,7 +16,7 @@ EPUBJSR.app.init = (function($){
bookURL = bookURL || (search ? search[1] : "moby-dick"); bookURL = bookURL || (search ? search[1] : "moby-dick");
//-- Setup the browser prefixes //-- Setup the browser prefixes
EPUBJS.core.crossBrowserColumnCss(); // EPUBJS.core.crossBrowserColumnCss();
//-- Set up our sidebar //-- Set up our sidebar
windowWidth = $(window).width(); windowWidth = $(window).width();
@ -26,27 +26,38 @@ EPUBJSR.app.init = (function($){
$("#main").width(windowWidth); $("#main").width(windowWidth);
} }
loadSettings();
//-- Create a new book object, //-- Create a new book object,
// this will create an iframe in the el with the ID provided // this will create an iframe in the el with the ID provided
Book = new EPUBJS.Book("area"); Book = new EPUBJS.Book(bookURL);
//Book.single = true; //Book.single = true;
//-- Add listeners to handle book events //-- Add listeners to handle book events
//-- Full list of event are at start of book.js //-- Full list of event are at start of book.js
Book.listen("book:metadataReady", meta);
Book.listen("book:tocReady", toc);
Book.listen("book:bookReady", bookReady); // Book.listen("book:metadataReady", meta);
Book.listen("book:chapterReady", chapterChange); // Book.listen("book:tocReady", toc);
Book.listen("book:online", goOnline); // Book.listen("book:bookReady", bookReady);
Book.listen("book:offline", goOffline); // Book.listen("book:chapterReady", chapterChange);
Book.on("book:online", goOnline);
Book.on("book:offline", goOffline);
Book.getMetadata().then(meta);
Book.getToc().then(toc);
Book.ready.all.then(bookReady);
Book.renderTo("area");
//Book.registerHook("beforeChapterDisplay", EPUBJS.Hooks.transculsions.insert); //Book.registerHook("beforeChapterDisplay", EPUBJS.Hooks.transculsions.insert);
//-- Start loading / parsing of the book. //-- Start loading / parsing of the book.
// This must be done AFTER adding listeners or hooks // This must be done AFTER adding listeners or hooks
Book.start(bookURL); //Book.renderTo("area");
//-- Wait for Dom ready to handle jquery //-- Wait for Dom ready to handle jquery
$(function() { $(function() {
@ -56,9 +67,9 @@ EPUBJSR.app.init = (function($){
} }
function meta(){ function meta(meta){
var title = Book.getTitle(), var title = meta.bookTitle,//Book.getTitle(),
author = Book.getCreator(), author = meta.creator, //Book.getCreator(),
$title = $("#book-title"), $title = $("#book-title"),
$author = $("#chapter-title"), $author = $("#chapter-title"),
$dash = $("#title-seperator"); $dash = $("#title-seperator");
@ -70,17 +81,16 @@ EPUBJSR.app.init = (function($){
} }
function toc(){ function toc(contents){
var contents = Book.getTOC(), var $toc = $("#toc"),
$toc = $("#toc"),
$links, $links,
$items; $items;
$toc.empty(); $toc.empty();
//-- Recursively generate TOC levels //-- Recursively generate TOC levels
$items = generateTocItems(contents, 1); $items = generateTocItems(contents, 1);
$toc.append($items); $toc.append($items);
$links = $(".toc_link"); $links = $(".toc_link");
@ -96,15 +106,14 @@ EPUBJSR.app.init = (function($){
//-- Provide the Book with the url to show //-- Provide the Book with the url to show
// The Url must be found in the books manifest // The Url must be found in the books manifest
Book.goto(url);
e.preventDefault();
if(!Book.useHash){
Book.show(url);
e.preventDefault();
}
}); });
} }
function loadSettings() { function loadSettings() {
@ -197,14 +206,13 @@ EPUBJSR.app.init = (function($){
function generateTocItems(contents, level){ function generateTocItems(contents, level){
var $container = $("<ul>"); var $container = $("<ul>");
var type = (level == 1) ? "chapter" : "section"; var type = (level == 1) ? "chapter" : "section";
contents.forEach(function(item){ contents.forEach(function(item){
var $subitems, var $subitems,
$wrapper = $("<li id='toc-"+item.id+"'>"), $wrapper = $("<li id='toc-"+item.id+"'>"),
$item = $("<a class='toc_link " + type + "' href='#/"+item.href+"' data-url='"+item.href+"'>"+item.label+"</a>"); $item = $("<a class='toc_link " + type + "' href='#/"+item.href+"' data-url='"+item.href+"'>"+item.label+"</a>");
$wrapper.append($item); $wrapper.append($item);
if(item.subitems && item.subitems.length){ if(item.subitems && item.subitems.length){
level++; level++;
$subitems = generateTocItems(item.subitems, level); $subitems = generateTocItems(item.subitems, level);
@ -231,14 +239,14 @@ EPUBJSR.app.init = (function($){
function goOnline(){ function goOnline(){
var $icon = $("#store"); var $icon = $("#store");
offline = false; offline = false;
$icon.attr("src", "img/save.png"); $icon.attr("src", $icon.data("save"));
} }
function goOffline(){ function goOffline(){
var $icon = $("#store"); var $icon = $("#store");
offline = true; offline = true;
$icon.attr("src", "img/saved.png"); $icon.attr("src", $icon.data("saved"));
} }
@ -294,19 +302,7 @@ EPUBJSR.app.init = (function($){
} }
}); });
//-- TODO: This doesn't seem to work
$window.bind("touchy-swipe", function(event, phase, $target, data){
if(data.direction = "left"){
Book.nextPage();
}
if(data.direction = "right"){
Book.prevPage();
}
});
var lock = false; var lock = false;
@ -337,14 +333,14 @@ EPUBJSR.app.init = (function($){
//$book.css("pointer-events", "none"); //-- Avoid capture by ifrmae //$book.css("pointer-events", "none"); //-- Avoid capture by ifrmae
$sidebar.addClass("open"); $sidebar.addClass("open");
$main.addClass("closed"); $main.addClass("closed");
$icon.attr("src", "img/close.png"); $icon.attr("src", $icon.data("close"));
} }
function hideSidebar(){ function hideSidebar(){
$book.css("pointer-events", "visible"); $book.css("pointer-events", "visible");
$sidebar.removeClass("open"); $sidebar.removeClass("open");
$main.removeClass("closed"); $main.removeClass("closed");
$icon.attr("src", "img/menu-icon.png"); $icon.attr("src",$icon.data("open"));
} }
function showSettings(){ function showSettings(){

View file

@ -12,7 +12,7 @@
<link rel="stylesheet" href="css/main.css"> <link rel="stylesheet" href="css/main.css">
<script src="js/libs/jquery-1.9.0.min.js"></script> <script src="js/libs/jquery-1.9.0.min.js"></script>
<script src="js/libs/modernizr-2.6.2.min.js"></script>
<script> <script>
"use strict"; "use strict";
@ -23,7 +23,7 @@
EPUBJS.filePath = "js/"; EPUBJS.filePath = "js/";
fileStorage.filePath = EPUBJS.filePath + "libs/"; fileStorage.filePath = EPUBJS.filePath + "libs/";
EPUBJSR.app.init("demo/moby-dick"); EPUBJSR.app.init("moby-dick");
} }
}; };

2
demo/js/epub.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
var EPUBJSR=EPUBJSR||{};EPUBJSR.app={},EPUBJSR.app.init=function(e){"use strict";function s(n){var s=window.location.search.match(/book=(.*)/),n=n||(s?s[1]:"moby-dick");EPUBJS.core.crossBrowserColumnCss(),i=e(window).width(),i>550?e("#main").width(i-r):e("#main").width(i),a(),t=new EPUBJS.Book("area"),t.listen("book:metadataReady",o),t.listen("book:tocReady",u),t.listen("book:bookReady",l),t.listen("book:chapterReady",p),t.listen("book:online",c),t.listen("book:offline",h),t.start(n),e(function(){d()})}function o(){var n=t.getTitle(),r=t.getCreator(),i=e("#book-title"),s=e("#chapter-title"),o=e("#title-seperator");document.title=n+" "+r,i.html(n),s.html(r),o.show()}function u(){var n=t.getTOC(),r=e("#toc"),i,s;r.empty(),s=f(n,1),r.append(s),i=e(".toc_link"),i.on("click",function(n){var r=e(this),i=r.data("url");e(".openChapter").removeClass("openChapter"),r.parents("li").addClass("openChapter"),t.useHash||(t.show(i),n.preventDefault())})}function a(){var n="";localStorage.getItem("fontSize")?n=localStorage.getItem("fontSize"):(n="medium",localStorage.setItem("fontSize",n));var r=e("#settingsPanel");r.append("<ul></ul>");var i=e("<li><h3></h3></li>"),s=e("<input type='radio' name='fontSize' value='x-small'><span class='xsmall'>Extra Small</span><br><input type='radio' name='fontSize' value='small'><span class='small'>Small</span><br><input type='radio' name='fontSize' value='medium'><span class='medium'>Medium</span><br><input type='radio' name='fontSize' value='large'><span class='large'>Large</span><br><input type='radio' name='fontSize' value='x-large'><span class='xlarge'>Extra Large</span>");i.find("h3").text("Font Size").after(s),r.find("ul").append(i);var o=e('input[name="fontSize"]');o.each(function(){e(this).attr("value")==n&&e(this).attr("checked","checked"),e(this).on("click",function(){localStorage.setItem("fontSize",e(this).attr("value")),t.iframe.contentDocument.location.reload(!0)})})}function f(t,n){var r=e("<ul>"),i=n==1?"chapter":"section";return t.forEach(function(t){var s,o=e("<li id='toc-"+t.id+"'>"),u=e("<a class='toc_link "+i+"' href='#/"+t.href+"' data-url='"+t.href+"'>"+t.label+"</a>");o.append(u),t.subitems&&t.subitems.length&&(n++,s=f(t.subitems,n),o.append(s)),r.append(o)}),r}function l(){var n=e("#divider"),r=e("#loader");r.hide(),t.single||n.addClass("show")}function c(){var t=e("#store");n=!1,t.attr("src","img/save.png")}function h(){var t=e("#store");n=!0,t.attr("src","img/saved.png")}function p(t){var n=t.msg,r=e("#toc-"+n),i=e(".currentChapter");r.length&&(i.removeClass("currentChapter"),r.addClass("currentChapter"))}function d(){function y(){f.addClass("open"),u.addClass("closed"),c.attr("src","img/close.png")}function b(){a.css("pointer-events","visible"),f.removeClass("open"),u.removeClass("closed"),c.attr("src","img/menu-icon.png")}function w(){v.hide(),d.show()}function E(){d.hide(),v.show()}var s=e("#next"),o=e("#prev"),u=e("#main"),a=e("#area"),f=e("#sidebar"),l=e("#open"),c=l.find("img"),h=e("#network"),p=e("#setting"),d=e("#settingsPanel"),v=e("#toc"),m=e(window);m.on("resize",function(){i=e(window).width(),i>550?u.width(i-r):u.width(i)}),s.on("click",function(){t.nextPage()}),o.on("click",function(){t.prevPage()}),p.on("click",function(){d.is(":visible")?E():w()}),m.bind("touchy-swipe",function(e,n,r,i){(i.direction="left")&&t.nextPage(),(i.direction="right")&&t.prevPage()});var g=!1;e(document).keydown(function(e){if(g)return;if(e.keyCode==37)return o.trigger("click"),g=!0,setTimeout(function(){g=!1},100),!1;if(e.keyCode==39)return s.trigger("click"),g=!0,setTimeout(function(){g=!1},100),!1}),l.on("click",function(){f.hasClass("open")?b():y()}),h.on("click",function(){n=!n,t.fromStorage(n)})}var t,n=!1,r=0,i;return s}(jQuery),jQuery.fn.extend({clickOutside:function(e,t){var n=this;return jQuery(document).on("click.offer",function(r){if(t&&jQuery.inArray(r.target,t)>-1)return;if(jQuery.contains(n[0],r.target))return;jQuery(document).off("click.offer"),e(r,n)}),this}}); var EPUBJSR=EPUBJSR||{};EPUBJSR.app={},EPUBJSR.app.init=function(e){"use strict";function s(n){var s=window.location.search.match(/book=(.*)/),n=n||(s?s[1]:"moby-dick");i=e(window).width(),i>550?e("#main").width(i-r):e("#main").width(i),t=new EPUBJS.Book(n),t.on("book:online",c),t.on("book:offline",h),t.getMetadata().then(o),t.getToc().then(u),t.ready.all.then(l),t.renderTo("area"),e(function(){d()})}function o(t){var n=t.bookTitle,r=t.creator,i=e("#book-title"),s=e("#chapter-title"),o=e("#title-seperator");document.title=n+" "+r,i.html(n),s.html(r),o.show()}function u(n){var r=e("#toc"),i,s;r.empty(),s=f(n,1),r.append(s),i=e(".toc_link"),i.on("click",function(n){var r=e(this),i=r.data("url");e(".openChapter").removeClass("openChapter"),r.parents("li").addClass("openChapter"),t.goto(i),n.preventDefault()})}function a(){var n="";localStorage.getItem("fontSize")?n=localStorage.getItem("fontSize"):(n="medium",localStorage.setItem("fontSize",n));var r=e("#settingsPanel");r.append("<ul></ul>");var i=e("<li><h3></h3></li>"),s=e("<input type='radio' name='fontSize' value='x-small'><span class='xsmall'>Extra Small</span><br><input type='radio' name='fontSize' value='small'><span class='small'>Small</span><br><input type='radio' name='fontSize' value='medium'><span class='medium'>Medium</span><br><input type='radio' name='fontSize' value='large'><span class='large'>Large</span><br><input type='radio' name='fontSize' value='x-large'><span class='xlarge'>Extra Large</span>");i.find("h3").text("Font Size").after(s),r.find("ul").append(i);var o=e('input[name="fontSize"]');o.each(function(){e(this).attr("value")==n&&e(this).attr("checked","checked"),e(this).on("click",function(){localStorage.setItem("fontSize",e(this).attr("value")),t.iframe.contentDocument.location.reload(!0)})})}function f(t,n){var r=e("<ul>"),i=n==1?"chapter":"section";return t.forEach(function(t){var s,o=e("<li id='toc-"+t.id+"'>"),u=e("<a class='toc_link "+i+"' href='#/"+t.href+"' data-url='"+t.href+"'>"+t.label+"</a>");o.append(u),t.subitems&&t.subitems.length&&(n++,s=f(t.subitems,n),o.append(s)),r.append(o)}),r}function l(){var n=e("#divider"),r=e("#loader");r.hide(),t.single||n.addClass("show")}function c(){var t=e("#store");n=!1,t.attr("src",t.data("save"))}function h(){var t=e("#store");n=!0,t.attr("src",t.data("saved"))}function p(t){var n=t.msg,r=e("#toc-"+n),i=e(".currentChapter");r.length&&(i.removeClass("currentChapter"),r.addClass("currentChapter"))}function d(){function y(){f.addClass("open"),u.addClass("closed"),c.attr("src",c.data("close"))}function b(){a.css("pointer-events","visible"),f.removeClass("open"),u.removeClass("closed"),c.attr("src",c.data("open"))}function w(){v.hide(),d.show()}function E(){d.hide(),v.show()}var s=e("#next"),o=e("#prev"),u=e("#main"),a=e("#area"),f=e("#sidebar"),l=e("#open"),c=l.find("img"),h=e("#network"),p=e("#setting"),d=e("#settingsPanel"),v=e("#toc"),m=e(window);m.on("resize",function(){i=e(window).width(),i>550?u.width(i-r):u.width(i)}),s.on("click",function(){t.nextPage()}),o.on("click",function(){t.prevPage()}),p.on("click",function(){d.is(":visible")?E():w()});var g=!1;e(document).keydown(function(e){if(g)return;if(e.keyCode==37)return o.trigger("click"),g=!0,setTimeout(function(){g=!1},100),!1;if(e.keyCode==39)return s.trigger("click"),g=!0,setTimeout(function(){g=!1},100),!1}),l.on("click",function(){f.hasClass("open")?b():y()}),h.on("click",function(){n=!n,t.fromStorage(n)})}var t,n=!1,r=0,i;return s}(jQuery),jQuery.fn.extend({clickOutside:function(e,t){var n=this;return jQuery(document).on("click.offer",function(r){if(t&&jQuery.inArray(r.target,t)>-1)return;if(jQuery.contains(n[0],r.target))return;jQuery(document).off("click.offer"),e(r,n)}),this}});

0
documentation/api.txt Normal file
View file

View file

@ -15,7 +15,6 @@
<script>window.jQuery || document.write('<script src="epubjs/libs/jquery-1.9.0.min.js"><\/script>')</script> <script>window.jQuery || document.write('<script src="epubjs/libs/jquery-1.9.0.min.js"><\/script>')</script>
--> -->
<script src="../libs/jquery/jquery-1.9.0.js"></script> <script src="../libs/jquery/jquery-1.9.0.js"></script>
<script src="../libs/modernizr/modernizr-2.6.2.min.js"></script>
<script> <script>
"use strict"; "use strict";
@ -25,7 +24,7 @@
fileStorage.filePath = "../libs/fileStorage/workers/"; fileStorage.filePath = "../libs/fileStorage/workers/";
EPUBJS.VERSION = "0.1.5"; EPUBJS.VERSION = "0.1.5";
EPUBJSR.app.init(); EPUBJSR.app.init('/demo/moby-dick');
} }
}; };
@ -34,15 +33,19 @@
<!--<script async src="epubjs/libs/jquery.touchy.min.js"></script>--> <!--<script async src="epubjs/libs/jquery.touchy.min.js"></script>-->
<!-- Render --> <!-- Render -->
<script src="../libs/underscore/underscore.js"></script>
<script src="../libs/rsvp/rsvp.js"></script>
<script src="../libs/fileStorage/fileStorage.min.js"></script>
<script src="../src/base.js"></script> <script src="../src/base.js"></script>
<script src="../src/core.js"></script> <script src="../src/core.js"></script>
<script src="../src/unarchiver.js"></script> <script src="../src/unarchiver.js"></script>
<script src="../libs/fileStorage/fileStorage.min.js"></script> <script src="../src/parser.js"></script>
<script src="../src/events.js"></script>
<script src="../src/hooks.js"></script> <script src="../src/hooks.js"></script>
<script src="../src/book.js"></script> <script src="../src/book.js"></script>
<script src="../src/chapter.js"></script> <script src="../src/chapter.js"></script>
<script src="../src/renderer.js"></script>
<script src="../src/epubcfi.js"></script>
<!-- Plugins --> <!-- Plugins -->
<script async src="../hooks/default/transculsions.js"></script> <script async src="../hooks/default/transculsions.js"></script>
@ -59,7 +62,7 @@
<div id="controls"> <div id="controls">
<input id="search" placeholder="search"> <input id="search" placeholder="search">
<a id="network"><img id="store" src="../demo/img/save.png"></a> <a id="network"><img id="store" src="../demo/img/save.png" save="../demo/img/save.png" data-saved="../demo/img/saved.png"></a>
<a id="setting"><img id="settings" src="../demo/img/settings.png"></a> <a id="setting"><img id="settings" src="../demo/img/settings.png"></a>
<a id="bookmark"><img id="bookmarks" src="../demo/img/star.png"></a> <a id="bookmark"><img id="bookmarks" src="../demo/img/star.png"></a>
</div> </div>
@ -71,7 +74,7 @@
</div> </div>
<div id="main"> <div id="main">
<div id="opener"> <div id="opener">
<a id="open"><img src="../demo/img/menu-icon.png"></a> <a id="open"><img src="../demo/img/menu-icon.png" data-close="../demo/img/close.png" data-open="../demo/img/menu-icon.png"></a>
</div> </div>
<div id="titlebar"> <div id="titlebar">
<span id="book-title"></span> <span id="book-title"></span>

View file

@ -13,11 +13,10 @@ module.exports = function(grunt) {
'build/hooks.js': ['<banner>', 'hooks/default/*.js'], 'build/hooks.js': ['<banner>', 'hooks/default/*.js'],
'demo/js/libs/fileStorage.min.js': 'libs/fileStorage/fileStorage.min.js', 'demo/js/libs/fileStorage.min.js': 'libs/fileStorage/fileStorage.min.js',
'demo/js/libs/loader_filesystem.min.js': 'libs/fileStorage/workers/loader_filesystem.min.js', 'demo/js/libs/loader_filesystem.min.js': 'libs/fileStorage/workers/loader_filesystem.min.js',
'demo/js/libs/jquery-1.9.0.min.js': 'libs/jquery/jquery-1.9.0.min.js', 'demo/js/libs/jquery-1.9.0.min.js': 'libs/jquery/jquery-1.9.0.min.js'
'demo/js/libs/modernizr-2.6.2.min.js': 'libs/modernizr/modernizr-2.6.2.min.js'
}, },
min: { min: {
'demo/js/epub.min.js': 'build/epub.js', 'demo/js/epub.min.js': ['libs/underscore/underscore-min.js', 'libs/rsvp/rsvp.min.js', 'build/epub.js'],
'demo/js/reader.min.js': 'build/reader.js', 'demo/js/reader.min.js': 'build/reader.js',
'demo/js/hooks.min.js': 'build/hooks.js', 'demo/js/hooks.min.js': 'build/hooks.js',
'demo/js/libs/zip.min.js': ['libs/zip/*.js'] 'demo/js/libs/zip.min.js': ['libs/zip/*.js']

View file

@ -9482,6 +9482,7 @@ jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( me
}); });
function getWindow( elem ) { function getWindow( elem ) {
console.log(elem.nodeType);
return jQuery.isWindow( elem ) ? return jQuery.isWindow( elem ) ?
elem : elem :
elem.nodeType === 9 ? elem.nodeType === 9 ?

File diff suppressed because one or more lines are too long

289
libs/rsvp/rsvp.js Normal file
View file

@ -0,0 +1,289 @@
(function(exports) {
"use strict";
var config = {};
var browserGlobal = (typeof window !== 'undefined') ? window : {};
var MutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
var RSVP;
if (typeof process !== 'undefined' &&
{}.toString.call(process) === '[object process]') {
config.async = function(callback, binding) {
process.nextTick(function() {
callback.call(binding);
});
};
} else if (MutationObserver) {
var queue = [];
var observer = new MutationObserver(function() {
var toProcess = queue.slice();
queue = [];
toProcess.forEach(function(tuple) {
var callback = tuple[0], binding = tuple[1];
callback.call(binding);
});
});
var element = document.createElement('div');
observer.observe(element, { attributes: true });
// Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661
window.addEventListener('unload', function(){
observer.disconnect();
observer = null;
});
config.async = function(callback, binding) {
queue.push([callback, binding]);
element.setAttribute('drainQueue', 'drainQueue');
};
} else {
config.async = function(callback, binding) {
setTimeout(function() {
callback.call(binding);
}, 1);
};
}
var Event = function(type, options) {
this.type = type;
for (var option in options) {
if (!options.hasOwnProperty(option)) { continue; }
this[option] = options[option];
}
};
var indexOf = function(callbacks, callback) {
for (var i=0, l=callbacks.length; i<l; i++) {
if (callbacks[i][0] === callback) { return i; }
}
return -1;
};
var callbacksFor = function(object) {
var callbacks = object._promiseCallbacks;
if (!callbacks) {
callbacks = object._promiseCallbacks = {};
}
return callbacks;
};
var EventTarget = {
mixin: function(object) {
object.on = this.on;
object.off = this.off;
object.trigger = this.trigger;
return object;
},
on: function(eventNames, callback, binding) {
var allCallbacks = callbacksFor(this), callbacks, eventName;
eventNames = eventNames.split(/\s+/);
binding = binding || this;
while (eventName = eventNames.shift()) {
callbacks = allCallbacks[eventName];
if (!callbacks) {
callbacks = allCallbacks[eventName] = [];
}
if (indexOf(callbacks, callback) === -1) {
callbacks.push([callback, binding]);
}
}
},
off: function(eventNames, callback) {
var allCallbacks = callbacksFor(this), callbacks, eventName, index;
eventNames = eventNames.split(/\s+/);
while (eventName = eventNames.shift()) {
if (!callback) {
allCallbacks[eventName] = [];
continue;
}
callbacks = allCallbacks[eventName];
index = indexOf(callbacks, callback);
if (index !== -1) { callbacks.splice(index, 1); }
}
},
trigger: function(eventName, options) {
var allCallbacks = callbacksFor(this),
callbacks, callbackTuple, callback, binding, event;
if (callbacks = allCallbacks[eventName]) {
for (var i=0, l=callbacks.length; i<l; i++) {
callbackTuple = callbacks[i];
callback = callbackTuple[0];
binding = callbackTuple[1];
if (typeof options !== 'object') {
options = { detail: options };
}
event = new Event(eventName, options);
callback.call(binding, event);
}
}
}
};
var Promise = function() {
this.on('promise:resolved', function(event) {
this.trigger('success', { detail: event.detail });
}, this);
this.on('promise:failed', function(event) {
this.trigger('error', { detail: event.detail });
}, this);
};
var noop = function() {};
var invokeCallback = function(type, promise, callback, event) {
var hasCallback = typeof callback === 'function',
value, error, succeeded, failed;
if (hasCallback) {
try {
value = callback(event.detail);
succeeded = true;
} catch(e) {
failed = true;
error = e;
}
} else {
value = event.detail;
succeeded = true;
}
if (value && typeof value.then === 'function') {
value.then(function(value) {
promise.resolve(value);
}, function(error) {
promise.reject(error);
});
} else if (hasCallback && succeeded) {
promise.resolve(value);
} else if (failed) {
promise.reject(error);
} else {
promise[type](value);
}
};
Promise.prototype = {
then: function(done, fail) {
var thenPromise = new Promise();
if (this.isResolved) {
config.async(function() {
invokeCallback('resolve', thenPromise, done, { detail: this.resolvedValue });
}, this);
}
if (this.isRejected) {
config.async(function() {
invokeCallback('reject', thenPromise, fail, { detail: this.rejectedValue });
}, this);
}
this.on('promise:resolved', function(event) {
invokeCallback('resolve', thenPromise, done, event);
});
this.on('promise:failed', function(event) {
invokeCallback('reject', thenPromise, fail, event);
});
return thenPromise;
},
resolve: function(value) {
resolve(this, value);
this.resolve = noop;
this.reject = noop;
},
reject: function(value) {
reject(this, value);
this.resolve = noop;
this.reject = noop;
}
};
function resolve(promise, value) {
config.async(function() {
promise.trigger('promise:resolved', { detail: value });
promise.isResolved = true;
promise.resolvedValue = value;
});
}
function reject(promise, value) {
config.async(function() {
promise.trigger('promise:failed', { detail: value });
promise.isRejected = true;
promise.rejectedValue = value;
});
}
function all(promises) {
var i, results = [];
var allPromise = new Promise();
var remaining = promises.length;
if (remaining === 0) {
allPromise.resolve([]);
}
var resolver = function(index) {
return function(value) {
resolve(index, value);
};
};
var resolve = function(index, value) {
results[index] = value;
if (--remaining === 0) {
allPromise.resolve(results);
}
};
var reject = function(error) {
allPromise.reject(error);
};
for (i = 0; i < remaining; i++) {
promises[i].then(resolver(i), reject);
}
return allPromise;
}
EventTarget.mixin(Promise.prototype);
function configure(name, value) {
config[name] = value;
}
exports.Promise = Promise;
exports.Event = Event;
exports.EventTarget = EventTarget;
exports.all = all;
exports.configure = configure;
})(window.RSVP = {});

1
libs/rsvp/rsvp.min.js vendored Normal file
View file

@ -0,0 +1 @@
(function(e){"use strict";function v(e,n){t.async(function(){e.trigger("promise:resolved",{detail:n}),e.isResolved=!0,e.resolvedValue=n})}function m(e,n){t.async(function(){e.trigger("promise:failed",{detail:n}),e.isRejected=!0,e.rejectedValue=n})}function g(e){var t,n=[],r=new h,i=e.length;i===0&&r.resolve([]);var s=function(e){return function(t){o(e,t)}},o=function(e,t){n[e]=t,--i===0&&r.resolve(n)},u=function(e){r.reject(e)};for(t=0;t<i;t++)e[t].then(s(t),u);return r}function y(e,n){t[e]=n}var t={},n=typeof window!="undefined"?window:{},r=n.MutationObserver||n.WebKitMutationObserver,i;if(typeof process!="undefined"&&{}.toString.call(process)==="[object process]")t.async=function(e,t){process.nextTick(function(){e.call(t)})};else if(r){var s=[],o=new r(function(){var e=s.slice();s=[],e.forEach(function(e){var t=e[0],n=e[1];t.call(n)})}),u=document.createElement("div");o.observe(u,{attributes:!0}),window.addEventListener("unload",function(){o.disconnect(),o=null}),t.async=function(e,t){s.push([e,t]),u.setAttribute("drainQueue","drainQueue")}}else t.async=function(e,t){setTimeout(function(){e.call(t)},1)};var a=function(e,t){this.type=e;for(var n in t){if(!t.hasOwnProperty(n))continue;this[n]=t[n]}},f=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n][0]===t)return n;return-1},l=function(e){var t=e._promiseCallbacks;return t||(t=e._promiseCallbacks={}),t},c={mixin:function(e){return e.on=this.on,e.off=this.off,e.trigger=this.trigger,e},on:function(e,t,n){var r=l(this),i,s;e=e.split(/\s+/),n=n||this;while(s=e.shift())i=r[s],i||(i=r[s]=[]),f(i,t)===-1&&i.push([t,n])},off:function(e,t){var n=l(this),r,i,s;e=e.split(/\s+/);while(i=e.shift()){if(!t){n[i]=[];continue}r=n[i],s=f(r,t),s!==-1&&r.splice(s,1)}},trigger:function(e,t){var n=l(this),r,i,s,o,u;if(r=n[e])for(var f=0,c=r.length;f<c;f++)i=r[f],s=i[0],o=i[1],typeof t!="object"&&(t={detail:t}),u=new a(e,t),s.call(o,u)}},h=function(){this.on("promise:resolved",function(e){this.trigger("success",{detail:e.detail})},this),this.on("promise:failed",function(e){this.trigger("error",{detail:e.detail})},this)},p=function(){},d=function(e,t,n,r){var i=typeof n=="function",s,o,u,a;if(i)try{s=n(r.detail),u=!0}catch(f){a=!0,o=f}else s=r.detail,u=!0;s&&typeof s.then=="function"?s.then(function(e){t.resolve(e)},function(e){t.reject(e)}):i&&u?t.resolve(s):a?t.reject(o):t[e](s)};h.prototype={then:function(e,n){var r=new h;return this.isResolved&&t.async(function(){d("resolve",r,e,{detail:this.resolvedValue})},this),this.isRejected&&t.async(function(){d("reject",r,n,{detail:this.rejectedValue})},this),this.on("promise:resolved",function(t){d("resolve",r,e,t)}),this.on("promise:failed",function(e){d("reject",r,n,e)}),r},resolve:function(e){v(this,e),this.resolve=p,this.reject=p},reject:function(e){m(this,e),this.resolve=p,this.reject=p}},c.mixin(h.prototype),e.Promise=h,e.Event=a,e.EventTarget=c,e.all=g,e.configure=y})(window.RSVP={});

1
libs/underscore/underscore-min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@ EPUBJSR.app.init = (function($){
bookURL = bookURL || (search ? search[1] : "moby-dick"); bookURL = bookURL || (search ? search[1] : "moby-dick");
//-- Setup the browser prefixes //-- Setup the browser prefixes
EPUBJS.core.crossBrowserColumnCss(); // EPUBJS.core.crossBrowserColumnCss();
//-- Set up our sidebar //-- Set up our sidebar
windowWidth = $(window).width(); windowWidth = $(window).width();
@ -24,27 +24,38 @@ EPUBJSR.app.init = (function($){
$("#main").width(windowWidth); $("#main").width(windowWidth);
} }
loadSettings();
//-- Create a new book object, //-- Create a new book object,
// this will create an iframe in the el with the ID provided // this will create an iframe in the el with the ID provided
Book = new EPUBJS.Book("area"); Book = new EPUBJS.Book(bookURL);
//Book.single = true; //Book.single = true;
//-- Add listeners to handle book events //-- Add listeners to handle book events
//-- Full list of event are at start of book.js //-- Full list of event are at start of book.js
Book.listen("book:metadataReady", meta);
Book.listen("book:tocReady", toc);
Book.listen("book:bookReady", bookReady); // Book.listen("book:metadataReady", meta);
Book.listen("book:chapterReady", chapterChange); // Book.listen("book:tocReady", toc);
Book.listen("book:online", goOnline); // Book.listen("book:bookReady", bookReady);
Book.listen("book:offline", goOffline); // Book.listen("book:chapterReady", chapterChange);
Book.on("book:online", goOnline);
Book.on("book:offline", goOffline);
Book.getMetadata().then(meta);
Book.getToc().then(toc);
Book.ready.all.then(bookReady);
Book.renderTo("area");
//Book.registerHook("beforeChapterDisplay", EPUBJS.Hooks.transculsions.insert); //Book.registerHook("beforeChapterDisplay", EPUBJS.Hooks.transculsions.insert);
//-- Start loading / parsing of the book. //-- Start loading / parsing of the book.
// This must be done AFTER adding listeners or hooks // This must be done AFTER adding listeners or hooks
Book.start(bookURL); //Book.renderTo("area");
//-- Wait for Dom ready to handle jquery //-- Wait for Dom ready to handle jquery
$(function() { $(function() {
@ -54,9 +65,9 @@ EPUBJSR.app.init = (function($){
} }
function meta(){ function meta(meta){
var title = Book.getTitle(), var title = meta.bookTitle,//Book.getTitle(),
author = Book.getCreator(), author = meta.creator, //Book.getCreator(),
$title = $("#book-title"), $title = $("#book-title"),
$author = $("#chapter-title"), $author = $("#chapter-title"),
$dash = $("#title-seperator"); $dash = $("#title-seperator");
@ -68,17 +79,16 @@ EPUBJSR.app.init = (function($){
} }
function toc(){ function toc(contents){
var contents = Book.getTOC(), var $toc = $("#toc"),
$toc = $("#toc"),
$links, $links,
$items; $items;
$toc.empty(); $toc.empty();
//-- Recursively generate TOC levels //-- Recursively generate TOC levels
$items = generateTocItems(contents, 1); $items = generateTocItems(contents, 1);
$toc.append($items); $toc.append($items);
$links = $(".toc_link"); $links = $(".toc_link");
@ -94,15 +104,14 @@ EPUBJSR.app.init = (function($){
//-- Provide the Book with the url to show //-- Provide the Book with the url to show
// The Url must be found in the books manifest // The Url must be found in the books manifest
Book.goto(url);
e.preventDefault();
if(!Book.useHash){
Book.show(url);
e.preventDefault();
}
}); });
} }
function loadSettings() { function loadSettings() {
@ -195,14 +204,13 @@ EPUBJSR.app.init = (function($){
function generateTocItems(contents, level){ function generateTocItems(contents, level){
var $container = $("<ul>"); var $container = $("<ul>");
var type = (level == 1) ? "chapter" : "section"; var type = (level == 1) ? "chapter" : "section";
contents.forEach(function(item){ contents.forEach(function(item){
var $subitems, var $subitems,
$wrapper = $("<li id='toc-"+item.id+"'>"), $wrapper = $("<li id='toc-"+item.id+"'>"),
$item = $("<a class='toc_link " + type + "' href='#/"+item.href+"' data-url='"+item.href+"'>"+item.label+"</a>"); $item = $("<a class='toc_link " + type + "' href='#/"+item.href+"' data-url='"+item.href+"'>"+item.label+"</a>");
$wrapper.append($item); $wrapper.append($item);
if(item.subitems && item.subitems.length){ if(item.subitems && item.subitems.length){
level++; level++;
$subitems = generateTocItems(item.subitems, level); $subitems = generateTocItems(item.subitems, level);
@ -229,14 +237,14 @@ EPUBJSR.app.init = (function($){
function goOnline(){ function goOnline(){
var $icon = $("#store"); var $icon = $("#store");
offline = false; offline = false;
$icon.attr("src", "img/save.png"); $icon.attr("src", $icon.data("save"));
} }
function goOffline(){ function goOffline(){
var $icon = $("#store"); var $icon = $("#store");
offline = true; offline = true;
$icon.attr("src", "img/saved.png"); $icon.attr("src", $icon.data("saved"));
} }
@ -292,19 +300,7 @@ EPUBJSR.app.init = (function($){
} }
}); });
//-- TODO: This doesn't seem to work
$window.bind("touchy-swipe", function(event, phase, $target, data){
if(data.direction = "left"){
Book.nextPage();
}
if(data.direction = "right"){
Book.prevPage();
}
});
var lock = false; var lock = false;
@ -335,14 +331,14 @@ EPUBJSR.app.init = (function($){
//$book.css("pointer-events", "none"); //-- Avoid capture by ifrmae //$book.css("pointer-events", "none"); //-- Avoid capture by ifrmae
$sidebar.addClass("open"); $sidebar.addClass("open");
$main.addClass("closed"); $main.addClass("closed");
$icon.attr("src", "img/close.png"); $icon.attr("src", $icon.data("close"));
} }
function hideSidebar(){ function hideSidebar(){
$book.css("pointer-events", "visible"); $book.css("pointer-events", "visible");
$sidebar.removeClass("open"); $sidebar.removeClass("open");
$main.removeClass("closed"); $main.removeClass("closed");
$icon.attr("src", "img/menu-icon.png"); $icon.attr("src",$icon.data("open"));
} }
function showSettings(){ function showSettings(){

File diff suppressed because it is too large Load diff

View file

@ -1,337 +1,43 @@
EPUBJS.Chapter = function(book, pos){ EPUBJS.Chapter = function(spineObject){
this.href = spineObject.href;
this.book = book; this.id = spineObject.id;
this.iframe = this.book.iframe; this.spinePos = spineObject.index;
this.properties = spineObject.properties;
this.pos = pos || this.book.spinePos this.linear = spineObject.linear;
this.chapInfo = this.book.spine[this.pos]; this.pages = 1;
//-- 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.prototype.load = function(){
var path = this.path;
if(this.book.online && !this.book.contained){ EPUBJS.Chapter.prototype.contents = function(store){
this.setIframeSrc(path); // if(this.store && (!this.book.online || this.book.contained))
if(store){
return store.get(href);
}else{ }else{
this.loadFromStorage(path); return EPUBJS.core.request(href, 'xml');
}
}
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;
} }
//-- 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); EPUBJS.Chapter.prototype.url = function(store){
var promise = new RSVP.Promise();
if(this.elWidth < cutoff || this.book.single) {
this.spread = false; //-- Single Page if(store){
return store.getUrl(href);
divisor = 1;
this.colWidth = Math.floor(this.elWidth / divisor);
}else{ }else{
this.spread = true; //-- Double Page promise.resolve(this.href); //-- this is less than ideal but keeps it a promise
return promise;
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.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(){ EPUBJS.Chapter.prototype.setPages = function(num){
this.paginated = false; this.pages = num;
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.goToChapterEnd = function(){ EPUBJS.Chapter.prototype.getPages = function(num){
this.chapterEnd(); return this.pages;
}
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.getID = function(){ EPUBJS.Chapter.prototype.getID = function(){
return this.ID; 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(); var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.overrideMimeType('text/xml'); xhr.open("GET", url);
xhr.onreadystatechange = handler;
xhr.onload = function(e) {
if (this.status == 200) { if(type == 'blob'){
callback(this.responseXML); xhr.responseType = type;
} }
};
if(type == "json") {
xhr.setRequestHeader("Accept", "application/json");
}
if(type == 'xml') {
xhr.overrideMimeType('text/xml');
}
xhr.send(); 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){ // EPUBJS.core.loadFile = function(url){
// var xhr = new XMLHttpRequest(), // var xhr = new XMLHttpRequest(),
@ -63,66 +109,47 @@ EPUBJS.core.loadXML = function(url, callback){
// "error" : failed // "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) { EPUBJS.core.toArray = function(obj) {
var arr = []; var arr = [];
@ -139,6 +166,16 @@ EPUBJS.core.toArray = function(obj) {
return arr; 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 //-- https://github.com/ebidel/filer.js/blob/master/src/filer.js#L128
EPUBJS.core.dataURLToBlob = function(dataURL) { EPUBJS.core.dataURLToBlob = function(dataURL) {
var BASE64_MARKER = ';base64,'; var BASE64_MARKER = ';base64,';
@ -220,3 +257,25 @@ EPUBJS.core.addScript = function(src, callback, target) {
target = target || document.body; target = target || document.body;
target.appendChild(s); 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);