From: Łukasz Rekucki Date: Fri, 18 Jun 2010 10:41:32 +0000 (+0200) Subject: Merge branch 'master' of github.com:fnp/wolnelektury X-Git-Url: https://git.mdrn.pl/wolnelektury.git/commitdiff_plain/c4b4a64757ba65018dc24334cb44a12ad2a4316a?hp=5a7aa53544f4bc488e4f09facc3ba3af7c36feb9 Merge branch 'master' of github.com:fnp/wolnelektury --- diff --git a/apps/catalogue/models.py b/apps/catalogue/models.py index 367f382c6..90ecb1a3c 100644 --- a/apps/catalogue/models.py +++ b/apps/catalogue/models.py @@ -189,8 +189,12 @@ class Book(models.Model): def save(self, force_insert=False, force_update=False, reset_short_html=True, refresh_mp3=True): if reset_short_html: # Reset _short_html during save + update = {} for key in filter(lambda x: x.startswith('_short_html'), self.__dict__): + update[key] = '' self.__setattr__(key, '') + # Fragment.short_html relies on book's tags, so reset it here too + self.fragments.all().update(**update) book = super(Book, self).save(force_insert, force_update) @@ -323,18 +327,23 @@ class Book(models.Model): book.save() book_tags = [] - for category in ('kind', 'genre', 'author', 'epoch'): - tag_name = getattr(book_info, category) - tag_sort_key = tag_name - if category == 'author': - tag_sort_key = tag_name.last_name - tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name - tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category) - if created: - tag.name = tag_name - tag.sort_key = slughifi(tag_sort_key) - tag.save() - book_tags.append(tag) + categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch')) + for field_name, category in categories: + try: + tag_names = getattr(book_info, field_name) + except: + tag_names = [getattr(book_info, category)] + for tag_name in tag_names: + tag_sort_key = tag_name + if category == 'author': + tag_sort_key = tag_name.last_name + tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name + tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category) + if created: + tag.name = tag_name + tag.sort_key = slughifi(tag_sort_key) + tag.save() + book_tags.append(tag) book.tags = book_tags @@ -460,11 +469,8 @@ class Fragment(models.Model): if short_html and len(short_html): return mark_safe(short_html) else: - book_authors = [mark_safe(u'%s' % (tag.get_absolute_url(), tag.name)) - for tag in self.book.tags if tag.category == 'author'] - setattr(self, key, unicode(render_to_string('catalogue/fragment_short.html', - {'fragment': self, 'book': self.book, 'book_authors': book_authors}))) + {'fragment': self}))) self.save() return mark_safe(getattr(self, key)) diff --git a/apps/catalogue/templatetags/catalogue_tags.py b/apps/catalogue/templatetags/catalogue_tags.py index 7f2bf291d..36a015ae6 100644 --- a/apps/catalogue/templatetags/catalogue_tags.py +++ b/apps/catalogue/templatetags/catalogue_tags.py @@ -61,6 +61,29 @@ def simple_title(tags): return capfirst(', '.join(title)) +@register.simple_tag +def book_title(book, html_links=False): + names = list(book.tags.filter(category='author')) + + books = [] + while book: + books.append(book) + book = book.parent + names.extend(reversed(books)) + + if html_links: + names = ['%s' % (tag.get_absolute_url(), tag.name) for tag in names] + else: + names = [tag.name for tag in names] + + return ', '.join(names) + + +@register.simple_tag +def book_title_html(book): + return book_title(book, html_links=True) + + @register.simple_tag def title_from_tags(tags): def split_tags(tags): diff --git a/apps/catalogue/test_utils.py b/apps/catalogue/test_utils.py index 3a8af57aa..398a0fee2 100644 --- a/apps/catalogue/test_utils.py +++ b/apps/catalogue/test_utils.py @@ -2,6 +2,7 @@ from django.conf import settings from django.test import TestCase import shutil import tempfile +from slughifi import slughifi class WLTestCase(TestCase): """ @@ -36,3 +37,14 @@ class BookInfoStub(object): def to_dict(self): return dict((key, unicode(value)) for key, value in self.__dict.items()) + + +def info_args(title): + """ generate some keywords for comfortable BookInfoCreation """ + slug = unicode(slughifi(title)) + return { + 'title': unicode(title), + 'slug': slug, + 'url': u"http://wolnelektury.pl/example/%s" % slug, + 'about': u"http://wolnelektury.pl/example/URI/%s" % slug, + } diff --git a/apps/catalogue/tests/__init__.py b/apps/catalogue/tests/__init__.py index d656d455b..2366653de 100644 --- a/apps/catalogue/tests/__init__.py +++ b/apps/catalogue/tests/__init__.py @@ -1,3 +1,4 @@ from catalogue.tests.book_import import * -from catalogue.tests.tags import * from catalogue.tests.search import * +from catalogue.tests.tags import * +from catalogue.tests.templatetags import * diff --git a/apps/catalogue/tests/book_import.py b/apps/catalogue/tests/book_import.py index fed99226f..e5fa031d4 100644 --- a/apps/catalogue/tests/book_import.py +++ b/apps/catalogue/tests/book_import.py @@ -82,7 +82,7 @@ class BookImportLogicTests(WLTestCase): BOOK_TEXT = """""" book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info) self.book_info.title = u"Extraordinary" - book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info) + book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info, overwrite=True) tags = [ (tag.category, tag.slug) for tag in book.tags ] tags.sort() @@ -93,7 +93,7 @@ class BookImportLogicTests(WLTestCase): BOOK_TEXT = """""" book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info) self.book_info.author = PersonStub(("Hans", "Christian"), "Andersen") - book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info) + book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info, overwrite=True) tags = [ (tag.category, tag.slug) for tag in book.tags ] tags.sort() @@ -104,6 +104,26 @@ class BookImportLogicTests(WLTestCase): self.assertEqual(tags, self.expected_tags) - # the old tag should disappear - self.assertRaises(models.Tag.DoesNotExist, models.Tag.objects.get, - slug="jim-lazy", category="author") + # the old tag shouldn't disappear + models.Tag.objects.get(slug="jim-lazy", category="author") + + def test_multiple_tags(self): + BOOK_TEXT = """""" + self.book_info.authors = self.book_info.author, PersonStub(("Joe",), "Dilligent"), + self.book_info.kinds = self.book_info.kind, 'Y-Kind', + self.book_info.genres = self.book_info.genre, 'Y-Genre', + self.book_info.epochs = self.book_info.epoch, 'Y-Epoch', + + self.expected_tags.extend([ + ('author', 'joe-dilligent'), + ('genre', 'y-genre'), + ('epoch', 'y-epoch'), + ('kind', 'y-kind'), + ]) + self.expected_tags.sort() + + book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info) + tags = [ (tag.category, tag.slug) for tag in book.tags ] + tags.sort() + + self.assertEqual(tags, self.expected_tags) diff --git a/apps/catalogue/tests/tags.py b/apps/catalogue/tests/tags.py index f9102a7c8..00d11678d 100644 --- a/apps/catalogue/tests/tags.py +++ b/apps/catalogue/tests/tags.py @@ -2,20 +2,9 @@ from catalogue import models from catalogue.test_utils import * from django.core.files.base import ContentFile -from slughifi import slughifi from nose.tools import raises -def info_args(title): - """ generate some keywords for comfortable BookInfoCreation """ - slug = unicode(slughifi(title)) - return { - 'title': unicode(title), - 'slug': slug, - 'url': u"http://wolnelektury.pl/example/%s" % slug, - 'about': u"http://wolnelektury.pl/example/URI/%s" % slug, - } - class BooksByTagTests(WLTestCase): """ tests the /katalog/tag page for found books """ @@ -23,38 +12,20 @@ class BooksByTagTests(WLTestCase): def setUp(self): WLTestCase.setUp(self) author = PersonStub(("Common",), "Man") - tags = dict(genre='G', epoch='E', author=author, kind="K") # grandchild - kwargs = info_args(u"GChild") - kwargs.update(tags) - gchild_info = BookInfoStub(**kwargs) + self.gchild_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Kind', author=author, + **info_args("GChild")) # child - kwargs = info_args(u"Child") - kwargs.update(tags) - child_info = BookInfoStub(parts=[gchild_info.url], **kwargs) - # other grandchild - kwargs = info_args(u"Different GChild") - kwargs.update(tags) - diffgchild_info = BookInfoStub(**kwargs) - # other child - kwargs = info_args(u"Different Child") - kwargs.update(tags) - kwargs['kind'] = 'K2' - diffchild_info = BookInfoStub(parts=[diffgchild_info.url], **kwargs) + self.child_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Other Kind', author=author, + parts=[self.gchild_info.url], + **info_args("Child")) # parent - kwargs = info_args(u"Parent") - kwargs.update(tags) - parent_info = BookInfoStub(parts=[child_info.url, diffchild_info.url], **kwargs) - - # create the books - book_file = ContentFile('') - for info in gchild_info, child_info, diffgchild_info, diffchild_info, parent_info: - book = models.Book.from_text_and_meta(book_file, info) + self.parent_info = BookInfoStub(genre='Genre', epoch='Epoch', kind='Kind', author=author, + parts=[self.child_info.url], + **info_args("Parent")) - # useful tags - self.author = models.Tag.objects.get(name='Common Man', category='author') - models.Tag.objects.create(name='Empty tag', slug='empty', category='author') + self.book_file = ContentFile('') def test_nonexistent_tag(self): """ Looking for a non-existent tag should yield 404 """ @@ -63,30 +34,37 @@ class BooksByTagTests(WLTestCase): def test_book_tag(self): """ Looking for a book tag isn't permitted """ - self.assertEqual(404, self.client.get('/katalog/parent/').status_code) + models.Book.from_text_and_meta(self.book_file, self.gchild_info) + self.assertEqual(404, self.client.get('/katalog/gchild/').status_code) def test_tag_empty(self): """ Tag with no books should return no books """ + models.Book.from_text_and_meta(self.book_file, self.gchild_info) + models.Tag.objects.create(name='Empty tag', slug='empty', category='author') + context = self.client.get('/katalog/empty/').context self.assertEqual(0, len(context['object_list'])) - def test_tag_common(self): - """ Filtering by tag should only yield top-level books. """ - context = self.client.get('/katalog/%s/' % self.author.slug).context + def test_tag_eliminate(self): + """ Filtering by tag should only yield top-level qualifying books. """ + for info in self.gchild_info, self.child_info, self.parent_info: + models.Book.from_text_and_meta(self.book_file, info) + + # all three qualify + context = self.client.get('/katalog/genre/').context self.assertEqual([book.title for book in context['object_list']], ['Parent']) - def test_tag_child(self): - """ Filtering by child's tag should yield the child """ - context = self.client.get('/katalog/k2/').context + # parent and gchild qualify, child doesn't + context = self.client.get('/katalog/kind/').context self.assertEqual([book.title for book in context['object_list']], - ['Different Child']) + ['Parent']) - def test_tag_child_jump(self): - """ Of parent and grandchild, only parent should be returned. """ - context = self.client.get('/katalog/k/').context + # Filtering by child's tag should yield the child + context = self.client.get('/katalog/other-kind/').context self.assertEqual([book.title for book in context['object_list']], - ['Parent']) + ['Child']) + class TagRelatedTagsTests(WLTestCase): @@ -171,17 +149,14 @@ class TagRelatedTagsTests(WLTestCase): 'wrong related tag epoch tag on tag page') - def test_siblings_tags_add(self): + def test_siblings_tags_count(self): """ if children have tags and parent hasn't, count the children """ cats = self.client.get('/katalog/epoch/').context['categories'] self.assertTrue(('ChildKind', 2) in [(tag.name, tag.count) for tag in cats['kind']], 'wrong related kind tags on tag page') - def test_themes_add(self): - """ all occurencies of theme should be counted """ - - cats = self.client.get('/katalog/epoch/').context['categories'] + # all occurencies of theme should be counted self.assertTrue(('Theme', 4) in [(tag.name, tag.count) for tag in cats['theme']], 'wrong related theme count') @@ -244,7 +219,7 @@ class TestIdenticalTag(WLTestCase): cats = self.client.get('/katalog/lektura/tag/').context['categories'] for category in 'author', 'kind', 'genre', 'epoch', 'theme': - self.assertTrue('tag' in [tag.name for tag in cats[category]], + self.assertTrue('tag' in [tag.slug for tag in cats[category]], 'missing related tag for %s' % category) def test_qualified_url(self): diff --git a/apps/catalogue/tests/templatetags.py b/apps/catalogue/tests/templatetags.py new file mode 100644 index 000000000..7a2ac36b9 --- /dev/null +++ b/apps/catalogue/tests/templatetags.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from catalogue import models +from catalogue.templatetags import catalogue_tags +from catalogue.test_utils import * +from django.core.files.base import ContentFile + + +class BookDescTests(WLTestCase): + """ tests book_title template tag """ + + def setUp(self): + WLTestCase.setUp(self) + authors = PersonStub(("Common",), "Man"), PersonStub(("Jane",), "Doe") + + child_info = BookInfoStub(authors=authors, genre="Genre", epoch='Epoch', kind="Kind", + **info_args(u"Child")) + parent_info = BookInfoStub(authors=authors, genre="Genre", epoch='Epoch', kind="Kind", + parts=[child_info.url], + **info_args(u"Parent")) + + self.child = models.Book.from_text_and_meta(ContentFile(''), child_info) + models.Book.from_text_and_meta(ContentFile(''), parent_info) + self.child = models.Book.objects.get(pk=self.child.pk) + + def test_book_desc(self): + """ book description should return authors, ancestors, book """ + self.assertEqual(catalogue_tags.book_title(self.child), 'Jane Doe, Common Man, Parent, Child') diff --git a/wolnelektury/manage.py b/wolnelektury/manage.py index 93b280527..309a56e04 100755 --- a/wolnelektury/manage.py +++ b/wolnelektury/manage.py @@ -2,7 +2,7 @@ import os.path import sys -ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Add apps and lib directories to PYTHONPATH sys.path = [ diff --git a/wolnelektury/static/js/book.js b/wolnelektury/static/js/book.js index 598ef2eb1..9960bfa6a 100644 --- a/wolnelektury/static/js/book.js +++ b/wolnelektury/static/js/book.js @@ -1,10 +1,14 @@ $(function() { function scrollToAnchor(anchor) { if (anchor) { - var element = $('a[name="' + anchor.slice(1) + '"]'); + var anchor_name = anchor.slice(1); + var element = $('a[name="' + anchor_name + '"]'); if (element.length > 0) { $.scrollTo(element, 500, {offset: {top: -50, left: 0}}); - $(element).highlightFade('yellow'); + foot_elem = $('#footnotes a[name="' + anchor_name + '"]'); + if (foot_elem.length > 0) { + $(element).parent().highlightFade('yellow'); + } window.location.hash = anchor; } } diff --git a/wolnelektury/static/js/catalogue.js b/wolnelektury/static/js/catalogue.js index 6e0f562fb..55ecef674 100644 --- a/wolnelektury/static/js/catalogue.js +++ b/wolnelektury/static/js/catalogue.js @@ -312,42 +312,45 @@ function serverTime() { location.href = $('h2 a', this).attr('href'); }); - function toggled_by_slide(cont, short_el, long_el, button, short_text, long_text) { - function toggle(cont, short_el, long_el, button, short_text, long_text) { - if (cont.hasClass('short')) { - cont.animate({"height": long_el.attr("cont_h")+'px'}, {duration: "fast" }).removeClass('short'); - short_el.hide(); - long_el.show(); - button.html(long_text); - } else { - cont.animate({"height": short_el.attr("cont_h")+'px'}, {duration: "fast" }).addClass('short'); - long_el.hide(); - short_el.show(); - button.html(short_text); - } - } + function toggled_by_slide(cont, short_el, long_el, button, short_text, long_text) { + function toggle(cont, short_el, long_el, button, short_text, long_text) { + if (cont.hasClass('short')) { + cont.animate({"height": long_el.attr("cont_h")+'px'}, {duration: "fast" }).removeClass('short'); + short_el.hide(); + long_el.show(); + button.html(long_text); + } else { + cont.animate({"height": short_el.attr("cont_h")+'px'}, {duration: "fast" }).addClass('short'); + long_el.hide(); + short_el.show(); + button.html(short_text); + } + } + if (long_el.html().length <= short_el.html().length) + return; + long_el.attr("cont_h", cont.height()).hide(); short_el.show().attr("cont_h", cont.height()); - cont.addClass('short'); - button.html(short_text); - button.hover( + cont.addClass('short'); + button.html(short_text); + button.hover( function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); }, function() { $(this).css({background: '#EEE'}); } - ).click(function(){ - toggle(cont, short_el, long_el, button, short_text, long_text) - }); - cont.hover( + ).click(function(){ + toggle(cont, short_el, long_el, button, short_text, long_text) + }); + cont.hover( function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); }, function() { $(this).css({background: '#FFF'}); } ).click(function(){ toggle(cont, short_el, long_el, button, short_text, long_text) }) - } + } toggled_by_slide($('#description'), $('#description-short'), $('#description-long'), $('#toggle-description p'), LOCALE_TEXTS[LANGUAGE_CODE]['EXPAND_DESCRIPTION']+' ▼', - LOCALE_TEXTS[LANGUAGE_CODE]['HIDE_DESCRIPTION'] + ' ▲' - ); + LOCALE_TEXTS[LANGUAGE_CODE]['HIDE_DESCRIPTION'] + ' ▲' + ); $('#toggle-share-shelf').hover( function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); }, diff --git a/wolnelektury/templates/catalogue/book_detail.html b/wolnelektury/templates/catalogue/book_detail.html index 809bd1a25..4a8a9313c 100644 --- a/wolnelektury/templates/catalogue/book_detail.html +++ b/wolnelektury/templates/catalogue/book_detail.html @@ -7,7 +7,7 @@ {% block bodyid %}book-detail{% endblock %} {% block body %} -

{{ book.title }}, {{ categories.author|join:", " }}

+

{% book_title book %}

{{ form.q }} {% trans "or" %} {% trans "return to main page" %}

@@ -19,9 +19,10 @@

{% trans "Based on" %}: {{ extra_info.source_name }}

{% if book.has_description %}
- {{ book.description|safe }} +
{{ book.description|safe }}
+
{{ book.description|safe|truncatewords_html:30 }}
-

{% trans "Hide description" %} ▲

+

{% endif %}

{% trans "Put a book" %} {% trans "on the shelf!" %}

@@ -82,27 +83,28 @@

{% trans "Details" %}

  • + {% trans "Author" %}: {% for tag in categories.author %} - {{ tag }} + {{ tag }}{% if not forloop.last %}, {% endif %} {% endfor %}
  • {% trans "Epoch" %}: {% for tag in categories.epoch %} - {{ tag }} + {{ tag }}{% if not forloop.last %}, {% endif %} {% endfor %}
  • {% trans "Kind" %}: {% for tag in categories.kind %} - {{ tag }} + {{ tag }}{% if not forloop.last %}, {% endif %} {% endfor %}
  • {% trans "Genre" %}: {% for tag in categories.genre %} - {{ tag }} + {{ tag }}{% if not forloop.last %}, {% endif %} {% endfor %}
diff --git a/wolnelektury/templates/catalogue/fragment_short.html b/wolnelektury/templates/catalogue/fragment_short.html index ccca721de..4526857bb 100644 --- a/wolnelektury/templates/catalogue/fragment_short.html +++ b/wolnelektury/templates/catalogue/fragment_short.html @@ -1,4 +1,5 @@ {% load i18n %} +{% load catalogue_tags %}
{% if fragment.short_text %}
@@ -13,7 +14,7 @@ {% endif %}