summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--js/index.js7
-rw-r--r--js/offline.js5
-rw-r--r--js/read.js649
-rw-r--r--read.html645
4 files changed, 659 insertions, 647 deletions
diff --git a/js/index.js b/js/index.js
index c0f2e84..a16dd44 100644
--- a/js/index.js
+++ b/js/index.js
@@ -4,6 +4,7 @@
let _dl_progress_timeout;
+/* exported cache_refresh */
function cache_refresh(force) {
if ('serviceWorker' in navigator) {
localforage.getItem("epube.cache-timestamp").then(function(stamp) {
@@ -21,6 +22,7 @@ function cache_refresh(force) {
return false;
}
+/* exported toggle_fav */
function toggle_fav(elem) {
const bookId = elem.getAttribute("data-book-id");
@@ -38,6 +40,7 @@ function toggle_fav(elem) {
$(elem).html(msg).attr('data-is-fav', data.status);
+ /* global index_mode */
if (index_mode == "favorites" && data.status == 0) {
$("#cell-" + bookId).remove();
}
@@ -48,6 +51,7 @@ function toggle_fav(elem) {
return false;
}
+/* global offline_remove */
function mark_offline(elem) {
const bookId = elem.getAttribute("data-book-id");
@@ -78,6 +82,7 @@ function mark_offline(elem) {
});
}
+/* exported mark_offline_books */
function mark_offline_books() {
const elems = $(".offline_dropitem");
@@ -159,6 +164,7 @@ function offline_cache(bookId, callback) {
});
}
+/* exported show_summary */
function show_summary(elem) {
const id = elem.getAttribute("data-book-id");
@@ -176,6 +182,7 @@ function show_summary(elem) {
return false;
}
+/* exported offline_get_all */
function offline_get_all() {
if (confirm("Download all books on this page?")) {
diff --git a/js/offline.js b/js/offline.js
index 6fd3ddd..4f9a13a 100644
--- a/js/offline.js
+++ b/js/offline.js
@@ -2,6 +2,7 @@
/* global localforage, Holder */
+/* exported offline_search */
function offline_search() {
const query = $(".search_query").val();
@@ -12,14 +13,17 @@ function offline_search() {
return false;
}
+/* exported offline_remove2 */
function offline_remove2(elem) {
const bookId = elem.getAttribute("data-book-id");
+ /* global offline_remove */
return offline_remove(bookId, function() {
$("#cell-" + bookId).remove();
});
}
+/* exported offline_clear */
function offline_clear() {
if (confirm("Remove all offline data?")) {
@@ -151,6 +155,7 @@ function populate_list() {
}
+/* exported show_summary */
function show_summary(elem) {
const bookId = elem.getAttribute("data-book-id");
diff --git a/js/read.js b/js/read.js
index f82fc8d..04d2c15 100644
--- a/js/read.js
+++ b/js/read.js
@@ -1,7 +1,630 @@
'use strict';
-/* global localforage, book, cacheId */
+/* globals ePub, localforage, book, cacheId */
+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.custom.js",
+ "css/transitions.css",
+ "js/reader.js", "css/reader.css", "js/dict.js",
+ "themes/default.css", "themes/mocca.css", "themes/night.css",
+ "themes/plan9.css", "themes/gray.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() {
+ apply_theme();
+
+ $(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");
+
+ // let's store this for later
+ localforage.setItem(cacheId('book'), resp.clone().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());
+ }
+ });
+ }
+ }
+ });
+ }
+ });
+
+ resp.blob().then(function(blob) {
+
+ const fileReader = new FileReader();
+
+ fileReader.onload = function() {
+ book.open(this.result);
+ };
+
+ fileReader.readAsArrayBuffer(blob);
+
+ });
+ } else {
+ $(".loading_message").html("Unable to download book: " + resp.status + ".");
+ }
+ }).catch(function(err) {
+ console.warn(err);
+
+ if ($(".loading").is(":visible")) {
+ $(".loading_message").html("Unable to load book (remote).");
+ }
+ });
+
+ } 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.custom.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($("<style type='text/css'>")
+ .text(_res_data[base_url + 'css/reader.css']));
+
+ return localforage.getItem("epube.theme").then(function(theme) {
+ if (!theme) theme = 'default';
+
+ const theme_url = base_url + 'themes/' + theme + '.css';
+
+ $(contents.document.head)
+ .append($("<style type='text/css' id='theme_css'>")
+ .text(_res_data[theme_url]));
+ });
+
+ });
+
+ $('#settings-modal').on('shown.bs.modal', function() {
+
+ localforage.getItem(cacheId("lastread")).then((item) => {
+ if (item && item.cfi) {
+ $(".lastread_input").val(item.page + '%');
+ }
+
+ $.post("backend.php", { op: "getlastread", id: $.urlParam("id") }, function(data) {
+ $(".lastread_input").val(data.page + '%');
+ });
+
+ });
+
+ localforage.getItem("epube.keep-ui-visible").then(function(keep) {
+ $(".keep_ui_checkbox")
+ .attr("checked", keep)
+ .on("click", function(elem) {
+ localforage.setItem("epube.keep-ui-visible", elem.checked);
+ });
+ });
+
+ localforage.getItem("epube.fontFamily").then(function(font) {
+ if (!font) font = DEFAULT_FONT_FAMILY;
+
+ $(".font_family").val(font);
+ });
+
+ localforage.getItem("epube.theme").then(function(theme) {
+ $(".theme_name").val(theme);
+ });
+
+ localforage.getItem("epube.fontSize").then(function(size) {
+
+ if (!size) size = DEFAULT_FONT_SIZE;
+
+ const zoom = $(".font_size").html("");
+
+ for (let i = 10; i <= 32; i++) {
+ const opt = $("<option>").val(i).html(i + " px");
+ zoom.append(opt);
+ }
+
+ zoom.val(size);
+
+ });
+
+ localforage.getItem("epube.lineHeight").then(function(height) {
+
+ if (!height) height = DEFAULT_LINE_HEIGHT;
+
+ const zoom = $(".line_height").html("");
+
+ for (let i = 100; i <= 220; i += 10) {
+ const opt = $("<option>").val(i).html(i + "%");
+ zoom.append(opt);
+ }
+
+ zoom.val(height);
+
+ });
+ });
+
+ $('#dict-modal').on('shown.bs.modal', function() {
+ $(".dict_result").scrollTop(0);
+ })
+
+ $(".dict_search_btn").on("click", function() {
+ $("#dict-modal").modal('hide');
+ window.open("https://google.com/search?q=" + $(".dict_query").val());
+ });
+
+ function toc_loc_msg(href) {
+ try {
+ const cfiBase = book.spine.get(href).cfiBase;
+
+ const loc = book.locations._locations.find(function(k) {
+ return k.indexOf(cfiBase) != -1
+ });
+
+ return window.book.locations.locationFromCfi(loc);
+
+ } catch (e) {
+ console.warn(e);
+ }
+
+ return "";
+ }
+
+ function process_toc_sublist(row, list, nest) {
+
+ if (nest == 3) return false;
+
+ if (row.subitems) {
+
+ const sublist = $("<ul class='toc_sublist list-unstyled'>");
+
+ $.each(row.subitems, function(i, row) {
+
+ const a = $("<a>")
+ .attr('href', '#')
+ .html("<b class='pull-right'>" + toc_loc_msg(row.href) + "</b>" + row.label)
+ .attr('data-href', row.href)
+ .click(function() {
+ book.rendition.display(a.attr('data-href'));
+ });
+
+ sublist.append($("<li>").append(a));
+
+ process_toc_sublist(row, sublist, nest + 1);
+
+ });
+
+ list.append(sublist);
+ }
+ }
+
+ $('#toc-modal').on('shown.bs.modal', function() {
+
+ const toc = book.navigation.toc;
+
+ const list = $(".toc_list");
+ list.html("");
+
+ $.each(toc, function(i, row) {
+
+ // if anything fails here the toc entry is likely useless anyway (i.e. no cfi)
+ try {
+ const a = $("<a>")
+ .attr('href', '#')
+ .html("<b class='pull-right'>" + toc_loc_msg(row.href) + "</b>" + row.label)
+ .attr('data-href', row.href)
+ .click(function() {
+ book.rendition.display(a.attr('data-href'));
+ });
+
+ list.append($("<li>").append(a));
+
+ process_toc_sublist(row, list, 0);
+
+ } catch (e) {
+ console.warn(e);
+ }
+ });
+
+ // well the toc didn't work out, might as well generate one
+ if (list.children().length <= 1) {
+
+ list.html("");
+
+ $.each(book.spine.items, function (i, row) {
+
+ const a = $("<a>")
+ .attr('href', '#')
+ .attr('title', row.url)
+ .html("Section " + (i+1))
+ .attr('data-href', row.href)
+ .click(function() {
+ book.rendition.display(a.attr('data-href'));
+ });
+
+ list.append($("<li>").append(a));
+
+ });
+ }
+
+ });
+
+ book.ready.then(function() {
+
+ const meta = book.package.metadata;
+
+ document.title = meta.title + " – " + meta.creator;
+ $(".title").html("<b>" + meta.title + "</b> - " + meta.creator);
+
+ return localforage.getItem(cacheId("locations")).then(function(locations) {
+
+ console.log('stored pagination', locations != null);
+
+ // legacy format is array of objects {cfi: ..., page: ...}
+ if (locations && typeof locations[0] == "string") {
+ _pagination_stored = 1;
+ return book.locations.load(locations);
+ } else {
+ console.log("requesting pagination...");
+
+ const url = "backend.php?op=getpagination&id=" + encodeURIComponent($.urlParam("id"));
+
+ return fetch(url, {credentials:'same-origin'}).then(function(resp) {
+
+ if (resp.ok) {
+ return resp.json().then(function(locations) {
+ if (locations && typeof locations[0] == "string") {
+ _pagination_stored = 1;
+ return book.locations.load(locations);
+ } else {
+ $(".loading_message").html("Paginating...");
+ return book.locations.generate(1600);
+ }
+ });
+ } else {
+ $(".loading_message").html("Paginating...");
+ return book.locations.generate(1600);
+ }
+ }).catch(function() {
+ $(".loading_message").html("Paginating...");
+ return book.locations.generate(1600);
+ });
+ }
+
+ });
+
+ }).then(function(locations) {
+
+ console.log("locations ready, stored=", _pagination_stored);
+
+ if (locations) {
+ if (navigator.onLine && !_pagination_stored) {
+ $.post("backend.php", { op: "storepagination", id: $.urlParam("id"),
+ payload: JSON.stringify(locations), total: 100});
+ }
+
+ // store if needed
+ localforage.getItem(cacheId("locations")).then(function(item) {
+ if (!item) localforage.setItem(cacheId("locations"), locations);
+ });
+
+ } else {
+ $(".loading_message").html("Pagination failed.");
+ return;
+ }
+
+ $(".location").click(function() {
+ const current = book.rendition.currentLocation().start.location;
+ const total = book.locations.length();
+
+ const page = prompt("Jump to location [1-" + total + "]", current);
+
+ if (page) {
+ book.rendition.display(book.locations._locations[page]);
+ }
+ });
+
+ open_lastread();
+
+ window.setTimeout(function() {
+ open_lastread();
+
+ $(".loading").hide();
+ }, 250);
+ });
+
+ rendition.on("keyup", hotkey_handler);
+
+ rendition.on('resized', function() {
+ console.log('resized');
+
+ $(".loading").show();
+ $(".loading_message").html("Opening chapter...");
+
+ window.setTimeout(function() {
+ open_lastread();
+
+ $(".loading").hide();
+ }, 250);
+ });
+
+ rendition.on('rendered', function(/*chapter*/) {
+ $(".chapter").html($("<span>").addClass("glyphicon glyphicon-th-list"));
+
+ resize_side_columns();
+
+ try {
+ const location = book.rendition.currentLocation();
+
+ if (location.start) {
+ const cur_href = book.canonical(location.start.href);
+ let toc_entry = false;
+
+ /* eslint-disable no-inner-declarations */
+ function iterate_sublist(row, nest) {
+ if (nest == 2) return false;
+
+ if (row.subitems) {
+ $.each(row.subitems, function (i, r) {
+
+ if (book.spine.get(r.href).canonical == cur_href) {
+ toc_entry = r;
+ return true;
+ }
+
+ if (iterate_sublist(r, nest + 0))
+ return true;
+ });
+ }
+
+ return false;
+ }
+ /* eslint-enable no-inne-declarations */
+
+ $.each(book.navigation.toc, function(i, a) {
+ if (book.spine.get(a.href).canonical == cur_href) {
+ toc_entry = a;
+ return;
+ }
+
+ if (iterate_sublist(a, 0)) return;
+
+ });
+
+ if (toc_entry && toc_entry.label.trim())
+ $(".chapter").append("&nbsp;" + toc_entry.label);
+ }
+
+ } catch (e) {
+ console.warn(e);
+ }
+ });
+
+ rendition.on('relocated', function(location) {
+
+ // locations not generated yet
+ if (book.locations.length() == 0)
+ return;
+
+ const currentCfi = location.start.cfi;
+ const currentPage = parseInt(book.locations.percentageFromCfi(currentCfi) * 100);
+ const pct = book.locations.percentageFromCfi(currentCfi);
+
+ $("#cur_page").html(location.start.location);
+ $("#total_pages").html(book.locations.length());
+
+ $("#page_pct").html(parseInt(pct*100) + '%');
+
+ if (_store_position && new Date().getTime()/1000 - _last_position_sync > 15) {
+ console.log("storing lastread", currentPage, currentCfi);
+
+ if (navigator.onLine) {
+
+ $.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";
+ }
+ });
+
+ _store_position = 0;
+ } else {
+ _last_position_sync = 0;
+ }
+
+ localforage.setItem(cacheId("lastread"),
+ {cfi: currentCfi, page: currentPage, total: 100});
+
+ }
+ });
+
+}
+
+/* exported toggle_fullscreen */
function toggle_fullscreen() {
const element = document.documentElement;
const isFullscreen = document.webkitIsFullScreen || document.mozFullScreen || false;
@@ -22,6 +645,7 @@ function show_ui(show) {
$(".header,.footer").fadeOut();
}
+/* exported toggle_ui */
function toggle_ui() {
if ($(".header").is(":visible"))
$(".header,.footer").fadeOut();
@@ -137,6 +761,18 @@ function resize_side_columns() {
}
$(document).ready(function() {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker
+ .register('worker.js')
+ .then(function() {
+ console.log("service worker registered");
+
+ init_loader();
+ });
+ } else {
+ alert("Service worker support missing in browser (are you using plain HTTP?).");
+ }
+
$(document).on("keyup", function(e) {
hotkey_handler(e);
});
@@ -148,9 +784,9 @@ $(document).ready(function() {
$("#right").on("mouseup", function() {
next_page();
});
-
});
+/* exported apply_line_height */
function apply_line_height(elem) {
const height = $(elem).val();
@@ -159,6 +795,7 @@ function apply_line_height(elem) {
});
}
+/* exported apply_font */
function apply_font(elem) {
const font = $(elem).val();
@@ -168,6 +805,7 @@ function apply_font(elem) {
}
+/* exported apply_font_size */
function apply_font_size(elem) {
const size = $(elem).val();
@@ -200,6 +838,7 @@ function apply_styles() {
}
+/* exported clear_lastread */
function clear_lastread() {
if (confirm("Clear stored last read location?")) {
const total = window.book.locations.length();
@@ -216,6 +855,7 @@ function clear_lastread() {
}
}
+/* exported mark_as_read */
function mark_as_read() {
if (confirm("Mark book as read?")) {
const total = 100;
@@ -233,6 +873,7 @@ function mark_as_read() {
}
}
+/* exported save_and_close */
function save_and_close() {
const location = window.book.rendition.currentLocation();
@@ -256,6 +897,7 @@ function save_and_close() {
}
}
+/* exported change_theme */
function change_theme(elem) {
const theme = $(elem).val();
@@ -282,6 +924,7 @@ function apply_theme() {
});
}
+/* exported search */
function search() {
const query = $(".search_input").val();
const list = $(".search_results");
@@ -315,6 +958,7 @@ function search() {
}
}
+/* exported dict_lookup */
function dict_lookup(word, callback) {
$.post("backend.php", {op: 'define', word: word}, function(data) {
if (data) {
@@ -328,6 +972,7 @@ function dict_lookup(word, callback) {
});
}
+/* exported open_previous_location */
function open_previous_location(elem) {
const cfi = $(elem).attr("data-location-cfi");
diff --git a/read.html b/read.html
index 1ce7f7b..10b5497 100644
--- a/read.html
+++ b/read.html
@@ -233,650 +233,5 @@
</div>
</div>
-<script type='text/javascript'>
- 'use strict';
-
- let _pagination_stored = 0;
- let _last_position_sync = 0;
- let _store_position = 0;
- let _is_ios = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
- let _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 : "");
- }
-
- $(document).ready(function() {
- if ('serviceWorker' in navigator) {
- navigator.serviceWorker
- .register('worker.js')
- .then(function() {
- console.log("service worker registered");
-
- init_loader();
- });
- } else {
- alert("Service worker support missing in browser (are you using plain HTTP?).");
- }
- });
-
- 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
- var res_names = [ "lib/bootstrap/v3/js/jquery.js", "lib/jquery.mobile.custom.js",
- "css/transitions.css",
- "js/reader.js", "css/reader.css", "js/dict.js",
- "themes/default.css", "themes/mocca.css", "themes/night.css",
- "themes/plan9.css", "themes/gray.css" ];
-
- for (var 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) {
- var 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() {
- apply_theme();
-
- $(window).on('online', function() {
- console.log("we're online, storing lastread");
-
- var currentCfi = book.rendition.currentLocation().start.cfi;
- var 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");
-
- var fileReader = new FileReader();
-
- fileReader.onload = function(evt) {
- 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) {
- var 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) {
- var bookId = $.urlParam("b");
-
- // let's store this for later
- localforage.setItem(cacheId('book'), resp.clone().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());
- }
- });
- }
- }
- });
- }
- });
-
- resp.blob().then(function(blob) {
-
- var fileReader = new FileReader();
-
- fileReader.onload = function() {
- book.open(this.result);
- };
-
- fileReader.readAsArrayBuffer(blob);
-
- });
- } else {
- $(".loading_message").html("Unable to download book: " + resp.status + ".");
- }
- }).catch(function(err) {
- console.warn(err);
-
- if ($(".loading").is(":visible")) {
- $(".loading_message").html("Unable to load book (remote).");
- }
- });
-
- } else {
- $(".loading_message").html("This book is not available offline.");
- }
- }
- });
-
- var book = ePub();
-
- window.book = book;
-
- var rendition = book.renderTo("reader", {
- width: '100%',
- height: '100%',
- minSpreadWidth: 961
- });
-
- var displayed = rendition.display();
-
- var fontSize;
- var fontFamily;
- var lineHeight;
- var 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);
- }
-
- });
-
- var base_url = window.location.href.match(/^.*\//)[0];
- var res_names = [ "lib/bootstrap/v3/js/jquery.js", "lib/jquery.mobile.custom.js",
- "js/reader.js", "js/dict.js" ];
- var doc = contents.document;
-
- for (var i = 0; i < res_names.length; i++) {
-
- // we need to create script element with proper context, that is inside the iframe
- var 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($("<style type='text/css'>")
- .text(_res_data[base_url + 'css/reader.css']));
-
- /*localforage.getItem("epube.disable-transitions").then(function(notransitions) {
- if (!notransitions) {
- $(contents.document.head)
- .append($("<style type='text/css'>")
- .text(_res_data[base_url + 'css/transitions.css']));
-
- // TODO: fix transitions somehow
-
- EPUBJS.Render.Iframe.prototype.setLeft = function(leftPos){
- this.docEl.style[this.transform] = 'translate('+ (-leftPos) + 'px, 0)';
- }
- }
- }); */
-
- return localforage.getItem("epube.theme").then(function(theme) {
-
- if (!theme) theme = 'default';
-
- var theme_url = base_url + 'themes/' + theme + '.css';
-
- $(contents.document.head)
- .append($("<style type='text/css' id='theme_css'>")
- .text(_res_data[theme_url]));
- });
-
- });
-
- $('#settings-modal').on('shown.bs.modal', function() {
-
- localforage.getItem(cacheId("lastread")).then((item) => {
- if (item && item.cfi) {
- $(".lastread_input").val(item.page + '%');
- }
-
- $.post("backend.php", { op: "getlastread", id: $.urlParam("id") }, function(data) {
- $(".lastread_input").val(data.page + '%');
- });
-
- });
-
- /*localforage.getItem("epube.disable-transitions").then(function(disable) {
- $(".transition_checkbox")
- .attr("checked", disable)
- .on("click", function() {
- localforage.setItem("epube.disable-transitions", this.checked);
- });
- });*/
-
- localforage.getItem("epube.keep-ui-visible").then(function(keep) {
- $(".keep_ui_checkbox")
- .attr("checked", keep)
- .on("click", function() {
- localforage.setItem("epube.keep-ui-visible", this.checked);
- });
- });
-
- localforage.getItem("epube.fontFamily").then(function(font) {
- if (!font) font = DEFAULT_FONT_FAMILY;
-
- $(".font_family").val(font);
- });
-
- localforage.getItem("epube.theme").then(function(theme) {
- $(".theme_name").val(theme);
- });
-
- localforage.getItem("epube.fontSize").then(function(size) {
-
- if (!size) size = DEFAULT_FONT_SIZE;
-
- var zoom = $(".font_size").html("");
-
- for (var i = 10; i <= 32; i++) {
- var opt = $("<option>").val(i).html(i + " px");
-
- if (i == size) opt.attr("selected", "1");
-
- zoom.append(opt);
- }
-
- });
-
- localforage.getItem("epube.lineHeight").then(function(height) {
-
- if (!height) height = DEFAULT_LINE_HEIGHT;
-
- var zoom = $(".line_height").html("");
-
- for (var i = 100; i <= 220; i += 10) {
- var opt = $("<option>").val(i).html(i + "%");
-
- if (i == height) opt.attr("selected", "1");
-
- zoom.append(opt);
- }
-
- });
- })
-
- $('#dict-modal').on('shown.bs.modal', function() {
- $(".dict_result").scrollTop(0);
- })
-
- $(".dict_search_btn").on("click", function() {
- $("#dict-modal").modal('hide');
- window.open("https://google.com/search?q=" + $(".dict_query").val());
- });
-
- $('#toc-modal').on('shown.bs.modal', function() {
- function toc_loc_msg(href) {
- try {
- var cfiBase = book.spine.get(href).cfiBase;
-
- var loc = book.locations._locations.find(function(k) {
- return k.indexOf(cfiBase) != -1
- });
-
- return window.book.locations.locationFromCfi(loc);
-
- } catch (e) {
- console.warn(e);
- }
-
- return "";
- }
-
- function process_toc_sublist(row, list, nest) {
-
- if (nest == 3) return false;
-
- if (row.subitems) {
-
- var sublist = $("<ul class='toc_sublist list-unstyled'>");
-
- $.each(row.subitems, function(i, row) {
-
- var a = $("<a>")
- .attr('href', '#')
- .html("<b class='pull-right'>" + toc_loc_msg(row.href) + "</b>" + row.label)
- .attr('data-href', row.href)
- .click(function() {
- book.rendition.display(a.attr('data-href'));
- });
-
- sublist.append($("<li>").append(a));
-
- process_toc_sublist(row, sublist, nest + 1);
-
- });
-
- list.append(sublist);
- }
- }
-
- var toc = book.navigation.toc;
-
- var list = $(".toc_list");
- list.html("");
-
- $.each(toc, function(i, row) {
-
- // if anything fails here the toc entry is likely useless anyway (i.e. no cfi)
- try {
- var a = $("<a>")
- .attr('href', '#')
- .html("<b class='pull-right'>" + toc_loc_msg(row.href) + "</b>" + row.label)
- .attr('data-href', row.href)
- .click(function() {
- book.rendition.display(a.attr('data-href'));
- });
-
- list.append($("<li>").append(a));
-
- process_toc_sublist(row, list, 0);
-
- } catch (e) {
- console.warn(e);
- }
- });
-
- // well the toc didn't work out, might as well generate one
- if (list.children().length <= 1) {
-
- list.html("");
-
- $.each(book.spine.items, function (i, row) {
-
- var a = $("<a>")
- .attr('href', '#')
- .attr('title', row.url)
- .html("Section " + (i+1))
- .attr('data-href', row.href)
- .click(function() {
- book.rendition.display(a.attr('data-href'));
- });
-
- list.append($("<li>").append(a));
-
- });
- }
-
- });
-
- book.ready.then(function() {
-
- var meta = book.package.metadata;
-
- document.title = meta.title + " – " + meta.creator;
- $(".title").html("<b>" + meta.title + "</b> - " + meta.creator);
-
- return localforage.getItem(cacheId("locations")).then(function(locations) {
-
- // legacy format is array of objects {cfi: ..., page: ...}
- if (locations && typeof locations[0] == "string") {
- _pagination_stored = 1;
- return book.locations.load(locations);
- } else {
- var url = "backend.php?op=getpagination&id=" + encodeURIComponent($.urlParam("id"));
-
- return fetch(url, {credentials:'same-origin'}).then(function(resp) {
-
- if (resp.ok) {
- return resp.json().then(function(locations) {
- if (locations && typeof locations[0] == "string") {
- _pagination_stored = 1;
- return book.locations.load(locations);
- } else {
- $(".loading_message").html("Paginating...");
- return book.locations.generate(1600);
- }
- });
- } else {
- $(".loading_message").html("Paginating...");
- return book.locations.generate(1600);
- }
- }).catch(function() {
- $(".loading_message").html("Paginating...");
- return book.locations.generate(1600);
- });
- }
-
- });
-
- }).then(function(locations) {
-
- if (locations && !_pagination_stored) {
- if (navigator.onLine) {
- $.post("backend.php", { op: "storepagination", id: $.urlParam("id"),
- payload: JSON.stringify(locations), total: 100});
- }
-
- localforage.setItem(cacheId("locations"), locations);
-
- }
-
- $(".location").click(function() {
- var current = book.rendition.currentLocation().start.location;
- var total = book.locations.length();
-
- var page = prompt("Jump to location [1-" + total + "]", current);
-
- if (page) {
- book.rendition.display(book.locations._locations[page]);
- }
- });
-
- open_lastread();
-
- window.setTimeout(function() {
- open_lastread();
-
- $(".loading").hide();
- }, 250);
- });
-
- rendition.on("keyup", hotkey_handler);
-
- rendition.on('resized', function() {
- console.log('resized');
-
- $(".loading").show();
- $(".loading_message").html("Opening chapter...");
-
- window.setTimeout(function() {
- open_lastread();
-
- $(".loading").hide();
- }, 250);
- });
-
- rendition.on('rendered', function(chapter) {
- $(".chapter").html($("<span>").addClass("glyphicon glyphicon-th-list"));
-
- resize_side_columns();
-
- try {
- var location = book.rendition.currentLocation();
-
- if (location.start) {
- var cur_href = book.canonical(location.start.href);
- var toc_entry = false;
-
- function iterate_sublist(row, nest) {
- if (nest == 3) return false;
-
- if (row.subitems) {
- $.each(row.subitems, function (i, r) {
-
- if (book.spine.get(r.href).canonical == cur_href) {
- toc_entry = r;
- return true;
- }
-
- if (iterate_sublist(r, nest + 1))
- return true;
- });
- }
-
- return false;
- }
-
- $.each(book.navigation.toc, function(i, a) {
- if (book.spine.get(a.href).canonical == cur_href) {
- toc_entry = a;
- return;
- }
-
- if (iterate_sublist(a, 0)) return;
-
- });
-
- if (toc_entry && toc_entry.label.trim())
- $(".chapter").append("&nbsp;" + toc_entry.label);
- }
-
- } catch (e) {
- console.warn(e);
- }
- });
-
- rendition.on('relocated', function(location) {
-
- // locations not generated yet
- if (book.locations.length() == 0)
- return;
-
- var currentCfi = location.start.cfi;
- var currentPage = parseInt(book.locations.percentageFromCfi(currentCfi) * 100);
- var pct = book.locations.percentageFromCfi(currentCfi);
-
- $("#cur_page").html(location.start.location);
- $("#total_pages").html(book.locations.length());
-
- $("#page_pct").html(parseInt(pct*100) + '%');
-
- if (_store_position && new Date().getTime()/1000 - _last_position_sync > 15) {
- console.log("storing lastread", currentPage, currentCfi);
-
- if (navigator.onLine) {
-
- $.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";
- }
- });
-
- _store_position = 0;
- } else {
- _last_position_sync = 0;
- }
-
- localforage.setItem(cacheId("lastread"),
- {cfi: currentCfi, page: currentPage, total: 100});
-
- }
- });
-
- }
-</script>
-
</body>
</html>