diff --git a/comic/models.py b/comic/models.py
index 6f89ff4..e71dff5 100644
--- a/comic/models.py
+++ b/comic/models.py
@@ -2,7 +2,6 @@ import io
import mimetypes
import uuid
import zipfile
-from dataclasses import dataclass
from functools import reduce
from itertools import zip_longest
from os import listdir
@@ -230,18 +229,12 @@ class ComicBook(models.Model):
def page_count(self):
return ComicPage.objects.filter(Comic=self).count()
- @dataclass
- class Navigation:
- next_path: str
- prev_path: str
- cur_path: str
-
def nav(self, user):
- return self.Navigation(
- next_path=self.nav_get_next_comic(user),
- prev_path=self.nav_get_prev_comic(user),
- cur_path=urlsafe_base64_encode(self.selector.bytes)
- )
+ return {
+ "next_path": self.nav_get_next_comic(user),
+ "prev_path": self.nav_get_prev_comic(user),
+ "cur_path": urlsafe_base64_encode(self.selector.bytes)
+ }
def nav_get_prev_comic(self, user) -> str:
base_dir = settings.COMIC_BOOK_VOLUME
diff --git a/comic/templates/comic/comic_list.html b/comic/templates/comic/comic_list.html
index d750f80..ec0dca9 100644
--- a/comic/templates/comic/comic_list.html
+++ b/comic/templates/comic/comic_list.html
@@ -90,76 +90,5 @@
{% endblock %}
{% block script %}
-
+
{% endblock %}
\ No newline at end of file
diff --git a/comic/templates/comic/read_comic.html b/comic/templates/comic/read_comic.html
index b035d43..402e7b4 100644
--- a/comic/templates/comic/read_comic.html
+++ b/comic/templates/comic/read_comic.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+{% load static %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
@@ -21,65 +22,7 @@
{% endblock %}
{% block script %}
-
+ {{ nav|json_script:"nav" }}
+ {{ status.last_read_page|json_script:"last_read_page" }}
+
{% endblock %}
\ No newline at end of file
diff --git a/comic/templates/comic/read_comic_pdf.html b/comic/templates/comic/read_comic_pdf.html
index e5ad77d..065cd7d 100644
--- a/comic/templates/comic/read_comic_pdf.html
+++ b/comic/templates/comic/read_comic_pdf.html
@@ -24,150 +24,7 @@
{% block script %}
-
+ {{ nav|json_script:"nav" }}
+ {{ status.last_read_page|json_script:"last_read_page" }}
+
{% endblock %}
\ No newline at end of file
diff --git a/comic/templates/comic/recent_comics.html b/comic/templates/comic/recent_comics.html
index b838595..8261dbb 100644
--- a/comic/templates/comic/recent_comics.html
+++ b/comic/templates/comic/recent_comics.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+{% load static %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
@@ -40,83 +41,5 @@
{% endblock %}
{% block script %}
-
+
{% endblock %}
\ No newline at end of file
diff --git a/static/js/comic_list.js b/static/js/comic_list.js
new file mode 100644
index 0000000..80f59ac
--- /dev/null
+++ b/static/js/comic_list.js
@@ -0,0 +1,67 @@
+var qsRegex;
+var buttonFilter;
+ var $grid = $('.comic-container').isotope({
+ itemSelector: '.grid-item',
+ layoutMode: 'fitRows',
+ filter: function() {
+ var $this = $(this);
+ var searchResult = qsRegex ? $this.text().match( qsRegex ) : true;
+ var buttonResult = buttonFilter ? $this.is( buttonFilter ) : true;
+ return searchResult && buttonResult;
+ }
+ });
+ $('#filters').on( 'click', 'button', function() {
+ buttonFilter = $( this ).attr('data-filter');
+ sessionStorage.setItem(window.location.href+"button", buttonFilter);
+ $grid.isotope();
+ });
+
+ var $quicksearch = $('#quicksearch').keyup( debounce( function() {
+ qsRegex = new RegExp($quicksearch.val(), 'gi');
+ sessionStorage.setItem(window.location.href+'text', $quicksearch.val());
+ $grid.isotope();
+ }) );
+
+ // debounce so filtering doesn't happen every millisecond
+ function debounce( fn, threshold ) {
+ var timeout;
+ threshold = threshold || 100;
+ return function debounced() {
+ clearTimeout( timeout );
+ var args = arguments;
+ var _this = this;
+ function delayed() {
+ fn.apply( _this, args );
+ }
+ timeout = setTimeout( delayed, threshold );
+ };
+ }
+setInterval(function (){
+ $grid.isotope();
+}, 1000)
+
+let field = document.getElementById("quicksearch");
+
+// See if we have an autosave value
+// (this will only happen if the page is accidentally refreshed)
+if (sessionStorage.getItem(window.location.href+'text') || sessionStorage.getItem(window.location.href+'button')) {
+ // Restore the contents of the text field
+ field.value = sessionStorage.getItem(window.location.href+'text');
+ qsRegex = new RegExp($quicksearch.val(), 'gi');
+ buttonFilter = sessionStorage.getItem(window.location.href+'button');
+ $grid.isotope();
+}
+
+// Listen for changes in the text field
+field.addEventListener("change", function() {
+ // And save the results into the session storage object
+
+});
+
+function comic_action(selector, item_type, action) {
+ $.ajax({
+ url: '/comic/action/' + action + '/' + item_type + '/' + selector + '/',
+ success: function (){window.location.reload()}
+ })
+
+}
diff --git a/static/js/comic_list.min.js b/static/js/comic_list.min.js
new file mode 100644
index 0000000..77ed1bd
--- /dev/null
+++ b/static/js/comic_list.min.js
@@ -0,0 +1 @@
+var qsRegex;var buttonFilter;var $grid=$(".comic-container").isotope({itemSelector:".grid-item",layoutMode:"fitRows",filter:function(){var $this=$(this);var searchResult=qsRegex?$this.text().match(qsRegex):true;var buttonResult=buttonFilter?$this.is(buttonFilter):true;return searchResult&&buttonResult}});$("#filters").on("click","button",function(){buttonFilter=$(this).attr("data-filter");sessionStorage.setItem(window.location.href+"button",buttonFilter);$grid.isotope()});var $quicksearch=$("#quicksearch").keyup(debounce(function(){qsRegex=new RegExp($quicksearch.val(),"gi");sessionStorage.setItem(window.location.href+"text",$quicksearch.val());$grid.isotope()}));function debounce(fn,threshold){var timeout;threshold=threshold||100;return function debounced(){clearTimeout(timeout);var args=arguments;var _this=this;function delayed(){fn.apply(_this,args)}timeout=setTimeout(delayed,threshold)}}setInterval(function(){$grid.isotope()},1e3);let field=document.getElementById("quicksearch");if(sessionStorage.getItem(window.location.href+"text")||sessionStorage.getItem(window.location.href+"button")){field.value=sessionStorage.getItem(window.location.href+"text");qsRegex=new RegExp($quicksearch.val(),"gi");buttonFilter=sessionStorage.getItem(window.location.href+"button");$grid.isotope()}field.addEventListener("change",function(){});function comic_action(selector,item_type,action){$.ajax({url:"/comic/action/"+action+"/"+item_type+"/"+selector+"/",success:function(){window.location.reload()}})}
\ No newline at end of file
diff --git a/static/js/read_comic.js b/static/js/read_comic.js
new file mode 100644
index 0000000..49f08dc
--- /dev/null
+++ b/static/js/read_comic.js
@@ -0,0 +1,62 @@
+const nav = JSON.parse(document.getElementById('nav').textContent);
+const last_read_page = JSON.parse(document.getElementById('last_read_page').textContent);
+
+Reveal.initialize({
+ controls: false,
+ hash: true,
+ width: "100%",
+ height: "100%",
+ margin: 0,
+ minScale: 1,
+ maxScale: 1,
+ disableLayout: true,
+ progress: true,
+ keyboard: {
+ 37: () => {prevPage()},
+ 39: () => {nextPage()},
+ 38: () => {window.scrollTo({ top: window.scrollY-window.innerHeight*.6, left: 0, behavior: 'smooth' })},
+ 40: () => {window.scrollTo({ top: window.scrollY+window.innerHeight*.6, left: 0, behavior: 'smooth' })},
+ },
+ touch: false,
+ transition: 'slide',
+ plugins: [ RevealMenu ]
+}).then(() => {
+ Reveal.slide(last_read_page)
+
+});
+
+Reveal.on( 'slidechanged', event => {
+ setTimeout(() =>{document.getElementsByClassName('slides')[0].scrollIntoView({behavior: 'smooth'})}, 100)
+ $.ajax({url: "/comic/set_page/" + nav.cur_path + "/" + event.indexh + "/"})
+});
+
+const hammertime = new Hammer(document.getElementById('comic_box'), {});
+hammertime.on('swipeleft', function (ev) {
+ if (Reveal.isLastSlide()){
+ window.location = "/comic/read/"+ nav.next_path +"/"
+ } else {
+ Reveal.next()
+ }
+});
+hammertime.on('swiperight', function (ev) {
+ if (Reveal.isFirstSlide()){
+ window.location = "/comic/read/"+ nav.prev_path +"/"
+ } else {
+ Reveal.prev();
+ }
+});
+
+function prevPage() {
+ if (Reveal.isFirstSlide()){
+ window.location = "/comic/read/"+ nav.prev_path +"/"
+ } else {
+ Reveal.prev();
+ }
+}
+function nextPage() {
+ if (Reveal.isLastSlide()){
+ window.location = "/comic/read/"+ nav.next_path +"/"
+ } else {
+ Reveal.next()
+ }
+}
\ No newline at end of file
diff --git a/static/js/read_comic.min.js b/static/js/read_comic.min.js
new file mode 100644
index 0000000..fa7ca8a
--- /dev/null
+++ b/static/js/read_comic.min.js
@@ -0,0 +1 @@
+const nav=JSON.parse(document.getElementById("nav").textContent);const last_read_page=JSON.parse(document.getElementById("last_read_page").textContent);Reveal.initialize({controls:false,hash:true,width:"100%",height:"100%",margin:0,minScale:1,maxScale:1,disableLayout:true,progress:true,keyboard:{37:()=>{prevPage()},39:()=>{nextPage()},38:()=>{window.scrollTo({top:window.scrollY-window.innerHeight*.6,left:0,behavior:"smooth"})},40:()=>{window.scrollTo({top:window.scrollY+window.innerHeight*.6,left:0,behavior:"smooth"})}},touch:false,transition:"slide",plugins:[RevealMenu]}).then(()=>{Reveal.slide(last_read_page)});Reveal.on("slidechanged",event=>{setTimeout(()=>{document.getElementsByClassName("slides")[0].scrollIntoView({behavior:"smooth"})},100);$.ajax({url:"/comic/set_page/"+nav.cur_path+"/"+event.indexh+"/"})});const hammertime=new Hammer(document.getElementById("comic_box"),{});hammertime.on("swipeleft",function(ev){if(Reveal.isLastSlide()){window.location="/comic/read/"+nav.next_path+"/"}else{Reveal.next()}});hammertime.on("swiperight",function(ev){if(Reveal.isFirstSlide()){window.location="/comic/read/"+nav.prev_path+"/"}else{Reveal.prev()}});function prevPage(){if(Reveal.isFirstSlide()){window.location="/comic/read/"+nav.prev_path+"/"}else{Reveal.prev()}}function nextPage(){if(Reveal.isLastSlide()){window.location="/comic/read/"+nav.next_path+"/"}else{Reveal.next()}}
\ No newline at end of file
diff --git a/static/js/read_comic_pdf.js b/static/js/read_comic_pdf.js
new file mode 100644
index 0000000..a941596
--- /dev/null
+++ b/static/js/read_comic_pdf.js
@@ -0,0 +1,146 @@
+// If absolute URL from the remote server is provided, configure the CORS
+// header on that server.
+const nav = JSON.parse(document.getElementById('nav').textContent);
+const last_read_page = JSON.parse(document.getElementById('last_read_page').textContent);
+var url = "/comic/read/" + nav.cur_path + "/pdf"
+
+// Loaded via