mirror of
https://github.com/ajurna/cbwebreader.git
synced 2025-12-06 06:17:17 +00:00
change the comic list view to use a datatable.
This commit is contained in:
20
comic/migrations/0013_comicstatus_finished.py
Normal file
20
comic/migrations/0013_comicstatus_finished.py
Normal 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),
|
||||
),
|
||||
]
|
||||
26
comic/migrations/0014_auto_20160404_1402.py
Normal file
26
comic/migrations/0014_auto_20160404_1402.py
Normal 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),
|
||||
]
|
||||
@@ -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
|
||||
|
||||
@@ -31,4 +31,12 @@ body {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
td a {
|
||||
display:block;
|
||||
width:100%;
|
||||
}
|
||||
tr.clickable-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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'),
|
||||
]
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user