'use strict';
/* globals ePub, localforage, book, cacheId, EpubeApp */
let _pagination_stored = 0;
let _last_position_sync = 0;
let _store_position = 0;
//const _is_ios = (/iPad|iPhone|iPod/).test(navigator.userAgent) && !window.MSStream;
const _res_data = [];
const DEFAULT_FONT_SIZE = 16;
const DEFAULT_FONT_FAMILY = "Georgia";
const DEFAULT_LINE_HEIGHT = 140;
function cacheId(suffix) {
return "epube-book." + $.urlParam("b") + (suffix ? "." + suffix : "");
}
function init_loader() {
// we need to preload resources for reader iframe because it can't utilize our
// service worker because while offline it is created outside our base server context
const res_names = [ "lib/bootstrap/v3/js/jquery.js", "lib/jquery.mobile-events.min.js",
"css/transitions.css",
"js/reader.js", "css/reader.css", "js/dict.js",
"themes/default.css", "themes/light.css", "themes/mocca.css", "themes/night.css",
"themes/plan9.css", "themes/gray.css", "themes/sepia.css" ];
for (let i = 0; i < res_names.length; i++) {
fetch(res_names[i], {credentials: 'same-origin'}).then(function(resp) {
if (resp.status == 200) {
resp.text().then(function(data) {
const url = new URL(resp.url);
url.searchParams.delete("ts");
_res_data[url.toString()] = data;
})
} else {
console.warn('loader failed for resource', res_names[i], resp);
}
});
}
check_resource_load(res_names, _res_data, 0);
}
function check_resource_load(res_names, res_data, attempt) {
console.log("check_resource_load", attempt, res_names.length, Object.keys(res_data).length);
if (attempt == 5) {
$(".loading_message").html("Unable to load resources.");
return;
}
if (res_names.length != Object.keys(res_data).length) {
window.setTimeout(function() {
check_resource_load(res_names, res_data, attempt+1);
}, 250);
} else {
init_reader();
}
}
function init_reader() {
if (typeof EpubeApp != "undefined") {
EpubeApp.setPage("PAGE_READER");
}
apply_theme();
/* global Cookie */
if (Cookie.get("is-epube-app") == "true") {
$("body").addClass("is-epube-app");
}
$(window).on('online', function() {
console.log("we're online, storing lastread");
const currentCfi = book.rendition.currentLocation().start.cfi;
const currentPage = parseInt(book.locations.percentageFromCfi(currentCfi) * 100);
$.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: currentPage,
cfi: currentCfi }, function(data) {
if (data.cfi) {
_last_position_sync = new Date().getTime()/1000;
}
})
.fail(function(e) {
if (e && e.status == 401) {
window.location = "index.php";
}
});
});
localforage.getItem(cacheId("book")).then(function(item) {
// ios doesn't work with FileReader for whatever reason
if (/*!_is_ios &&*/ item) {
console.log("loading from local storage");
const fileReader = new FileReader();
fileReader.onload = function() {
try {
book.open(this.result);
} catch (e) {
$(".loading_message").html("Unable to load book (local).");
console.log(e);
}
};
fileReader.readAsArrayBuffer(item);
} else {
console.log("loading from network");
if (navigator.onLine) {
const book_url = "backend.php?op=download&id=" + $.urlParam("id");
$(".loading_message").html("Downloading...");
fetch(book_url, {credentials: 'same-origin'}).then(function(resp) {
if (resp.status == 200) {
const bookId = $.urlParam("b");
resp.blob().then(function(blob) {
// if there's no base information cached yet, let's do that too
localforage.getItem(cacheId()).then(function(info) {
if (!info) {
$.post("backend.php", {op: "getinfo", id: bookId }, function(data) {
if (data) {
localforage.setItem(cacheId(), data);
if (data.has_cover) {
fetch("backend.php?op=cover&id=" + bookId, {credentials: 'same-origin'}).then(function(resp) {
if (resp.status == 200) {
localforage.setItem(cacheId('cover'), resp.blob());
}
});
}
}
});
}
});
const fileReader = new FileReader();
fileReader.onload = function() {
book.open(this.result).then(() => {
// let's store this for later
localforage.setItem(cacheId('book'), blob);
}).catch((e) => {
$(".loading_message").html("Unable to open book.
" + e + "");
});
};
fileReader.onerror = function(e) {
console.log('filereader error', e);
$(".loading_message").html("Unable to open book.
" + e + "");
}
fileReader.readAsArrayBuffer(blob);
}).catch((e) => {
console.log('blob error', e);
$(".loading_message").html("Unable to download book.
" + e + "");
});
} else {
$(".loading_message").html("Unable to download book: " + resp.status + ".");
}
}).catch(function(e) {
console.warn(e);
if ($(".loading").is(":visible")) {
$(".loading_message").html("Unable to load book (remote).
" + e + "");
}
});
} else {
$(".loading_message").html("This book is not available offline.");
}
}
});
const book = ePub();
window.book = book;
const rendition = book.renderTo("reader", {
width: '100%',
height: '100%',
minSpreadWidth: 961
});
const displayed = rendition.display();
// this sets default theme, then we apply CSS to already rendered content
// with apply_styles()
displayed.then(function () {
let fontSize;
let fontFamily;
let lineHeight;
//let themeName;
Promise.all([
localforage.getItem("epube.fontSize"),
localforage.getItem("epube.fontFamily"),
localforage.getItem("epube.lineHeight"),
localforage.getItem("epube.theme")
]).then(function(res) {
fontSize = res[0] ? res[0] + "px" : DEFAULT_FONT_SIZE + "px";
fontFamily = res[1] ? res[1] : DEFAULT_FONT_FAMILY;
lineHeight = res[2] ? res[2] + "%" : DEFAULT_LINE_HEIGHT + "%";
//themeName = res[3] ? res[3] : 'default';
rendition.themes.default({
html: {
'font-size': fontSize,
'font-family': "'" + fontFamily + "'",
'line-height': lineHeight,
'text-align': 'justify'
}
});
});
});
rendition.hooks.content.register(function(contents) {
contents.on("linkClicked", function(href) {
console.log('linkClicked', href);
if (href.indexOf("://") == -1) {
$(".prev_location_btn")
.attr("data-location-cfi", book.rendition.currentLocation().start.cfi)
.show();
window.setTimeout(function() {
show_ui(true);
}, 50);
}
});
const base_url = window.location.href.match(/^.*\//)[0];
const res_names = [ "lib/bootstrap/v3/js/jquery.js", "lib/jquery.mobile-events.min.js",
"js/reader.js", "js/dict.js" ];
const doc = contents.document;
for (let i = 0; i < res_names.length; i++) {
// we need to create script element with proper context, that is inside the iframe
const elem = doc.createElement("script");
elem.type = 'text/javascript';
elem.text = _res_data[base_url + res_names[i]];
doc.head.appendChild(elem);
}
$(contents.document.head)
.append($("