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