summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2017-02-26 13:12:33 +0300
committerAndrew Dolgov <[email protected]>2017-02-26 13:12:33 +0300
commite01f57a3d98943954372110dc75e8d731fbacc10 (patch)
tree2d57e3a2368984f03507f2650f0b94273dced625
parentb8ae4b31c129031e89e4c7fb9801d6761513dd73 (diff)
further offline improvements
-rw-r--r--backend.php3
-rw-r--r--index.php15
-rw-r--r--js/index.js92
-rw-r--r--js/offline.js63
-rw-r--r--js/read.js10
-rw-r--r--offline.html2
-rw-r--r--read.html192
-rw-r--r--worker.js29
8 files changed, 312 insertions, 94 deletions
diff --git a/backend.php b/backend.php
index 5d30f9d..308d2df 100644
--- a/backend.php
+++ b/backend.php
@@ -93,7 +93,8 @@
if ($line = $result->fetchArray()) {
print $line["pagination"];
} else {
- print json_encode(["error" => "NOT_FOUND"]);
+ header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
+ echo "File not found.";
}
}
diff --git a/index.php b/index.php
index ead1231..0c15289 100644
--- a/index.php
+++ b/index.php
@@ -22,6 +22,7 @@
<script src="lib/bootstrap/v3/js/jquery.js"></script>
<script src="lib/bootstrap/v3/js/bootstrap.min.js"></script>
<script src="lib/holder.min.js"></script>
+ <script src="lib/localforage.min.js"></script>
<title>The Epube</title>
<link type="text/css" rel="stylesheet" media="screen" href="css/index.css" />
<link rel="shortcut icon" type="image/png" href="img/favicon.png" />
@@ -29,6 +30,7 @@
<link rel="manifest" href="manifest.json">
<meta name="mobile-web-app-capable" content="yes">
<script src="js/index.js"></script>
+ <script src="js/common.js"></script>
</head>
<body>
@@ -75,12 +77,13 @@
.then(function() {
console.log("service worker registered");
});
-
- $(window).on('offline', function() {
+ /*$(window).on('offline', function() {
window.location.reload();
- });
+ });*/
}
+ mark_offline_books();
+
});
</script>
@@ -133,7 +136,7 @@
$is_read = false;
if ($line["epub_id"]) {
- $read_link = "read.html?" . http_build_query(["id" => $line["epub_id"]]);
+ $read_link = "read.html?" . http_build_query(["id" => $line["epub_id"], "b" => $line["id"]]);
$lastread_result = $ldb->query("SELECT lastread, total_pages FROM epube_books, epube_pagination
WHERE epube_pagination.bookid = epube_books.bookid AND
@@ -219,8 +222,8 @@
?> -->
<?php if ($line["epub_id"]) { ?>
- <li><a href="#" onclick="return offline_cache(this)"
- data-book-id="<?php echo $line["id"] ?>" class="offline" title="">Make available offline</a></li>
+ <li><a href="#" onclick=""
+ data-book-id="<?php echo $line["id"] ?>" class="offline_dropitem"></a></li>
<li class="divider"></li>
<?php } ?>
diff --git a/js/index.js b/js/index.js
index e76be90..95615a2 100644
--- a/js/index.js
+++ b/js/index.js
@@ -1,13 +1,91 @@
-function offline_cache(elem) {
- try {
+function mark_offline_books() {
+ var elems = $(".offline_dropitem");
+
+ $.each(elems, function (i, elem) {
var bookId = elem.getAttribute("data-book-id");
+ var cacheId = "epube-book." + bookId;
+
+ localforage.getItem(cacheId).then(function(book) {
+ if (book) {
+
+ elem.onclick = function() {
+ offline_remove(elem, function() {
+ mark_offline_books();
+ });
+ };
+
+ elem.innerHTML = "Remove offline data";
+
+
+ } else {
+ elem.onclick = function() {
+ offline_cache(bookId, function() {
+ mark_offline_books();
+ });
+ };
+
+ elem.innerHTML = "Make available offline";
+ }
+ });
+ });
+}
+
+function offline_cache(bookId, callback) {
+ console.log("offline cache: " + bookId);
+
+ $.post("backend.php", {op: "getinfo", id: bookId}, function(data) {
+
+ if (data) {
+ var cacheId = 'epube-book.' + bookId;
+
+ localforage.setItem(cacheId, data).then(function(data) {
+
+ console.log(cacheId + ' got data');
+
+ fetch('getbook/' + data.epub_id + ".epub", {credentials: 'same-origin'}).then(function(resp) {
+ if (resp.status == 200) {
+ console.log(cacheId + ' got book');
+
+ callback();
+
+ localforage.setItem(cacheId + '.book', resp.blob());
+ }
+ });
+
+ fetch("backend.php?op=getpagination&id=" + data.epub_id, {credentials: 'same-origin'}).then(function(resp) {
+ if (resp.status == 200) {
+ console.log(cacheId + ' got pagination');
+
+ resp.text().then(function(text) {
+ localforage.setItem(cacheId + '.pagination', JSON.parse(text));
+ });
+ }
+ });
+
+ fetch("backend.php?op=getlastread&id=" + data.epub_id, {credentials: 'same-origin'}).then(function(resp) {
+ if (resp.status == 200) {
+ console.log(cacheId + ' got lastread');
+ resp.text().then(function(text) {
+ localforage.setItem(cacheId + '.lastread', JSON.parse(text));
+ });
+ }
+ });
+
+ if (data.has_cover) {
+
+ fetch("backend.php?op=cover&id=" + bookId, {credentials: 'same-origin'}).then(function(resp) {
+
+ if (resp.status == 200) {
+ console.log(cacheId + ' got cover');
+ localforage.setItem(cacheId + '.cover', resp.blob());
+ }
- console.log(bookId);
+ });
+ }
- return false;
+ });
+ }
- } catch (e) {
- console.warn(e);
- }
+ });
}
diff --git a/js/offline.js b/js/offline.js
index d9bed0b..d1c49d6 100644
--- a/js/offline.js
+++ b/js/offline.js
@@ -1,23 +1,64 @@
-var CACHE_NAME = "epube-test";
-
function populate_list() {
var books = $("#books_container");
+ books.html("");
- window.caches.open(CACHE_NAME).then(function(cache) {
- cache.keys().then(function(items) {
+ localforage.iterate(function(value, key, i) {
+ if (key.match(/epube-book\.\d{1,}$/)) {
- $.each(items, function(i, req) {
+ Promise.all([
+ localforage.getItem(key),
+ localforage.getItem(key + ".cover")
+ ]).then(function(results) {
- if (req.url.match(/\.epub/)) {
- console.log(req.url);
+ var info = results[0];
+ if (info) {
+ var cover = false;
- }
+ if (results && results[1]) {
+ cover = URL.createObjectURL(results[1]);
+ }
- });
+ var cell = "<div class='col-xs-6 col-sm-3 col-md-2 index_cell'>";
- });
- });
+ cell += "<div class=\"thumb\">";
+ cell += "<a href=\"read.html?id="+info.epub_id+"&b="+info.id+"\"><img data-src=\"holder.js/120x180\"></a>";
+
+ cell += "<div class=\"caption\">";
+ cell += "<div><a href=\"read.html?id="+info.epub_id+"&b="+info.id+"\">" + info.title + "</a></div>";
+ cell += "<div>" + info.author_sort + "</div>";
+
+ if (info.series_name) {
+ cell += "<div>" + info.series_name + " [" + info.series_index + "]</div>";
+ }
+
+ cell += "</div>";
+
+ cell += "<div class=\"dropdown\" style=\"white-space : nowrap\">";
+ cell += "<a href=\"#\" data-toggle=\"dropdown\" role=\"button\">" +
+ "More..." + "<span class=\"caret\"></span></a>";
+
+ cell += "<ul class=\"dropdown-menu\">";
+ cell += "<li><a href=\"#\" data-book-id=\""+info.id+"\" onclick=\"offline_remove(this)\">Remove download</a></li>";
+ cell += "</ul>";
+ cell += "</div>";
+
+ cell += "</div>";
+ cell += "</div>";
+
+ var cell = $(cell);
+
+ if (cover) {
+ cell.find("img").attr("src", cover);
+ }
+
+ books.append(cell);
+
+ Holder.run();
+ }
+ });
+ }
+ });
}
diff --git a/js/read.js b/js/read.js
index 9039826..dc968f4 100644
--- a/js/read.js
+++ b/js/read.js
@@ -111,10 +111,14 @@ function mark_as_read() {
function save_and_close() {
if (navigator.onLine) {
- var curPage = book.pagination.pageFromCfi(book.getCurrentLocationCfi());
+ var currentPage = book.pagination.pageFromCfi(book.getCurrentLocationCfi());
+ var currentCfi = book.getCurrentLocationCfi();
- $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: curPage,
- cfi: book.getCurrentLocationCfi() }, function(data) {
+ localforage.setItem("epube-book." + $.urlParam("b") + ".lastread",
+ {cfi: currentCfi, page: currentPage});
+
+ $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: currentPage,
+ cfi: currentCfi }, function(data) {
window.location = "index.php";
});
} else {
diff --git a/offline.html b/offline.html
index 72d678b..c844bd8 100644
--- a/offline.html
+++ b/offline.html
@@ -8,6 +8,7 @@
<script src="lib/bootstrap/v3/js/jquery.js"></script>
<script src="lib/bootstrap/v3/js/bootstrap.min.js"></script>
<script src="lib/holder.min.js"></script>
+ <script src="lib/localforage.min.js"></script>
<title>The Epube</title>
<link type="text/css" rel="stylesheet" media="screen" href="css/index.css" />
<link rel="shortcut icon" type="image/png" href="img/favicon.png" />
@@ -15,6 +16,7 @@
<link rel="manifest" href="manifest.json">
<meta name="mobile-web-app-capable" content="yes">
<script src="js/offline.js"></script>
+ <script src="js/common.js"></script>
</head>
<body>
diff --git a/read.html b/read.html
index 3297331..8db7e60 100644
--- a/read.html
+++ b/read.html
@@ -13,6 +13,7 @@
<script src="lib/epub.js"></script>
<script src="lib/smartimages.js"></script>
<script src="js/read.js"></script>
+ <script src="js/common.js"></script>
<link id="favicon" rel="shortcut icon" type="image/png" href="img/favicon.png" />
<link type="text/css" rel="stylesheet" media="screen" href="css/read.css" />
@@ -149,13 +150,13 @@
<div id="reader"></div>
<div class="loading">
- <div>
+ <div class="loading_message">
Opening book...
</div>
</div>
<script>
- var _pagination_cached = 0;
+ var _pagination_stored = 0;
var _last_position_sync = 0;
$.urlParam = function(name){
@@ -163,8 +164,27 @@
return results[1] || 0;
}
+ function cacheId(suffix) {
+ return "epube-book." + $.urlParam("b") + (suffix ? "." + suffix : "");
+ }
+
$(document).ready(function() {
+ $(window).on('online', function() {
+ console.log("we're online, storing lastread");
+
+ var currentPage = book.pagination.pageFromCfi(book.getCurrentLocationCfi());
+ var currentCfi = book.getCurrentLocationCfi();
+
+ $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: currentPage,
+ cfi: currentCfi }, function(data) {
+
+ if (data.cfi) {
+ _last_position_sync = new Date().getTime()/1000;
+ }
+ });
+ });
+
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('worker.js')
@@ -173,19 +193,90 @@
});
}
- var book_url = "getbook/" + $.urlParam("id") + ".epub";
+ localforage.getItem(cacheId("book")).then(function(item) {
+ if (item) {
+
+ console.log("loading from local storage");
+
+ var fileReader = new FileReader();
+
+ fileReader.onload = function() {
+ book.open(this.result);
+ };
- console.log("init: " + book_url);
+ fileReader.readAsArrayBuffer(item);
+
+ } else {
+
+ console.log("loading from network");
+
+ if (navigator.onLine) {
+ var book_url = "getbook/" + $.urlParam("id") + ".epub";
+
+ RSVP.on('error', function(error) {
+ if ($(".loading").is(":visible")) {
+ $(".loading_message").html("Unable to download book.");
+ }
+ console.log(error);
+ });
+
+ 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 + ".");
+ }
+ });
+
+ } else {
+ $(".loading_message").html("Unable to download books while offline.");
+ }
+ }
+
+ });
init_taps();
document.onkeydown = hotkey_handler;
var book = ePub({
- restore: true,
+ restore: false,
});
- book.open(book_url);
-
var settings = {
fontSize: localStorage['epube:fontSize'] ? localStorage['epube:fontSize'] : '16px',
fontFamily: localStorage['epube:fontFamily'] ? localStorage['epube:fontFamily'] : 'Georgia',
@@ -243,47 +334,56 @@
});
rendered.then(function() {
- console.log("book ready");
-
- var url = "backend.php?op=getpagination&id=" + encodeURIComponent($.urlParam("id"));
-
- EPUBJS.core.request(url).then(function(storedPageList){
-
- pageList = storedPageList;
+
+ localforage.getItem(cacheId("pagination")).then(function(pageList) {
- if (book.loadPagination(pageList).length > 0) {
- _pagination_cached = 1;
+ if (pageList && book.loadPagination(pageList).length > 0) {
+ _pagination_stored = 1;
} else {
- book.generatePagination();
+ var url = "backend.php?op=getpagination&id=" + encodeURIComponent($.urlParam("id"));
+
+ EPUBJS.core.request(url).then(function(pageList) {
+ console.log("pagination: requesting remote");
+
+ if (book.loadPagination(pageList).length > 0) {
+ localforage.setItem(cacheId("pagination"), pageList);
+ _pagination_stored = 1;
+ } else {
+ book.generatePagination();
+ }
+
+ }).catch(function() {
+ book.generatePagination();
+ });
}
- });
+ });
});
book.pageListReady.then(function(pageList) {
- console.log("page list ready");
-
- if (!_pagination_cached) {
- console.log("storing pagination on server");
+ if (!_pagination_stored) {
+ if (navigator.onLine) {
+ $.post("backend.php", { op: "storepagination", id: $.urlParam("id"),
+ payload: JSON.stringify(pageList), total: book.pagination.totalPages });
+ }
- $.post("backend.php", { op: "storepagination", id: $.urlParam("id"),
- payload: JSON.stringify(pageList), total: book.pagination.totalPages });
+ localforage.setItem(cacheId("pagination"), pageList);
}
- var localCfi = localStorage["cfipoint." + $.urlParam("id")];
-
- if (localCfi) {
-
- window.setTimeout(function() {
- book.gotoCfi(localCfi);
- }, 250);
-
- } else {
-
- $.get("backend.php", { op: "getlastread", id: $.urlParam("id") }, function(data) {
- if (data.cfi) book.gotoCfi(data.cfi);
+ if (navigator.onLine) {
+ $.post("backend.php", { op: "getlastread", id: $.urlParam("id") }, function(data) {
+ if (navigator.onLine && data && data.cfi) {
+ book.gotoCfi(data.cfi);
+ } else {
+ localforage.getItem(cacheId("lastread")).then(function(item) {
+ if (item) book.gotoCfi(item.cfi);
+ });
+ }
});
-
+ } else {
+ localforage.getItem(cacheId("lastread")).then(function(item) {
+ if (item) book.gotoCfi(item.cfi);
+ });
}
$("#total_pages").html(book.pagination.totalPages);
@@ -316,20 +416,28 @@
console.log("storing lastread");
var currentCfi = book.getCurrentLocationCfi();
+ var currentPage = location.anchorPage;
if (navigator.onLine) {
- $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: location.anchorPage,
- cfi: currentCfi });
+ $.post("backend.php", { op: "storelastread", id: $.urlParam("id"), page: currentPage,
+ cfi: currentCfi }, function(data) {
+
+ if (data.cfi) {
+ _last_position_sync = new Date().getTime()/1000;
+ }
+
+ });
+
_store_position = 0;
- _last_position_sync = new Date().getTime()/1000;
- localStorage.removeItem("cfipoint." + $.urlParam("id"));
} else {
- localStorage["cfipoint." + $.urlParam("id")] = currentCfi;
_last_position_sync = 0;
}
+ localforage.setItem(cacheId("lastread"),
+ {cfi: currentCfi, page: currentPage});
+
}
});
diff --git a/worker.js b/worker.js
index 2ef4b9c..e2413a4 100644
--- a/worker.js
+++ b/worker.js
@@ -1,10 +1,13 @@
-var CACHE_NAME = 'epube-test';
+//importScripts('lib/localforage.min.js');
+
+var CACHE_NAME = 'epube-v1';
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
var urls = [
'read.html',
+ 'js/common.js',
'js/read.js',
'js/offline.js',
'css/read.css',
@@ -35,8 +38,6 @@ this.addEventListener('fetch', function(event) {
if (resp) return resp;
- console.log(req.url);
-
if (req.url.match("read.html")) {
return caches.match("read.html");
}
@@ -46,27 +47,7 @@ this.addEventListener('fetch', function(event) {
}
}
- return fetch(req)
- .then(function(resp) {
-
- if (req.url.match(/(getlastread|getpagination|\.epub)/)) {
- caches.open(CACHE_NAME).then(function(cache) {
- cache.put(event.request, resp.clone());
- });
- } /*else {
- caches.match(req.url).then(function(cached) {
- if (cached) {
- console.log('refreshing ' + req.url);
-
- caches.open(CACHE_NAME).then(function(cache) {
- cache.put(event.request, resp.clone());
- });
- }
- });
- } */
-
- return resp.clone();
- });
+ return fetch(req);
})
);
});