diff options
author | Andrew Dolgov <[email protected]> | 2017-02-26 13:12:33 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2017-02-26 13:12:33 +0300 |
commit | e01f57a3d98943954372110dc75e8d731fbacc10 (patch) | |
tree | 2d57e3a2368984f03507f2650f0b94273dced625 | |
parent | b8ae4b31c129031e89e4c7fb9801d6761513dd73 (diff) |
further offline improvements
-rw-r--r-- | backend.php | 3 | ||||
-rw-r--r-- | index.php | 15 | ||||
-rw-r--r-- | js/index.js | 92 | ||||
-rw-r--r-- | js/offline.js | 63 | ||||
-rw-r--r-- | js/read.js | 10 | ||||
-rw-r--r-- | offline.html | 2 | ||||
-rw-r--r-- | read.html | 192 | ||||
-rw-r--r-- | worker.js | 29 |
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."; } } @@ -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(); + } + }); + } + }); } @@ -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> @@ -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}); + } }); @@ -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); }) ); }); |