Skip to content

Commit

Permalink
Improve section listing and editing
Browse files Browse the repository at this point in the history
* Now displaying full summaries in the listing
* Added page for editing a section (closes #30)
* Section ratings!

Closes #20.
  • Loading branch information
dellsystem committed May 29, 2017
1 parent 40a06b2 commit 801beb9
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 32 deletions.
5 changes: 3 additions & 2 deletions books/forms.py
Expand Up @@ -48,12 +48,13 @@ class Meta:
'title': forms.TextInput(attrs={'autofocus': 'autofocus'}),
}

def save(self, book):
def save(self, book=None):
"""Convert the string 'page' input into an integer (and set in_preface
accordingly)."""
section = super(SectionForm, self).save(commit=False)

section.book = book
if book:
section.book = book

page = section.page_number
try:
Expand Down
12 changes: 12 additions & 0 deletions books/models.py
Expand Up @@ -107,12 +107,24 @@ def get_page_display(self):
return self.page_number


class RatingField(models.IntegerField):
def __init__(self, min_value=1, max_value=5, **kwargs):
self.min_value, self.max_value = min_value, max_value
models.IntegerField.__init__(self, **kwargs)

def formfield(self, **kwargs):
defaults = {'min_value': self.min_value, 'max_value':self.max_value}
defaults.update(kwargs)
return super(RatingField, self).formfield(**defaults)


class Section(PageArtefact):
book = models.ForeignKey(Book, related_name='sections')
authors = models.ManyToManyField(Author, related_name='sections', blank=True)
title = models.CharField(max_length=255)
subtitle = models.CharField(max_length=255, blank=True)
summary = models.TextField(blank=True)
rating = RatingField(default=0)

class Meta:
ordering = ['-in_preface', 'page_number']
Expand Down
4 changes: 4 additions & 0 deletions static/jquery.min.js

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions static/scripts.js
Expand Up @@ -31,3 +31,16 @@ function fetchDefinition() {
}
});
}

$('.editable-rating').rating({
maxRating: 5,
interactive: true,
onRate: function(value) {
$('#section_rating').val(value);
}
});

$('.display-rating').rating({
maxRating: 5,
interactive: false,
});
11 changes: 11 additions & 0 deletions static/semantic.min.css

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions static/semantic.min.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions static/styles.css
Expand Up @@ -48,3 +48,7 @@ blockquote footer {
margin-top: 15px !important;
padding-right: 15px !important;
}

.ui.compact.grid>.row {
padding: 0;
}
2 changes: 2 additions & 0 deletions templates/base.html
Expand Up @@ -61,6 +61,8 @@ <h1>
{% endblock %}
<br />
</div>
<script src="/static/jquery.min.js" type="text/javascript"></script>
<script src="/static/semantic.min.js" type="text/javascript"></script>
<script src="/static/scripts.js" type="text/javascript"></script>
</body>
</html>
68 changes: 68 additions & 0 deletions templates/edit_section.html
@@ -0,0 +1,68 @@
{% extends "base.html" %}

{% block breadcrumbs %}
<a class="section" href="{{ book.get_absolute_url }}">View book</a>
<i class="right angle icon divider"></i>
<a class="section" href="{{ section.get_absolute_url }}">View section</a>
<i class="right angle icon divider"></i>
<div class="active section">Edit section</div>
{% endblock %}

{% block content %}
{% include 'book_header.html' with book=book only %}

<div class="ui divider"></div>

<div class="ui segment">
<form class="ui form" method="post">
{% csrf_token %}
<div class="ui fields">
{% with error=section_form.title.errors %}
<div class="five wide {% if error %}error{% endif %} field">
<label>Title{% if error %} (REQUIRED){% endif %}</label>
{{ section_form.title }}
</div>
{% endwith %}
<div class="five wide field">
<label>Subtitle</label>
{{ section_form.subtitle }}
</div>
{% with error=section_form.page_number.errors %}
<div class="one wide {% if error %}error{% endif %} field"
{% if error %}title="{{ error|join:"/" }}"{% endif %}>
<label>Page</label>
{{ section_form.page_number }}
</div>
{% endwith %}
{% with error=author_form.mode.errors %}
<div class="two wide {% if error %}error{% endif %} field"
{% if error %}title="{{ error|join:"/" }}"{% endif %}>
<label>Author mode</label>
{{ author_form.mode }}
</div>
{% endwith %}
<div class="three wide field">
<label>Author</label>
{{ author_form.author }}
</div>
</div>
<div class="field">
<label>Summary</label>
{{ section_form.summary }}
</div>
<div class="ui basic center aligned segment">
<input type="hidden" name="section-rating"
id="section_rating" value="{{ section.rating }}" />
<div class="ui heart rating editable-rating"
data-rating="{{ section.rating }}">
</div>
<br /><br />
<button type="submit" name="submit"
class="ui blue button">
Submit
</button>
</div>
</form>
</div>

{% endblock %}
59 changes: 37 additions & 22 deletions templates/section_list.html
@@ -1,31 +1,46 @@
<div class="ui middle aligned divided list">
{% load markdown_filter %}


<br />
<div class="ui vertically divided compact grid">
{% for section in sections %}
<div class="item">
<div class="left floated content">
<div title="Summary"
class="ui icon {% if not section.summary %}red{% endif %} label">
<i class="browser icon"></i>
</div>
</div>
<div class="right floated content">
<div class="row">
<div class="one wide column">
<div class="ui large circular label">{{ section.get_page_display }}</div>
</div>
<div class="content">
<div class="header">
<a href="{{ section.get_absolute_url }}">{{ section.title }}</a>
<a href="{% url 'admin:books_section_change' section.pk %}">
<i class="edit icon"></i>
<div class="eleven wide column">
<h4 class="ui header">
<a href="{{ section.get_absolute_url }}">
{{ section.title|markdownify_title }}
</a>
</div>
{{ section.subtitle }}
{% if section.authors.count %}
{% if not section.has_default_authors %}
{% include 'author_list.html' with authors=section.authors %}
{% endif %}
{% else %}
(missing author)
<div class="ui heart rating display-rating" data-rating="{{ section.rating }}">
</div>
<div class="sub header">
{{ section.subtitle|markdownify_title }}
{% if section.authors.count %}
{% if not section.has_default_authors %}
{% include 'author_list.html' with authors=section.authors %}
{% endif %}
{% else %}
(missing author)
{% endif %}
</div>
</h4>
{% if section.summary %}
{{ section.summary|markdownify }}
{% endif %}
</div>
<div class="three wide right aligned column">
{{ section.terms.count }} <i class="flag icon"></i>
/
{{ section.notes.count }} <i class="sticky note icon"></i>
</div>
<div class="one wide right aligned column">
<a class="ui mini icon {% if not section.summary %}red{% endif %} button"
href="{% url 'edit_section' section.pk %}">
<i class="edit icon"></i>
</a>
</div>
</div>
{% endfor %}
</div>
12 changes: 6 additions & 6 deletions templates/view_book.html
Expand Up @@ -59,12 +59,12 @@ <h2 class="ui header">
</a>
<br />
<div style="text-align: center">
<div class="ui icon label" title="Terms">
<a class="ui icon label" title="Terms" href="#terms">
<i class="flag icon"></i> {{ book.terms.count }}
</div>
<div class="ui icon label" title="Notes">
</a>
<a class="ui icon label" title="Notes" href="#notes">
<i class="sticky note icon"></i> {{ book.notes.count }}
</div>
</a>
<div class="ui icon label" title="Sections">
<i class="angle right icon"></i> {{ book.sections.count }}
</div>
Expand All @@ -83,7 +83,7 @@ <h2 class="ui header">
{% endif %}
{% if book.completed_sections %}
<div class="ui celled two column grid">
<div class="column">
<div class="column" id="terms">
{% with num_terms=book.terms.count %}
<div class="ui fluid buttons">
{% if num_terms %}
Expand Down Expand Up @@ -121,7 +121,7 @@ <h2 class="ui header">
{% endif %}
{% endwith %}
</div>
<div class="column">
<div class="column" id="notes">
{% with num_notes=book.notes.count %}
<div class="ui fluid buttons">
{% if num_notes %}
Expand Down
2 changes: 1 addition & 1 deletion templates/view_section.html
Expand Up @@ -23,7 +23,7 @@
<div class="ten wide column">
<h3 class="ui header">
{{ section.title }}
<a href="{% url 'admin:books_section_change' section.pk %}">
<a href="{% url 'edit_section' section.pk %}">
<i class="edit icon"></i>
</a>
<div class="sub header">
Expand Down
11 changes: 10 additions & 1 deletion vocabreader/templatetags/markdown_filter.py
Expand Up @@ -8,4 +8,13 @@

@register.filter
def markdownify(text):
return mark_safe(markdown.markdown(text, safe_mode='escape') )
return mark_safe(markdown.markdown(text, safe_mode='escape'))


@register.filter
def markdownify_title(text):
"""Same as markdownify but removes the paragraph tags."""
output = markdown.markdown(text, safe_mode='escape')
if output.startswith('<p>') and output.endswith('</p>'):
output = output[3:-4]
return mark_safe(output)
2 changes: 2 additions & 0 deletions vocabreader/urls.py
Expand Up @@ -40,6 +40,8 @@
name='mark_complete'),
url(r'^section/(?P<section_id>\d+)$', vocabreader.views.view_section,
name='view_section'),
url(r'^section/(?P<section_id>\d+)/edit$', vocabreader.views.edit_section,
name='edit_section'),
url(r'^note/(?P<note_id>\d+)$', vocabreader.views.view_note,
name='view_note'),
url(r'^term/(?P<term_id>\d+)$', vocabreader.views.view_term,
Expand Down
60 changes: 60 additions & 0 deletions vocabreader/views.py
Expand Up @@ -398,6 +398,66 @@ def mark_complete(request, book_id):
return redirect(book)


def edit_section(request, section_id):
section = Section.objects.get(pk=section_id)

initial_author = None
if section.authors.count():
if section.has_default_authors():
author_mode = 'default'
else:
author_mode = 'custom'
initial_author = section.authors.first()
else:
author_mode = 'none'

if request.method == 'POST':
section_form = SectionForm(
request.POST, instance=section, prefix='section'
)
author_form = ArtefactAuthorForm(
request.POST, prefix='author',
)
if section_form.is_valid() and author_form.is_valid():
section = section_form.save()

# Set the authors according to author_form (only if the mode has
# changed).
new_author_mode = author_form.cleaned_data['mode']
if author_mode != new_author_mode:
if new_author_mode == 'default':
section.set_default_authors()
else:
# If it's "none", we only need to remove authors.
section.authors.clear()
if new_author_mode == 'custom':
section.authors.add(author_form.cleaned_data['author'])

messages.success(
request, u'Edited section: {}'.format(section.title)
)
return redirect(section.book)

section_form = SectionForm(instance=section, prefix='section')

author_form = ArtefactAuthorForm(
prefix='author',
initial={
'mode': author_mode,
'author': initial_author,
}
)

context = {
'section': section,
'book': section.book,
'section_form': section_form,
'author_form': author_form,
}

return render(request, 'edit_section.html', context)


def view_section(request, section_id):
section = Section.objects.get(pk=section_id)

Expand Down

0 comments on commit 801beb9

Please sign in to comment.