change the comic list view to use a datatable.

This commit is contained in:
ajurna@gmail.com
2016-04-04 16:16:00 +01:00
parent d995c88f47
commit 56e055e9f4
9 changed files with 190 additions and 11 deletions

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-04-04 11:28
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comic', '0012_auto_20160401_0949'),
]
operations = [
migrations.AddField(
model_name='comicstatus',
name='finished',
field=models.BooleanField(default=False),
),
]

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-04-04 13:02
from __future__ import unicode_literals
from django.db import migrations
from django.db.models import Max
def set_finished(apps, schema_editor):
comicstatus = apps.get_model('comic', 'comicstatus')
comicpage = apps.get_model('comic', 'ComicPage')
for row in comicstatus.objects.all():
last_page = comicpage.objects.filter(Comic=row.comic).aggregate(Max('index'))
if row.last_read_page == last_page['index__max']:
row.finished = True
row.save()
class Migration(migrations.Migration):
dependencies = [
('comic', '0013_comicstatus_finished'),
]
operations = [
migrations.RunPython(set_finished, reverse_code=migrations.RunPython.noop),
]

View File

@@ -353,5 +353,12 @@ class ComicStatus(models.Model):
comic = models.ForeignKey(ComicBook, unique=False, null=False)
last_read_page = models.IntegerField(default=0)
unread = models.BooleanField(default=True)
finished = models.BooleanField(default=False)
@property
def read(self):
return self.last_read_page
def __str__(self):
return 'C:{0} P:{1}'.format(self.comic.file_name, self.last_read_page)
# TODO: add support to reference items last being read

View File

@@ -32,3 +32,11 @@ body {
overflow: auto;
box-shadow: none;
}
td a {
display:block;
width:100%;
}
tr.clickable-row {
cursor: pointer;
}

View File

@@ -73,6 +73,7 @@
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/jasny-bootstrap.min.js"></script>
<script src="/static/js/jQuery-2.2.2.min.js"></script>
<script src="/static/js/js.cookie.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/t/bs/dt-1.10.11,b-colvis-1.1.2,r-2.0.2/datatables.min.js"></script>
{% block script %}
{% endblock %}

View File

@@ -3,6 +3,24 @@
{% block content %}
<div class="container">
<table class="table table-bordered table-striped table-hover" id="comic_list">
<caption><h2>Comics</h2></caption>
<thead>
<tr>
<th><center><span class="glyphicon glyphicon-file"></span></center></th>
<th width="100%">File/Folder</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr class="clickable-row" data-href="/comic/">
<td><center><span class="glyphicon glyphicon-file"></span></center></td>
<td>loading data</td>
<td><span class="label label-primary pull-right">1/23</span></td>
</tr>
</tbody>
</table>
<!--/.nav-collapse
<h2 class="center">Comics</h2>
<div class="list-group">
{% if file_list %}
@@ -17,12 +35,42 @@
{% else %}
<p class="list-group-item">No comics.</p>
{% endif %}
</div>
</div>-->
</div>
{% endblock %}
{% block script %}
<script>
$(document).ready(function() {
$('#comic_list').DataTable({
"processing": true,
"ajax": {
"type": "POST",
"url": "{{ json_url }}",
"data": function ( d ) {
d.csrfmiddlewaretoken = Cookies.get('csrftoken');
},
},
"rowCallback": function( row, data, index ) {
var r = $(row)
r.attr('data-href', data['url']);
r.attr('style', 'cursor: pointer;')
r.click(function() {
window.document.location = $(this).data("href");
});
},
"columns": [
{ "data" : "icon", "orderable": false },
{ "data" : "name" },
{ "data" : "label" },
],
"order": [[ 1, 'asc' ]],
});
$(".clickable-row").click(function() {
window.document.location = $(this).data("href");
});
} );
</script>
{% endblock %}

View File

@@ -11,5 +11,7 @@ urlpatterns = [
url(r'^account/$', views.account_page, name='account'),
url(r'^read/(?P<comic_selector>[\w-]+)/(?P<page>[0-9]+)/$', views.read_comic, name='read_comic'),
url(r'^read/(?P<comic_selector>[\w-]+)/(?P<page>[0-9]+)/img$', views.get_image, name='get_image'),
url(r'^list_json/$', views.comic_list_json, name='comic_list_json1'),
url(r'^list_json/(?P<directory_selector>[\w-]+)/$', views.comic_list_json, name='comic_list_json2'),
url(r'^(?P<directory_selector>[\w-]+)/$', views.comic_list, name='comic_list'),
]

View File

@@ -75,6 +75,20 @@ def generate_breadcrumbs_from_menu(paths):
return output
class DirFile:
def __init__(self):
self.name = ''
self.isdir = False
self.icon = ''
self.iscb = False
self.location = ''
self.label = ''
self.cur_page = 0
def __str__(self):
return self.name
def generate_directory(user, directory=False):
"""
@@ -90,7 +104,7 @@ def generate_directory(user, directory=False):
dir_path = ''
ordered_dir_list = get_ordered_dir_list(base_dir)
for file_name in ordered_dir_list:
df = ComicBook.DirFile()
df = DirFile()
df.name = file_name
if path.isdir(path.join(base_dir, dir_path, file_name)):
if directory:
@@ -101,7 +115,8 @@ def generate_directory(user, directory=False):
parent__isnull=True)
df.isdir = True
df.icon = 'glyphicon-folder-open'
df.location = urlsafe_base64_encode(d.selector.bytes)
df.location = '/comic/{0}/'.format(urlsafe_base64_encode(d.selector.bytes).decode())
df.label = generate_dir_status(user, d)
elif file_name.lower()[-4:] in ['.rar', '.zip', '.cbr', '.cbz']:
df.iscb = True
df.icon = 'glyphicon-book'
@@ -114,16 +129,18 @@ def generate_directory(user, directory=False):
directory__isnull=True)
except ComicBook.DoesNotExist:
book = ComicBook.process_comic_book(file_name, directory)
df.location = urlsafe_base64_encode(book.selector.bytes)
status, _ = ComicStatus.objects.get_or_create(comic=book, user=user)
last_page = status.last_read_page
df.location = '/comic/read/{0}/{1}/'.format(urlsafe_base64_encode(book.selector.bytes).decode(),
last_page)
if status.unread:
df.label = '<span class="label label-default pull-right">Unread</span>'
df.label = '<center><span class="label label-default">Unread</span></center>'
elif (last_page + 1) == book.page_count:
df.label = '<span class="label label-success pull-right">Read</span>'
df.label = '<center><span class="label label-success">Read</span></center>'
df.cur_page = last_page
else:
label_text = '<span class="label label-primary pull-right">%s/%s</span>' % \
label_text = '<center><span class="label label-primary">%s/%s</span></center>' % \
(last_page + 1, book.page_count)
df.label = label_text
df.cur_page = last_page
@@ -133,6 +150,21 @@ def generate_directory(user, directory=False):
return files
def generate_dir_status(user, directory):
cb_list = ComicBook.objects.filter(directory=directory)
total = cb_list.count()
total_read = ComicStatus.objects.filter(user=user,
comic__in=cb_list,
finished=True).count()
if total == 0:
return '<center><span class="label label-default">Empty</span></center>'
elif total == total_read:
return '<center><span class="label label-success">All Read</span></center>'
elif total_read == 0:
return '<center><span class="label label-default">Unread</span></center>'
return '<center><span class="label label-primary">{0}/{1}</span></center>'.format(total_read, total)
def get_ordered_dir_list(folder):
directories = []
files = []

View File

@@ -1,5 +1,6 @@
import uuid
from os import path
import json
from django.contrib.auth import login, authenticate
from django.contrib.auth.decorators import login_required, user_passes_test
@@ -7,13 +8,16 @@ from django.contrib.auth.models import User
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.http import urlsafe_base64_decode
from django.views.decorators.csrf import ensure_csrf_cookie
from django.db.models import Max
from .forms import SettingsForm, AccountForm, EditUserForm, AddUserForm, InitialSetupForm
from .models import Setting, ComicBook, ComicStatus, Directory
from .models import Setting, ComicBook, ComicStatus, Directory, ComicPage
from .util import generate_breadcrumbs_from_path, generate_breadcrumbs_from_menu, \
generate_title_from_path, Menu, generate_directory, scan_directory
@ensure_csrf_cookie
@login_required
def comic_list(request, directory_selector=False):
try:
@@ -24,8 +28,8 @@ def comic_list(request, directory_selector=False):
return redirect('/comic/settings/')
if directory_selector:
directory_selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
directory = Directory.objects.get(selector=directory_selector)
selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
directory = Directory.objects.get(selector=selector)
else:
directory = False
@@ -34,19 +38,46 @@ def comic_list(request, directory_selector=False):
if directory:
title = generate_title_from_path(directory.path)
breadcrumbs = generate_breadcrumbs_from_path(directory)
json_url = '/comic/list_json/{0}/'.format(directory_selector)
else:
title = generate_title_from_path('Home')
breadcrumbs = generate_breadcrumbs_from_path()
files = generate_directory(request.user, directory)
json_url = '/comic/list_json/'
files = generate_directory(request.user)
return render(request, 'comic/comic_list.html', {
'file_list': files,
'breadcrumbs': breadcrumbs,
'menu': Menu(request.user, 'Browse'),
'title': title,
'json_url': json_url
})
@login_required
def comic_list_json(request, directory_selector=False):
icon_str = '<span class="glyphicon {0}"></span>'
if directory_selector:
directory_selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
directory = Directory.objects.get(selector=directory_selector)
else:
directory = False
files = generate_directory(request.user, directory)
response_data = dict()
response_data['data'] = []
for file in files:
response_data['data'].append({
'icon': icon_str.format(file.icon),
'name': file.name,
'label': file.label,
'url': file.location,
})
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
@login_required
def account_page(request):
success_message = []
@@ -208,6 +239,10 @@ def read_comic(request, comic_selector, page):
status, _ = ComicStatus.objects.get_or_create(comic=book, user=request.user)
status.unread = False
status.last_read_page = page
if ComicPage.objects.filter(Comic=book).aggregate(Max('index'))['index__max'] == status.last_read_page:
status.finished = True
else:
status.finished = False
status.save()
title = 'CBWebReader - ' + book.file_name + ' - Page: ' + str(page)
context = {