Merge branch 'dev'
authorJan Szejko <jan.szejko@gmail.com>
Wed, 13 Apr 2016 08:17:15 +0000 (10:17 +0200)
committerJan Szejko <jan.szejko@gmail.com>
Wed, 13 Apr 2016 08:50:34 +0000 (10:50 +0200)
Conflicts:
src/api/management/commands/mobileinit.py
src/catalogue/templates/catalogue/inline_tag_list.html
src/catalogue/templates/catalogue/plain_list.html
src/catalogue/views.py
src/wolnelektury/static/scss/main/book_box.scss
src/wolnelektury/static/scss/main/header.scss
src/wolnelektury/templates/main_page.html
src/wolnelektury/templates/superbase.html

12 files changed:
1  2 
src/api/management/commands/mobileinit.py
src/catalogue/helpers.py
src/catalogue/models/book.py
src/catalogue/templates/catalogue/inline_tag_list.html
src/catalogue/templatetags/catalogue_tags.py
src/catalogue/views.py
src/picture/models.py
src/picture/views.py
src/wolnelektury/static/scss/main/book_box.scss
src/wolnelektury/static/scss/main/header.scss
src/wolnelektury/templates/main_page.html
src/wolnelektury/templates/superbase.html

@@@ -97,7 -97,7 +97,7 @@@ CREATE TABLE state (last_checked INTEGE
  """
  
      db.executescript(schema)
-     db.execute("INSERT INTO state VALUES (:last_checked)", locals())
+     db.execute("INSERT INTO state VALUES (:last_checked)", {'last_checked': last_checked})
      return db
  
  
@@@ -133,29 -133,30 +133,30 @@@ categories = {'author': 'autor'
  
  
  def add_book(db, book):
-     title = book.title
      if book.html_file:
          html_file = book.html_file.url
          html_file_size = book.html_file.size
      else:
          html_file = html_file_size = None
-     if book.cover:
-         cover = book.cover.url
-     else:
-         cover = None
-     parent = book.parent_id
-     parent_number = book.parent_number
-     sort_key = book.sort_key
-     size_str = pretty_size(html_file_size)
-     authors = book.author_unicode()
-     db.execute(book_sql, locals())
+     db.execute(book_sql, {
+         'title': book.title,
+         'cover': book.cover.url if book.cover else None,
+         'html_file': html_file,
+         'html_file_size': html_file_size,
+         'parent': book.parent_id,
+         'parent_number': book.parent_number,
+         'sort_key': book.sort_key,
+         'size_str': pretty_size(html_file_size),
 -        'authors': ", ".join(t.name for t in book.tags.filter(category='author')),
++        'authors': book.author_unicode(),
+     })
  
  
  def add_tag(db, tag):
-     category = categories[tag.category]
-     name = tag.name
-     sort_key = tag.sort_key
      books = Book.tagged_top_level([tag])
-     book_ids = ','.join(str(b.id) for b in books)
-     db.execute(tag_sql, locals())
+     book_ids = ','.join(str(book_id) for book_id in books.values_list('id', flat=True))
+     db.execute(tag_sql, {
+         'category': categories[tag.category],
+         'name': tag.name,
+         'sort_key': tag.sort_key,
+         'book_ids': book_ids,
+     })
diff --combined src/catalogue/helpers.py
@@@ -3,6 -3,9 +3,9 @@@
  # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
  #
  from django.conf import settings
+ from django.contrib.contenttypes.models import ContentType
+ from django.core.cache import cache
  from .models import Tag, Book
  from os.path import getmtime
  import cPickle
@@@ -36,7 -39,6 +39,6 @@@ def get_top_level_related_tags(tags, ca
  
      related = Tag.objects.filter(pk__in=related_ids)
  
-     # TODO: do we really need that?
      if categories is not None:
          related = related.filter(category__in=categories)
  
@@@ -57,7 -59,7 +59,7 @@@ def update_counters()
      def count_for_book(book, count_by_combination=None, parent_combinations=None):
          if not parent_combinations:
              parent_combinations = set()
 -        tags = sorted(tuple(t.pk for t in book.tags.filter(category__in=('author', 'genre', 'epoch', 'kind'))))
 +        tags = sorted(book.tags.filter(category__in=('author', 'genre', 'epoch', 'kind')).values_list('pk', flat=True))
          combs = list(combinations(tags))
          for c in combs:
              if c not in parent_combinations:
  
      with open(settings.CATALOGUE_COUNTERS_FILE, 'w') as f:
          cPickle.dump(counters, f)
+ def get_audiobook_tags():
+     audiobook_tag_ids = cache.get('audiobook_tags')
+     if audiobook_tag_ids is None:
+         books_with_audiobook = Book.objects.filter(media__type__in=('mp3', 'ogg'))\
+             .distinct().values_list('pk', flat=True)
+         audiobook_tag_ids = Tag.objects.filter(
+             items__content_type=ContentType.objects.get_for_model(Book),
+             items__object_id__in=list(books_with_audiobook)).distinct().values_list('pk', flat=True)
+         audiobook_tag_ids = list(audiobook_tag_ids)
+         cache.set('audiobook_tags', audiobook_tag_ids)
+     return audiobook_tag_ids
@@@ -4,9 -4,7 +4,9 @@@
  #
  from collections import OrderedDict
  from random import randint
 +import os.path
  import re
 +import urllib
  from django.conf import settings
  from django.db import connection, models, transaction
  from django.db.models import permalink
@@@ -21,10 -19,9 +21,10 @@@ from newtagging import manager
  from catalogue import constants
  from catalogue.fields import EbookField
  from catalogue.models import Tag, Fragment, BookMedia
 -from catalogue.utils import create_zip
 +from catalogue.utils import create_zip, gallery_url, gallery_path
  from catalogue import app_settings
  from catalogue import tasks
 +from wolnelektury.utils import makedirs
  
  bofh_storage = BofhFileSystemStorage()
  
@@@ -92,7 -89,7 +92,7 @@@ class Book(models.Model)
          pass
  
      class Meta:
-         ordering = ('sort_key',)
+         ordering = ('sort_key_author', 'sort_key')
          verbose_name = _('book')
          verbose_name_plural = _('books')
          app_label = 'catalogue'
          except AttributeError:
              return ''
  
 -    def author_str(self):
 -        return ", ".join(str(t) for t in self.tags.filter(category='author'))
 +    def authors(self):
 +        return self.tags.filter(category='author')
 +
 +    def author_unicode(self):
 +        return ", ".join(self.authors().values_list('name', flat=True))
  
      def save(self, force_insert=False, force_update=False, **kwargs):
          from sortify import sortify
          self.title = unicode(self.title)  # ???
  
          try:
 -            author = self.tags.filter(category='author')[0].sort_key
 -        except IndexError:
 +            author = self.authors().first().sort_key
 +        except AttributeError:
              author = u''
          self.sort_key_author = author
  
      def create_url(slug):
          return 'catalogue.views.book_detail', [slug]
  
 +    def gallery_path(self):
 +        return gallery_path(self.slug)
 +
 +    def gallery_url(self):
 +        return gallery_url(self.slug)
 +
      @property
      def name(self):
          return self.title
      def language_name(self):
          return dict(settings.LANGUAGES).get(self.language_code(), "")
  
 +    def is_foreign(self):
 +        return self.language_code() != settings.LANGUAGE_CODE
 +
      def has_media(self, type_):
          if type_ in Book.formats:
              return bool(getattr(self, "%s_file" % type_))
              index.index.rollback()
              raise e
  
 +    def download_pictures(self, remote_gallery_url):
 +        gallery_path = self.gallery_path()
 +        # delete previous files, so we don't include old files in ebooks
 +        if os.path.isdir(gallery_path):
 +            for filename in os.listdir(gallery_path):
 +                file_path = os.path.join(gallery_path, filename)
 +                os.unlink(file_path)
 +        ilustr_elements = list(self.wldocument().edoc.findall('//ilustr'))
 +        if ilustr_elements:
 +            makedirs(gallery_path)
 +            for ilustr in ilustr_elements:
 +                ilustr_src = ilustr.get('src')
 +                ilustr_path = os.path.join(gallery_path, ilustr_src)
 +                urllib.urlretrieve('%s/%s' % (remote_gallery_url, ilustr_src), ilustr_path)
 +
      @classmethod
      def from_xml_file(cls, xml_file, **kwargs):
          from django.core.files import File
  
      @classmethod
      def from_text_and_meta(cls, raw_file, book_info, overwrite=False, dont_build=None, search_index=True,
 -                           search_index_tags=True):
 +                           search_index_tags=True, remote_gallery_url=None):
          if dont_build is None:
              dont_build = set()
          dont_build = set.union(set(dont_build), set(app_settings.DONT_BUILD))
          cls.repopulate_ancestors()
          tasks.update_counters.delay()
  
 +        if remote_gallery_url:
 +            book.download_pictures(remote_gallery_url)
 +
          # No saves beyond this point.
  
          # Build cover.
          return books
  
      def pretty_title(self, html_links=False):
 -        names = [(tag.name, tag.get_absolute_url()) for tag in self.tags.filter(category='author')]
 +        names = [(tag.name, tag.get_absolute_url()) for tag in self.authors().only('name', 'category', 'slug')]
          books = self.parents() + [self]
          names.extend([(b.title, b.get_absolute_url()) for b in books])
  
          """
  
          books_by_parent = {}
 -        books = cls.objects.all().order_by('parent_number', 'sort_key').only(
 -                'title', 'parent', 'slug')
 +        books = cls.objects.order_by('parent_number', 'sort_key').only('title', 'parent', 'slug')
          if book_filter:
              books = books.filter(book_filter).distinct()
  
              books_by_author[tag] = []
  
          for book in books_by_parent.get(None, ()):
 -            authors = list(book.tags.filter(category='author'))
 +            authors = list(book.authors().only('pk'))
              if authors:
                  for author in authors:
                      books_by_author[author].append(book)
          else:
              return None
  
+     def update_popularity(self):
+         count = self.tags.filter(category='set').values('user').order_by('user').distinct().count()
+         try:
+             pop = self.popularity
+             pop.count = count
+             pop.save()
+         except BookPopularity.DoesNotExist:
+             BookPopularity.objects.create(book=self, count=count)
  
  def add_file_fields():
      for format_ in Book.formats:
          ).contribute_to_class(Book, field_name)
  
  add_file_fields()
+ class BookPopularity(models.Model):
+     book = models.OneToOneField(Book, related_name='popularity')
+     count = models.IntegerField(default=0)
@@@ -1,34 -1,29 +1,27 @@@
  {% load i18n %}
  {% load catalogue_tags %}
-       {% if choices %}
-         {% if category_choices %}
-             <ul>
-             {% for tag in category_choices %}
-                 <li class="active">{{ tag }} <a href="{% if gallery %}{% catalogue_url_gallery choices -tag %}{% else %}{% catalogue_url choices -tag %}{% endif %}">X</a></li>
-             {% endfor %}
-             </ul>
-         {% endif %}
-         {% if tags %}
+ {% if choices %}
+     {% if category_choices %}
          <ul>
-         {% for tag in tags %}
-             <li><a href="{% if gallery %}{% catalogue_url_gallery choices tag %}{% else %}{% catalogue_url choices tag %}{% endif %}">{{ tag }}{% if tag.count %}&nbsp;({{ tag.count }}){% endif %}</a></li>
 -        <li class="header">{% trans "Chosen" %}:</li>
+         {% for tag in category_choices %}
+             <li class="active">{{ tag }} <a href="{% catalogue_url list_type choices -tag %}">X</a></li>
          {% endfor %}
          </ul>
-         {% endif %}
    {% else %}
        {% if tags %}
-         <ul>
+     {% endif %}
{% endif %}
+ {% if tags %}
+     <ul>
 -        <li class="header">{% trans "Available" %}:</li>
          {% for tag in tags %}
-             <li><a href="{% if gallery %}{{ tag.get_absolute_gallery_url }}{% else %}{{ tag.get_absolute_url }}{% endif %}">{{ tag }} {% if tag.count %}&nbsp;({{ tag.count }}){% endif %}</a></li>
+             <li><a href="{% catalogue_url list_type choices tag %}">{{ tag }}{% if tag.count %}&nbsp;({{ tag.count }}){% endif %}</a></li>
          {% endfor %}
-         </ul>
-         {% endif %}
-     {% endif %}
-     {% if other %}
-       <ul>
+     </ul>
+ {% endif %}
+ {% if other %}
+     <ul>
          <li class="header">{% trans "Other" %}:</li>
          {% for tag in other %}
-             <li class="other"><a href="{% if gallery %}{{ tag.get_absolute_gallery_url }}{% else %}{{ tag.get_absolute_url }}{% endif %}">{{ tag }}</a></li>
+             <li class="other"><a href="{% catalogue_url list_type tag %}">{{ tag }}</a></li>
          {% endfor %}
      </ul>
    {% endif %}
+ {% endif %}
@@@ -15,6 -15,8 +15,8 @@@ from django.utils.cache import add_neve
  from django.utils.translation import ugettext as _
  
  from ssify import ssi_variable
+ from catalogue.helpers import get_audiobook_tags
  from catalogue.models import Book, BookMedia, Fragment, Tag, Source
  from catalogue.constants import LICENSES
  from picture.models import Picture
@@@ -242,37 -244,23 +244,23 @@@ def catalogue_url(parser, token)
  
      tags_to_add = []
      tags_to_remove = []
-     for bit in bits[1:]:
+     for bit in bits[2:]:
          if bit[0] == '-':
              tags_to_remove.append(bit[1:])
          else:
              tags_to_add.append(bit)
  
-     return CatalogueURLNode(tags_to_add, tags_to_remove)
- @register.tag
- def catalogue_url_gallery(parser, token):
-     bits = token.split_contents()
-     tags_to_add = []
-     tags_to_remove = []
-     for bit in bits[1:]:
-         if bit[0] == '-':
-             tags_to_remove.append(bit[1:])
-         else:
-             tags_to_add.append(bit)
-     return CatalogueURLNode(tags_to_add, tags_to_remove, gallery=True)
+     return CatalogueURLNode(bits[1], tags_to_add, tags_to_remove)
  
  
  class CatalogueURLNode(Node):
-     def __init__(self, tags_to_add, tags_to_remove, gallery=False):
+     def __init__(self, list_type, tags_to_add, tags_to_remove):
          self.tags_to_add = [Variable(tag) for tag in tags_to_add]
          self.tags_to_remove = [Variable(tag) for tag in tags_to_remove]
-         self.gallery = gallery
+         self.list_type_var = Variable(list_type)
  
      def render(self, context):
+         list_type = self.list_type_var.resolve(context)
          tags_to_add = []
          tags_to_remove = []
  
                  pass
  
          if len(tag_slugs) > 0:
-             if self.gallery:
+             if list_type == 'gallery':
                  return reverse('tagged_object_list_gallery', kwargs={'tags': '/'.join(tag_slugs)})
+             elif list_type == 'audiobooks':
+                 return reverse('tagged_object_list_audiobooks', kwargs={'tags': '/'.join(tag_slugs)})
              else:
                  return reverse('tagged_object_list', kwargs={'tags': '/'.join(tag_slugs)})
          else:
-             return reverse('book_list')
+             if list_type == 'gallery':
+                 return reverse('gallery')
+             elif list_type == 'audiobooks':
+                 return reverse('audiobook_list')
+             else:
+                 return reverse('book_list')
  
  
- @register.inclusion_tag('catalogue/tag_list.html')
- def tag_list(tags, choices=None, category=None, gallery=False):
-     print(tags, choices, category)
@register.inclusion_tag('catalogue/tag_list.html')
+ def tag_list(tags, choices=None, category=None, list_type='books'):
+     print(tags, choices, category)
      if choices is None:
          choices = []
  
  
      if len(tags) == 1 and category not in [t.category for t in choices]:
          one_tag = tags[0]
+     else:
+         one_tag = None
  
      if category is not None:
          other = Tag.objects.filter(category=category).exclude(pk__in=[t.pk for t in tags])\
              .exclude(pk__in=[t.pk for t in category_choices])
          # Filter out empty tags.
-         ct = ContentType.objects.get_for_model(Picture if gallery else Book)
+         ct = ContentType.objects.get_for_model(Picture if list_type == 'gallery' else Book)
          other = other.filter(items__content_type=ct).distinct()
+         if list_type == 'audiobooks':
+             other = other.filter(id__in=get_audiobook_tags())
+     else:
+         other = []
  
-     return locals()
+     return {
+         'one_tag': one_tag,
+         'choices': choices,
+         'category_choices': category_choices,
+         'tags': tags,
+         'other': other,
+         'list_type': list_type,
+     }
  
  
  @register.inclusion_tag('catalogue/inline_tag_list.html')
- def inline_tag_list(tags, choices=None, category=None, gallery=False):
-     return tag_list(tags, choices, category, gallery)
+ def inline_tag_list(tags, choices=None, category=None, list_type='books'):
+     return tag_list(tags, choices, category, list_type)
  
  
  @register.inclusion_tag('catalogue/collection_list.html')
  def collection_list(collections):
-     return locals()
+     return {'collections': collections}
  
  
  @register.inclusion_tag('catalogue/book_info.html')
@@@ -351,11 -359,11 +359,11 @@@ def book_info(book)
  @register.inclusion_tag('catalogue/work-list.html', takes_context=True)
  def work_list(context, object_list):
      request = context.get('request')
-     return locals()
+     return {'object_list': object_list, 'request': request}
  
  
  @register.inclusion_tag('catalogue/plain_list.html', takes_context=True)
- def plain_list(context, object_list, with_initials=True, by_author=False, choice=None, book=None, gallery=False,
+ def plain_list(context, object_list, with_initials=True, by_author=False, choice=None, book=None, list_type='books',
                 paged=True, initial_blocks=False):
      names = [('', [])]
      last_initial = None
                  initial = obj.get_initial().upper()
              if initial != last_initial:
                  last_initial = initial
 -                names.append((obj.author_str() if by_author else initial, []))
 +                names.append((obj.author_unicode() if by_author else initial, []))
          names[-1][1].append(obj)
-     return locals()
+     return {
+         'paged': paged,
+         'names': names,
+         'initial_blocks': initial_blocks,
+         'book': book,
+         'list_type': list_type,
+         'choice': choice,
+     }
  
  
  # TODO: These are no longer just books.
diff --combined src/catalogue/views.py
@@@ -19,69 -19,55 +19,55 @@@ from django.utils import translatio
  from django.utils.translation import ugettext as _, ugettext_lazy
  
  from ajaxable.utils import AjaxableFormView
- from pdcounter import models as pdcounter_models
+ from pdcounter.models import BookStub, Author
  from pdcounter import views as pdcounter_views
  from picture.models import Picture, PictureArea
- from ssify import ssi_included, ssi_expect, SsiVariable as V
+ from ssify import ssi_included, ssi_expect, SsiVariable as Var
  from suggest.forms import PublishingSuggestForm
  from catalogue import constants
  from catalogue import forms
  from catalogue.helpers import get_top_level_related_tags
- from catalogue import models
+ from catalogue.models import Book, Collection, Tag, Fragment
  from catalogue.utils import split_tags
  
  staff_required = user_passes_test(lambda user: user.is_staff)
  
  
- def catalogue(request, as_json=False):
-     books = models.Book.objects.filter(parent=None).order_by('sort_key_author', 'sort_key')
-     pictures = Picture.objects.order_by('sort_key_author', 'sort_key')
-     collections = models.Collection.objects.all()
-     return render(request, 'catalogue/catalogue.html', locals())
+ def catalogue(request):
+     return render(request, 'catalogue/catalogue.html', {
+         'books': Book.objects.filter(parent=None),
+         'pictures': Picture.objects.all(),
+         'collections': Collection.objects.all(),
+         'active_menu_item': 'all_works',
+     })
  
  
- def book_list(request, filter=None, get_filter=None, template_name='catalogue/book_list.html',
+ def book_list(request, filters=None, template_name='catalogue/book_list.html',
                nav_template_name='catalogue/snippets/book_list_nav.html',
-               list_template_name='catalogue/snippets/book_list.html', context=None):
-     """ generates a listing of all books, optionally filtered with a test function """
-     if get_filter:
-         filter = get_filter()
-     books_by_author, orphans, books_by_parent = models.Book.book_list(filter)
+               list_template_name='catalogue/snippets/book_list.html'):
+     """ generates a listing of all books, optionally filtered """
+     books_by_author, orphans, books_by_parent = Book.book_list(filters)
      books_nav = OrderedDict()
      for tag in books_by_author:
          if books_by_author[tag]:
              books_nav.setdefault(tag.sort_key[0], []).append(tag)
-     rendered_nav = render_to_string(nav_template_name, locals())
-     rendered_book_list = render_to_string(list_template_name, locals())
-     return render_to_response(template_name, locals(), context_instance=RequestContext(request))
- def audiobook_list(request):
-     books = models.Book.objects.filter(media__type__in=('mp3', 'ogg')).distinct().order_by(
-         'sort_key_author', 'sort_key')
-     books = list(books)
-     if len(books) > 3:
-         best = random.sample(books, 3)
-     else:
-         best = books
-     daisy = models.Book.objects.filter(media__type='daisy').distinct().order_by('sort_key_author', 'sort_key')
-     return render(request, 'catalogue/audiobook_list.html', {
-         'books': books,
-         'best': best,
-         'daisy': daisy,
+     # WTF: dlaczego nie include?
+     return render_to_response(template_name, {
+         'rendered_nav': render_to_string(nav_template_name, {'books_nav': books_nav}),
+         'rendered_book_list': render_to_string(list_template_name, {
+             'books_by_author': books_by_author,
+             'orphans': orphans,
+             'books_by_parent': books_by_parent,
          })
+     }, context_instance=RequestContext(request))
  
  
  def daisy_list(request):
-     return book_list(request, Q(media__type='daisy'),
-                      template_name='catalogue/daisy_list.html',
-                      )
+     return book_list(request, Q(media__type='daisy'), template_name='catalogue/daisy_list.html')
  
  
  def collection(request, slug):
-     coll = get_object_or_404(models.Collection, slug=slug)
+     coll = get_object_or_404(Collection, slug=slug)
      return render(request, 'catalogue/collection.html', {'collection': coll})
  
  
@@@ -89,7 -75,7 +75,7 @@@ def differentiate_tags(request, tags, a
      beginning = '/'.join(tag.url_chunk for tag in tags)
      unparsed = '/'.join(ambiguous_slugs[1:])
      options = []
-     for tag in models.Tag.objects.filter(slug=ambiguous_slugs[0]):
+     for tag in Tag.objects.filter(slug=ambiguous_slugs[0]):
          options.append({
              'url_args': '/'.join((beginning, tag.url_chunk, unparsed)).strip('/'),
              'tags': [tag]
          context_instance=RequestContext(request))
  
  
- # TODO: Rewrite this hellish piece of code which tries to do everything
- def tagged_object_list(request, tags='', gallery=False):
-     raw_tags = tags
-     # preliminary tests and conditions
+ def object_list(request, objects, fragments=None, related_tags=None, tags=None, list_type='books', extra=None):
+     if not tags:
+         tags = []
+     tag_ids = [tag.pk for tag in tags]
+     related_tag_lists = []
+     if related_tags:
+         related_tag_lists.append(related_tags)
+     else:
+         related_tag_lists.append(
+             Tag.objects.usage_for_queryset(objects, counts=True).exclude(category='set').exclude(pk__in=tag_ids))
+     if not (extra and extra.get('theme_is_set')):
+         if fragments is None:
+             if list_type == 'gallery':
+                 fragments = PictureArea.objects.filter(picture__in=objects)
+             else:
+                 fragments = Fragment.objects.filter(book__in=objects)
+         related_tag_lists.append(
+             Tag.objects.usage_for_queryset(fragments, counts=True).filter(category='theme').exclude(pk__in=tag_ids))
+     categories = split_tags(*related_tag_lists)
+     objects = list(objects)
+     if len(objects) > 3:
+         best = random.sample(objects, 3)
+     else:
+         best = objects
+     result = {
+         'object_list': objects,
+         'categories': categories,
+         'list_type': list_type,
+         'tags': tags,
+         'formats_form': forms.DownloadFormatsForm(),
+         'best': best,
+         'active_menu_item': list_type,
+     }
+     if extra:
+         result.update(extra)
+     return render_to_response(
+         'catalogue/tagged_object_list.html', result,
+         context_instance=RequestContext(request))
+ def literature(request):
+     books = Book.objects.filter(parent=None)
+     # last_published = Book.objects.exclude(cover_thumb='').filter(parent=None).order_by('-created_at')[:20]
+     # most_popular = Book.objects.exclude(cover_thumb='')\
+     #                    .order_by('-popularity__count', 'sort_key_author', 'sort_key')[:20]
+     return object_list(request, books, related_tags=get_top_level_related_tags([]))
+     # extra={
+     #     'last_published': last_published,
+     #     'most_popular': most_popular,
+     # })
+ def gallery(request):
+     return object_list(request, Picture.objects.all(), list_type='gallery')
+ def audiobooks(request):
+     audiobooks = Book.objects.filter(media__type__in=('mp3', 'ogg')).distinct()
+     return object_list(request, audiobooks, list_type='audiobooks', extra={
+         'daisy': Book.objects.filter(media__type='daisy').distinct(),
+     })
+ class ResponseInstead(Exception):
+     def __init__(self, response):
+         super(ResponseInstead, self).__init__()
+         self.response = response
+ def analyse_tags(request, tag_str):
      try:
-         tags = models.Tag.get_tag_list(tags)
-     except models.Tag.DoesNotExist:
+         tags = Tag.get_tag_list(tag_str)
+     except Tag.DoesNotExist:
          # Perhaps the user is asking about an author in Public Domain
          # counter (they are not represented in tags)
-         chunks = tags.split('/')
+         chunks = tag_str.split('/')
          if len(chunks) == 2 and chunks[0] == 'autor':
-             return pdcounter_views.author_detail(request, chunks[1])
+             raise ResponseInstead(pdcounter_views.author_detail(request, chunks[1]))
          else:
              raise Http404
-     except models.Tag.MultipleObjectsReturned, e:
+     except Tag.MultipleObjectsReturned, e:
          # Ask the user to disambiguate
-         return differentiate_tags(request, e.tags, e.ambiguous_slugs)
-     except models.Tag.UrlDeprecationWarning, e:
-         return HttpResponsePermanentRedirect(
-             reverse('tagged_object_list', args=['/'.join(tag.url_chunk for tag in e.tags)]))
+         raise ResponseInstead(differentiate_tags(request, e.tags, e.ambiguous_slugs))
+     except Tag.UrlDeprecationWarning, e:
+         raise ResponseInstead(HttpResponsePermanentRedirect(
+             reverse('tagged_object_list', args=['/'.join(tag.url_chunk for tag in e.tags)])))
  
      try:
          if len(tags) > settings.MAX_TAG_LIST:
      except AttributeError:
          pass
  
-     # beginning of digestion
-     theme_is_set = [tag for tag in tags if tag.category == 'theme']
-     shelf_is_set = [tag for tag in tags if tag.category == 'set']
-     only_shelf = shelf_is_set and len(tags) == 1
-     only_my_shelf = only_shelf and request.user.is_authenticated() and request.user == tags[0].user
-     tags_pks = [tag.pk for tag in tags]
-     objects = None
-     if theme_is_set:
-         # Only fragments (or pirctureareas) here.
-         shelf_tags = [tag for tag in tags if tag.category == 'set']
-         fragment_tags = [tag for tag in tags if tag.category != 'set']
-         if gallery:
-             fragments = PictureArea.tagged.with_all(fragment_tags)
-         else:
-             fragments = models.Fragment.tagged.with_all(fragment_tags)
-         if shelf_tags:
-             if gallery:
-                 # TODO: Pictures on shelves not supported yet.
-                 raise Http404
-             else:
-                 books = models.Book.tagged.with_all(shelf_tags).order_by()
-                 fragments = fragments.filter(Q(book__in=books) | Q(book__ancestor__in=books))
+     return tags
  
-         categories = split_tags(
-             models.Tag.objects.usage_for_queryset(fragments, counts=True).exclude(pk__in=tags_pks),
-         )
  
-         objects = fragments
+ def theme_list(request, tags, list_type):
+     shelf_tags = [tag for tag in tags if tag.category == 'set']
+     fragment_tags = [tag for tag in tags if tag.category != 'set']
+     if list_type == 'gallery':
+         fragments = PictureArea.tagged.with_all(fragment_tags)
      else:
-         if gallery:
-             if shelf_is_set:
-                 # TODO: Pictures on shelves not supported yet.
-                 raise Http404
-             else:
-                 if tags:
-                     objects = Picture.tagged.with_all(tags)
-                 else:
-                     objects = Picture.objects.all()
-             areas = PictureArea.objects.filter(picture__in=objects)
-             categories = split_tags(
-                 models.Tag.objects.usage_for_queryset(
-                     objects, counts=True).exclude(pk__in=tags_pks),
-                 models.Tag.objects.usage_for_queryset(
-                     areas, counts=True).filter(
-                     category__in=('theme', 'thing')).exclude(
-                     pk__in=tags_pks),
-             )
-         else:
-             if tags:
-                 all_books = models.Book.tagged.with_all(tags)
-             else:
-                 all_books = models.Book.objects.filter(parent=None)
-             if shelf_is_set:
-                 objects = all_books
-                 related_book_tags = models.Tag.objects.usage_for_queryset(
-                     objects, counts=True).exclude(
-                     category='set').exclude(pk__in=tags_pks)
-             else:
-                 if tags:
-                     objects = models.Book.tagged_top_level(tags)
-                 else:
-                     objects = all_books
-                 # WTF: was outside if, overwriting value assigned if shelf_is_set
-                 related_book_tags = get_top_level_related_tags(tags)
-             fragments = models.Fragment.objects.filter(book__in=all_books)
-             categories = split_tags(
-                 related_book_tags,
-                 models.Tag.objects.usage_for_queryset(
-                     fragments, counts=True).filter(
-                     category='theme').exclude(pk__in=tags_pks),
-             )
-         objects = objects.order_by('sort_key_author', 'sort_key')
+         fragments = Fragment.tagged.with_all(fragment_tags)
  
-     objects = list(objects)
-     if len(objects) > 3:
-         best = random.sample(objects, 3)
-     else:
-         best = objects
+     if shelf_tags:
+         # TODO: Pictures on shelves not supported yet.
+         books = Book.tagged.with_all(shelf_tags).order_by()
+         fragments = fragments.filter(Q(book__in=books) | Q(book__ancestor__in=books))
  
-     if not gallery and not objects and len(tags) == 1:
+     if not fragments and len(tags) == 1 and list_type == 'books':
          tag = tags[0]
-         if (tag.category in ('theme', 'thing') and PictureArea.tagged.with_any([tag]).exists() or
+         if tag.category == 'theme' and (
+                 PictureArea.tagged.with_any([tag]).exists() or
                  Picture.tagged.with_any([tag]).exists()):
-             return redirect('tagged_object_list_gallery', raw_tags, permanent=False)
+             return redirect('tagged_object_list_gallery', '/'.join(tag.url_chunk for tag in tags))
  
-     return render_to_response(
-         'catalogue/tagged_object_list.html',
-         {
-             'object_list': objects,
-             'categories': categories,
-             'only_shelf': only_shelf,
-             'only_my_shelf': only_my_shelf,
-             'formats_form': forms.DownloadFormatsForm(),
-             'tags': tags,
-             'tag_ids': tags_pks,
-             'theme_is_set': theme_is_set,
-             'best': best,
-             'gallery': gallery,
-         },
-         context_instance=RequestContext(request))
+     return object_list(request, fragments, tags=tags, list_type=list_type, extra={
+         'theme_is_set': True,
+         'active_menu_item': 'theme',
+     })
+ def tagged_object_list(request, tags, list_type):
+     try:
+         tags = analyse_tags(request, tags)
+     except ResponseInstead as e:
+         return e.response
+     if list_type == 'gallery' and any(tag.category == 'set' for tag in tags):
+         raise Http404
+     if any(tag.category in ('theme', 'thing') for tag in tags):
+         return theme_list(request, tags, list_type=list_type)
+     if list_type == 'books':
+         books = Book.tagged.with_all(tags)
+         if any(tag.category == 'set' for tag in tags):
+             params = {'objects': books}
+         else:
+             params = {
+                 'objects': Book.tagged_top_level(tags),
+                 'fragments': Fragment.objects.filter(book__in=books),
+                 'related_tags': get_top_level_related_tags(tags),
+             }
+     elif list_type == 'gallery':
+         params = {'objects': Picture.tagged.with_all(tags)}
+     elif list_type == 'audiobooks':
+         audiobooks = Book.objects.filter(media__type__in=('mp3', 'ogg')).distinct()
+         params = {
+             'objects': Book.tagged.with_all(tags, audiobooks),
+             'extra': {
+                 'daisy': Book.tagged.with_all(tags, audiobooks.filter(media__type='daisy').distinct()),
+             }
+         }
+     else:
+         raise Http404
+     return object_list(request, tags=tags, list_type=list_type, **params)
  
  
  def book_fragments(request, slug, theme_slug):
-     book = get_object_or_404(models.Book, slug=slug)
-     theme = get_object_or_404(models.Tag, slug=theme_slug, category='theme')
-     fragments = models.Fragment.tagged.with_all([theme]).filter(
+     book = get_object_or_404(Book, slug=slug)
+     theme = get_object_or_404(Tag, slug=theme_slug, category='theme')
+     fragments = Fragment.tagged.with_all([theme]).filter(
          Q(book=book) | Q(book__ancestor=book))
  
-     return render_to_response('catalogue/book_fragments.html', locals(), context_instance=RequestContext(request))
+     return render_to_response('catalogue/book_fragments.html', {
+         'book': book,
+         'theme': theme,
+         'fragments': fragments,
+         'active_menu_item': 'books',
+     }, context_instance=RequestContext(request))
  
  
  def book_detail(request, slug):
      try:
-         book = models.Book.objects.get(slug=slug)
-     except models.Book.DoesNotExist:
+         book = Book.objects.get(slug=slug)
+     except Book.DoesNotExist:
          return pdcounter_views.book_stub_detail(request, slug)
  
-     tags = book.tags.exclude(category__in=('set', 'theme'))
-     book_children = book.children.all().order_by('parent_number', 'sort_key')
-     return render_to_response('catalogue/book_detail.html', locals(), context_instance=RequestContext(request))
+     return render_to_response('catalogue/book_detail.html', {
+         'book': book,
+         'tags': book.tags.exclude(category__in=('set', 'theme')),
+         'book_children': book.children.all().order_by('parent_number', 'sort_key'),
+         'active_menu_item': 'books',
+     }, context_instance=RequestContext(request))
  
  
  def get_audiobooks(book):
      return audiobooks, projects, have_oggs
  
  
+ # używane w publicznym interfejsie
  def player(request, slug):
-     book = get_object_or_404(models.Book, slug=slug)
+     book = get_object_or_404(Book, slug=slug)
      if not book.has_media('mp3'):
          raise Http404
  
      audiobooks, projects, have_oggs = get_audiobooks(book)
  
-     extra_info = book.extra_info
-     return render_to_response('catalogue/player.html', locals(), context_instance=RequestContext(request))
+     return render_to_response('catalogue/player.html', {
+         'book': book,
+         'audiobook': '',
+         'audiobooks': audiobooks,
+         'projects': projects,
+     }, context_instance=RequestContext(request))
  
  
  def book_text(request, slug):
-     book = get_object_or_404(models.Book, slug=slug)
+     book = get_object_or_404(Book, slug=slug)
  
      if not book.has_html_file():
          raise Http404
-     return render_to_response('catalogue/book_text.html', locals(), context_instance=RequestContext(request))
+     return render_to_response('catalogue/book_text.html', {'book': book}, context_instance=RequestContext(request))
  
  
  # ==========
@@@ -321,7 -352,7 +352,7 @@@ def _no_diacritics_regexp(query)
  
      def repl(m):
          l = m.group()
 -        return u"(%s)" % '|'.join(names[l])
 +        return u"(?:%s)" % '|'.join(names[l])
  
      return re.sub(u'[%s]' % (u''.join(names.keys())), repl, query)
  
@@@ -389,11 -420,11 +420,11 @@@ _apps = 
  def _tags_starting_with(prefix, user=None):
      prefix = prefix.lower()
      # PD counter
-     book_stubs = pdcounter_models.BookStub.objects.filter(_word_starts_with('title', prefix))
-     authors = pdcounter_models.Author.objects.filter(_word_starts_with('name', prefix))
+     book_stubs = BookStub.objects.filter(_word_starts_with('title', prefix))
+     authors = Author.objects.filter(_word_starts_with('name', prefix))
  
-     books = models.Book.objects.filter(_word_starts_with('title', prefix))
-     tags = models.Tag.objects.filter(_word_starts_with('name', prefix))
+     books = Book.objects.filter(_word_starts_with('title', prefix))
+     tags = Tag.objects.filter(_word_starts_with('name', prefix))
      if user and user.is_authenticated():
          tags = tags.filter(~Q(category='set') | Q(user=user))
      else:
  
  
  def _get_result_link(match, tag_list):
-     if isinstance(match, models.Tag):
+     if isinstance(match, Tag):
          return reverse('catalogue.views.tagged_object_list',
                         kwargs={'tags': '/'.join(tag.url_chunk for tag in tag_list + [match])})
      elif isinstance(match, App):
  
  
  def _get_result_type(match):
-     if isinstance(match, models.Book) or isinstance(match, pdcounter_models.BookStub):
+     if isinstance(match, Book) or isinstance(match, BookStub):
          match_type = 'book'
      else:
          match_type = match.category
  
  def books_starting_with(prefix):
      prefix = prefix.lower()
-     return models.Book.objects.filter(_word_starts_with('title', prefix))
+     return Book.objects.filter(_word_starts_with('title', prefix))
  
  
  def find_best_matches(query, user=None):
-     """ Finds a models.Book, Tag, models.BookStub or Author best matching a query.
+     """ Finds a Book, Tag, BookStub or Author best matching a query.
  
      Returns a with:
        - zero elements when nothing is found,
      result = tuple(_tags_starting_with(query, user))
      # remove pdcounter stuff
      book_titles = set(match.pretty_title().lower() for match in result
-                       if isinstance(match, models.Book))
+                       if isinstance(match, Book))
      authors = set(match.name.lower() for match in result
-                   if isinstance(match, models.Tag) and match.category == 'author')
+                   if isinstance(match, Tag) and match.category == 'author')
      result = tuple(res for res in result if not (
-                  (isinstance(res, pdcounter_models.BookStub) and res.pretty_title().lower() in book_titles) or
-                  (isinstance(res, pdcounter_models.Author) and res.name.lower() in authors)
+                  (isinstance(res, BookStub) and res.pretty_title().lower() in book_titles) or
+                  (isinstance(res, Author) and res.name.lower() in authors)
               ))
  
      exact_matches = tuple(res for res in result if res.name.lower() == query)
@@@ -465,8 -496,8 +496,8 @@@ def search(request)
      prefix = request.GET.get('q', '')
  
      try:
-         tag_list = models.Tag.get_tag_list(tags)
-     except (models.Tag.DoesNotExist, models.Tag.MultipleObjectsReturned, models.Tag.UrlDeprecationWarning):
+         tag_list = Tag.get_tag_list(tags)
+     except (Tag.DoesNotExist, Tag.MultipleObjectsReturned, Tag.UrlDeprecationWarning):
          tag_list = []
  
      try:
@@@ -558,22 -589,22 +589,22 @@@ def import_book(request)
  # info views for API
  
  def book_info(request, book_id, lang='pl'):
-     book = get_object_or_404(models.Book, id=book_id)
+     book = get_object_or_404(Book, id=book_id)
      # set language by hand
      translation.activate(lang)
-     return render_to_response('catalogue/book_info.html', locals(), context_instance=RequestContext(request))
+     return render_to_response('catalogue/book_info.html', {'book': book}, context_instance=RequestContext(request))
  
  
  def tag_info(request, tag_id):
-     tag = get_object_or_404(models.Tag, id=tag_id)
+     tag = get_object_or_404(Tag, id=tag_id)
      return HttpResponse(tag.description)
  
  
  def download_zip(request, format, slug=None):
-     if format in models.Book.ebook_formats:
-         url = models.Book.zip_format(format)
+     if format in Book.ebook_formats:
+         url = Book.zip_format(format)
      elif format in ('mp3', 'ogg') and slug is not None:
-         book = get_object_or_404(models.Book, slug=slug)
+         book = get_object_or_404(Book, slug=slug)
          url = book.zip_audiobooks(format)
      else:
          raise Http404('No format specified for zip package')
@@@ -596,7 -627,7 +627,7 @@@ class CustomPDFFormView(AjaxableFormVie
          return (obj,), {}
  
      def get_object(self, request, slug, *args, **kwargs):
-         return get_object_or_404(models.Book, slug=slug)
+         return get_object_or_404(Book, slug=slug)
  
      def context_description(self, request, obj):
          return obj.pretty_title()
  
  @ssi_included
  def book_mini(request, pk, with_link=True):
-     # book = get_object_or_404(models.Book, pk=pk)
 -    book = get_object_or_404(Book, pk=pk)
 -    author_str = ", ".join(tag.name for tag in book.tags.filter(category='author'))
++    # book = get_object_or_404(Book, pk=pk)
 +    try:
-         book = models.Book.objects.only('cover_thumb', 'title', 'language', 'slug').get(pk=pk)
-     except models.Book.DoesNotExist:
++        book = Book.objects.only('cover_thumb', 'title', 'language', 'slug').get(pk=pk)
++    except Book.DoesNotExist:
 +        raise Http404
      return render(request, 'catalogue/book_mini_box.html', {
          'book': book,
 -        'author_str': author_str,
 -        'with_link': with_link,
 -        'show_lang': book.language_code() != settings.LANGUAGE_CODE,
 +        'no_link': not with_link,
      })
  
  
          ('social_tags.book_shelf_tags', (ipk,)),
      ))(ssi_expect(pk, int)))
  def book_short(request, pk):
-     book = get_object_or_404(models.Book, pk=pk)
+     book = get_object_or_404(Book, pk=pk)
      stage_note, stage_note_url = book.stage_note()
      audiobooks, projects, have_oggs = get_audiobooks(book)
  
      (lambda ipk: (
          ('social_tags.choose_cite', [ipk]),
          ('catalogue_tags.choose_fragment', [ipk], {
-             'unless': V('social_tags.choose_cite', [ipk])}),
+             'unless': Var('social_tags.choose_cite', [ipk])}),
      ))(ssi_expect(pk, int)))
  def book_wide(request, pk):
-     book = get_object_or_404(models.Book, pk=pk)
+     book = get_object_or_404(Book, pk=pk)
      stage_note, stage_note_url = book.stage_note()
      extra_info = book.extra_info
      audiobooks, projects, have_oggs = get_audiobooks(book)
  
  @ssi_included
  def fragment_short(request, pk):
-     fragment = get_object_or_404(models.Fragment, pk=pk)
+     fragment = get_object_or_404(Fragment, pk=pk)
      return render(request, 'catalogue/fragment_short.html', {'fragment': fragment})
  
  
  @ssi_included
  def fragment_promo(request, pk):
-     fragment = get_object_or_404(models.Fragment, pk=pk)
+     fragment = get_object_or_404(Fragment, pk=pk)
      return render(request, 'catalogue/fragment_promo.html', {'fragment': fragment})
  
  
  @ssi_included
  def tag_box(request, pk):
-     tag = get_object_or_404(models.Tag, pk=pk)
+     tag = get_object_or_404(Tag, pk=pk)
      assert tag.category != 'set'
  
      return render(request, 'catalogue/tag_box.html', {
  
  @ssi_included
  def collection_box(request, pk):
-     obj = get_object_or_404(models.Collection, pk=pk)
+     obj = get_object_or_404(Collection, pk=pk)
  
      return render(request, 'catalogue/collection_box.html', {
          'obj': obj,
  
  def tag_catalogue(request, category):
      if category == 'theme':
-         tags = models.Tag.objects.usage_for_model(
-             models.Fragment, counts=True).filter(category='theme')
+         tags = Tag.objects.usage_for_model(
+             Fragment, counts=True).filter(category='theme')
      else:
          tags = list(get_top_level_related_tags((), categories=(category,)))
  
          'best': best,
          'title': constants.CATEGORIES_NAME_PLURAL[category],
          'whole_category': constants.WHOLE_CATEGORY[category],
+         'active_menu_item': 'theme' if category == 'theme' else None,
      })
  
  
  def collections(request):
-     objects = models.Collection.objects.all()
+     objects = Collection.objects.all()
  
      if len(objects) > 3:
          best = random.sample(objects, 3)
diff --combined src/picture/models.py
@@@ -101,7 -101,7 +101,7 @@@ class Picture(models.Model)
          pass
  
      class Meta:
-         ordering = ('sort_key',)
+         ordering = ('sort_key_author', 'sort_key')
  
          verbose_name = _('picture')
          verbose_name_plural = _('pictures')
          self.sort_key = sortify(self.title)[:120]
  
          try:
 -            author = self.tags.filter(category='author')[0].sort_key
 -        except IndexError:
 +            author = self.authors().first().sort_key
 +        except AttributeError:
              author = u''
          self.sort_key_author = author
  
      def __unicode__(self):
          return self.title
  
 -    def author_str(self):
 -        return ", ".join(str(t) for t in self.tags.filter(category='author'))
 +    def authors(self):
 +        return self.tags.filter(category='author')
  
 -        return ", ".join(unicode(t) for t in self.tags.filter(category=category))
+     def tag_unicode(self, category):
++        return ", ".join(self.tags.filter(category=category).values_list('name', flat=True))
      def author_unicode(self):
-         return ", ".join(self.authors().values_list('name', flat=True))
+         return self.tag_unicode('author')
  
      @permalink
      def get_absolute_url(self):
              pics_by_author[tag] = []
  
          for pic in pics.iterator():
 -            authors = list(pic.tags.filter(category='author'))
 +            authors = list(pic.authors().only('pk'))
              if authors:
                  for author in authors:
                      pics_by_author[author].append(pic)
          return self._info
  
      def pretty_title(self, html_links=False):
 -        picture = self
 -        names = [(tag.name, tag.get_absolute_url())
 -                 for tag in self.tags.filter(category='author')]
 +        names = [(tag.name, tag.get_absolute_url()) for tag in self.authors().only('name', 'category', 'slug')]
          names.append((self.title, self.get_absolute_url()))
  
          if html_links:
diff --combined src/picture/views.py
@@@ -2,6 -2,7 +2,7 @@@
  # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
  # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
  #
+ from django.conf import settings
  from django.contrib.auth.decorators import permission_required
  from django.shortcuts import render_to_response, get_object_or_404, render
  from django.template import RequestContext
@@@ -26,18 -27,17 +27,17 @@@ from sponsors.models import Sponso
  #             books_nav.setdefault(tag.sort_key[0], []).append(tag)
  #
  #     return render_to_response(template_name, locals(), context_instance=RequestContext(request))
+ from wolnelektury.utils import ajax
  
  
  def picture_list_thumb(request, filter=None, get_filter=None, template_name='picture/picture_list_thumb.html',
                         cache_key=None, context=None):
-     book_list = Picture.objects.all()
+     pictures = Picture.objects.all()
      if filter:
-         book_list = book_list.filter(filter)
+         pictures = pictures.filter(filter)
      if get_filter:
-         book_list = book_list.filter(get_filter())
-     book_list = book_list.order_by('sort_key_author')
-     book_list = list(book_list)
-     return render_to_response(template_name, locals(), context_instance=RequestContext(request))
+         pictures = pictures.filter(get_filter())
+     return render_to_response(template_name, {'book_list': list(pictures)}, context_instance=RequestContext(request))
  
  
  def picture_detail(request, slug):
      # for tag in picture.tags.iterator():
      #     categories.setdefault(tag.category, []).append(tag)
  
-     themes = theme_things.get('theme', [])
-     things = theme_things.get('thing', [])
-     extra_info = picture.extra_info
-     return render_to_response("picture/picture_detail.html", locals(),
-                               context_instance=RequestContext(request))
+     return render_to_response("picture/picture_detail.html", {
+         'picture': picture,
+         'themes': theme_things.get('theme', []),
+         'things': theme_things.get('thing', []),
+     }, context_instance=RequestContext(request))
  
  
  def picture_viewer(request, slug):
          have_sponsors = Sponsor.objects.filter(name=sponsor)
          if have_sponsors.exists():
              sponsors.append(have_sponsors[0])
-     return render_to_response("picture/picture_viewer.html", locals(),
-                               context_instance=RequestContext(request))
+     return render_to_response("picture/picture_viewer.html", {
+         'picture': picture,
+         'sponsors': sponsors,
+     }, context_instance=RequestContext(request))
+ @ajax(method='get')
+ def picture_page(request, key=None):
+     pictures = Picture.objects.order_by('-id')
+     if key is not None:
+         pictures = pictures.filter(id__lt=key)
+     pictures = pictures[:settings.PICTURE_PAGE_SIZE]
+     picture_data = [
+         {
+             'id': picture.id,
+             'title': picture.title,
+             'author': picture.author_unicode(),
+             'epoch': picture.tag_unicode('epoch'),
+             'kind': picture.tag_unicode('kind'),
+             'genre': picture.tag_unicode('genre'),
+             'style': picture.extra_info['style'],
+             'image_url': picture.image_file.url,
+             'width': picture.width,
+             'height': picture.height,
+         }
+         for picture in pictures
+     ]
+     return {
+         'pictures': picture_data,
+         'count': Picture.objects.count(),
+     }
  
  
  # =========
@@@ -100,9 -127,10 +127,9 @@@ def import_picture(request)
  @ssi_included
  def picture_mini(request, pk, with_link=True):
      picture = get_object_or_404(Picture, pk=pk)
 -    author_str = ", ".join(tag.name for tag in picture.tags.filter(category='author'))
      return render(request, 'picture/picture_mini_box.html', {
          'picture': picture,
 -        'author_str': author_str,
 +        'author': picture.author_unicode(),
          'with_link': with_link,
      })
  
@@@ -122,8 -150,10 +149,10 @@@ def picture_short(request, pk)
  @ssi_included
  def picturearea_short(request, pk):
      area = get_object_or_404(PictureArea, pk=pk)
-     theme = area.tags.filter(category='theme')
-     theme = theme and theme[0] or None
-     thing = area.tags.filter(category='thing')
-     thing = thing and thing[0] or None
-     return render(request, 'picture/picturearea_short.html', locals())
+     themes = area.tags.filter(category='theme')
+     things = area.tags.filter(category='thing')
+     return render(request, 'picture/picturearea_short.html', {
+         'area': area,
+         'theme': themes[0] if themes else None,
+         'thing': things[0] if things else None,
+     })
++@import "../tools";
++@import "const";
++
  @mixin inner-box {
-     display: block;
-     color: black;
-     @include size(margin, 1px);
-     @include size(padding, 8px 10px);
-     @include white-box;
+   display: block;
+   color: black;
+   @include size(margin, 1px);
+   @include size(padding, 8px 10px);
+   @include white-box;
  }
  
  .cover-area {
-     float: left;
-     @include size(margin-right, 15px);
-     @include size(margin-bottom, 5px);
+   float: left;
+   @include size(margin-right, 15px);
+   @include size(margin-bottom, 5px);
  
-     @include min-screen($S_BOOK_SHORT_FULL) {
-         position: absolute;
-         top: 0;
-         left: 0;
-         margin-right: 0;
-     }
+   @include min-screen($S_BOOK_SHORT_FULL) {
+     position: absolute;
+     top: 0;
+     left: 0;
+     margin-right: 0;
+   }
  
-     img.cover {
-         @include size(height, 193px / 2);
-         @include size(width, 139px / 2);
+   img.cover {
+     @include size(height, 193px / 2);
+     @include size(width, 139px / 2);
  
-         @include min-screen($S_BOOK_SHORT_MEDIUM) {
-             @include size(height, 193px);
-             @include size(width, 139px);
-         }
+     @include min-screen($S_BOOK_SHORT_MEDIUM) {
+       @include size(height, 193px);
+       @include size(width, 139px);
      }
+   }
  }
  
  .book-mini-box {
-     /* Original design fits 6 boxes horizontally in 975px (162.5px each),
-      * but we really want to fit 2 boxes on a 320px mobile screen. */
+   /* Original design fits 6 boxes horizontally in 975px (162.5px each),
+    * but we really want to fit 2 boxes on a 320px mobile screen. */
  
-     @include size(width, 160px);
-     display: inline-block;
-     vertical-align: top;
+   @include size(width, 160px);
+   display: inline-block;
+   vertical-align: top;
  
-     @include min-screen(350px) {
-         @include size(width, 162.5px);
-     }
-     .book-mini-box-inner {
-         @include inner-box;
-         @include size(height, 271px);
-         @include size(margin, 1px);
-         @include size(padding, 8px 9px);
-         overflow: hidden;
+   @include min-screen(350px) {
+     @include size(width, 162.5px);
+   }
  
-         @include min-screen(350px) {
-             @include size(padding, 8px 10px);
-         }
+   .book-mini-box-inner {
+     @include inner-box;
+     @include size(height, 271px);
+     @include size(margin, 1px);
+     @include size(padding, 8px 9px);
+     overflow: hidden;
  
-         a {
-             display: block;
-         }
-     }
-     img.cover {
-         @include size(height, 193px);
-         @include size(width, 139px);
-         @include size(margin-bottom, 18px);
-     }
-     .language {
-         color: #aaa;
-         float: right;
-         @include mono;
-         @include size(font-size, 10px);
-         text-transform: uppercase;
-         position: relative;
-         @include size(top, -20px);
-     }
-     .desc {
-         margin-left: 0;
-     }
-     .author {
-         @include size(font-size, 11px);
-         @include mono;
-         color: #6d7877;
-         display: block;
-         overflow: hidden;
-         text-overflow: ellipsis;
-         white-space: nowrap;
+     @include min-screen(350px) {
+       @include size(padding, 8px 10px);
      }
-     .title {
-         @include size(font-size, 14px);
-         color: #242424;
-         white-space: normal;
+     a {
+       display: block;
      }
+   }
+   img.cover {
+     @include size(height, 193px);
+     @include size(width, 139px);
+     @include size(margin-bottom, 18px);
+   }
+   .language {
+     color: #aaa;
+     float: right;
+     @include mono;
+     @include size(font-size, 10px);
+     text-transform: uppercase;
+     position: relative;
+     @include size(top, -20px);
+   }
+   .desc {
+     margin-left: 0;
+   }
+   .author {
+     @include size(font-size, 11px);
+     @include mono;
+     color: #6d7877;
+     display: block;
+     overflow: hidden;
+     text-overflow: ellipsis;
+     white-space: nowrap;
+   }
+   .title {
+     @include size(font-size, 14px);
+     color: #242424;
+     white-space: normal;
+   }
  }
  
  .work-list {
-     margin: 0;
-     padding: 0;
-     list-style: none;
+   margin: 0;
+   padding: 0;
+   list-style: none;
  
-     .Book-item {
-         /*@include min-screen($S_BOOK_SHORT_FULL) {
-             display: inline-block;
-         }
-         vertical-align: top;*/
+   .Book-item {
+     /*@include min-screen($S_BOOK_SHORT_FULL) {
+         display: inline-block;
      }
+     vertical-align: top;*/
+   }
  }
  
+ #books-list .plain-list-container .plain-list {
+   p {
+     line-height: 1.2em;
+     margin-bottom: 20px;
+     &.header {
+       font-weight: bold;
+     }
+   }
+ }
  
  .book-box {
-     margin: 0;
-     vertical-align: top;
+   margin: 0;
+   vertical-align: top;
  
-     /* */
-     a {
-         color: #0D7E85;
-     }
+   /* */
+   a {
+     color: #0D7E85;
+   }
  
-     .book-box-inner {
-         position: relative;
-         @include inner-box;
-         @include size(min-height, 197.5px);
-     }
+   .book-box-inner {
+     position: relative;
+     @include inner-box;
+     @include size(min-height, 197.5px);
+   }
  }
  
  .audiobook-box {
-     .book-left-column {
-         @media screen and (min-width: 1024px) {
-             display: inline-block;
-             @include size(width, 590px);
-         }
+   .book-left-column {
+     @media screen and (min-width: 1024px) {
+       display: inline-block;
+       @include size(width, 590px);
      }
+   }
  
-     .audiobook-right-column {
-         @media screen and (min-width: 1024px) {
-             float: right;
-             @include size(width, 360px);
-         }
+   .audiobook-right-column {
+     @media screen and (min-width: 1024px) {
+       float: right;
+       @include size(width, 360px);
      }
+   }
  
-     .jp-type-playlist {
-         margin-top: 24px;
+   .jp-type-playlist {
+     margin-top: 24px;
  
-         @media screen and (min-width: 1024px) {
-             float: right;
-             margin-top: 48px;
-         }
+     @media screen and (min-width: 1024px) {
+       float: right;
+       margin-top: 48px;
      }
+   }
  }
  
  .book-wide-box {
-     margin: 0;
-     vertical-align: top;
+   margin: 0;
+   vertical-align: top;
  
-     @media screen and (min-width: 62.5em) {
-         @include size(width, 975px);
+   @media screen and (min-width: 62.5em) {
+     @include size(width, 975px);
+   }
+   .book-box-inner {
+     position: relative;
+     @include size(min-height, 244px);
+     @include inner-box;
+     @include size(margin-left, 0);
+     @include size(margin-right, 0);
+     .book-left-column { /* FIXME */
+       @media screen and (min-width: 62.5em) {
+         float: left;
+         @include size(width, 536px);
+       }
      }
  
-     .book-box-inner {
-         position: relative;
-         @include size(min-height, 244px);
-         @include inner-box;
-         @include size(margin-left, 0);
-         @include size(margin-right, 0);
-         .book-left-column { /* FIXME */
-             @media screen and (min-width: 62.5em) {
-                 float: left;
-                 @include size(width, 536px);
-             }
-         }
+     .license-icon {
+       display: block;
+       @include size(margin-top, 5px);
+     }
  
-         .license-icon {
-             display: block;
-             @include size(margin-top, 5px);
+     @include min-screen($S_BOOK_SHORT_FULL) {
+       // Show full title on the work's page.
+       .book-box-body {
+         height: auto;
+         @include size(min-height, 170px);
+         .book-box-head .title {
+           height: auto;
+           @include size(min-height, 57.6px);
          }
+       }
+     }
  
-         @include min-screen($S_BOOK_SHORT_FULL) {
-              // Show full title on the work's page.
+     .book-box-head,
+     .tags,
+     .book-box-tools {
+       @media screen and (min-width: 62.5em) {
+         @include size(width, 382px);
+       }
+     }
  
-             .book-box-body {
-                 height: auto;
-                 @include size(min-height, 170px);
+     #theme-list-wrapper {
+       @include min-screen($S_BOOK_SHORT_MEDIUM) {
+         @include size(margin-left, 154px);
+         @include size(width, 300px);
+       }
+       margin-bottom: 0;
  
-                 .book-box-head .title {
-                     height: auto;
-                     @include size(min-height, 57.6px);
-                 }
-             }
-         }
+       p {
+         @include size(margin-top, 10px);
+         @include size(margin-bottom, 10px);
+       }
+     }
  
-         .book-box-head,
-         .tags,
-         .book-box-tools {
-             @media screen and (min-width: 62.5em) {
-                 @include size(width, 382px);
-             }
+     .right-column {
+       @include size(margin-top, 16px);
+       // Eat the padding
+       @include size(margin-left, -10px);
+       @include size(margin-right, -10px);
+       max-width: none;
+       @media screen and (min-width: 62.5em) {
+         @include size(width, 415px);
+         // Eat the padding
+         @include size(margin-top, -8px);
+       }
+       .other-tools,
+       .other-download {
+         @include size(font-size, 11px);
+         clear: left;
+         @include size(margin-top, 25px);
+         line-height: 1.75em;
+         @include size(margin-left, 15px);
+         h2 {
+           margin: 0;
+           @include size(font-size, 11px);
+           @include mono;
          }
  
-         #theme-list-wrapper {
-             @include min-screen($S_BOOK_SHORT_MEDIUM) {
-                 @include size(margin-left, 154px);
-                 @include size(width, 300px);
-             }
-             margin-bottom: 0;
-             p {
-                 @include size(margin-top, 10px);
-                 @include size(margin-bottom, 10px);
-             }
+         @include min-screen($S_BOOK_SHORT_FULL) {
+           float: left;
+           clear: none;
+           @include size(width, 145px);
+           @include size(margin-top, 50px);
+           @include size(margin-right, 0);
+           @include size(margin-bottom, 0);
+           @include size(margin-left, 5px);
          }
  
-         .right-column {
-             @include size(margin-top, 16px);
-             // Eat the padding
-             @include size(margin-left, -10px);
-             @include size(margin-right, -10px);
-             max-width: none;
-             @media screen and (min-width: 62.5em) {
-                 @include size(width, 415px);
-                 // Eat the padding
-                 @include size(margin-top, -8px);
-             }
-             .other-tools,
-             .other-download {
-                 @include size(font-size, 11px);
-                 clear: left;
-                 @include size(margin-top, 25px);
-                 line-height: 1.75em;
-                 @include size(margin-left, 15px);
-                 h2 {
-                     margin: 0;
-                     @include size(font-size, 11px);
-                     @include mono;
-                 }
-                 @include min-screen($S_BOOK_SHORT_FULL) {
-                     float: left;
-                     clear: none;
-                     @include size(width, 145px);
-                     @include size(margin-top, 50px);
-                     @include size(margin-right, 0);
-                     @include size(margin-bottom, 0);
-                     @include size(margin-left, 5px);
-                 }
-                 @include min-screen(1000px) {
-                     @include size(margin-top, 50px);
-                     line-height: 1.2em;
-                 }
-             }
-             .other-download {
-                 @include min-screen($S_BOOK_SHORT_FULL) {
-                     @include size(margin-left, 15px);
-                     @include size(width, 220px);
-                 }
-             }
+         @include min-screen(1000px) {
+           @include size(margin-top, 50px);
+           line-height: 1.2em;
          }
+       }
+       .other-download {
+         @include min-screen($S_BOOK_SHORT_FULL) {
+           @include size(margin-left, 15px);
+           @include size(width, 220px);
+         }
+       }
      }
+   }
  
-     .jp-type-playlist {
-         margin-top: 24px;
-         margin-left: 0.625rem;
+   .jp-type-playlist {
+     margin-top: 24px;
+     margin-left: 0.625rem;
  
-         @media screen and (min-width: 1024px) {
-             float: right;
-             margin-right: 0.625rem;
-         }
+     @media screen and (min-width: 1024px) {
+       float: right;
+       margin-right: 0.625rem;
      }
+   }
  
  }
  
  @media screen and (min-width: 50em) {
-     .picture.book-wide-box .right-column {
-         float: none;
-         @include size(width, 415px);
-         top: 0;
-         @include size(margin-left, 550px);
-         margin-top: 0em;
-     }
+   .picture.book-wide-box .right-column {
+     float: none;
+     @include size(width, 415px);
+     top: 0;
+     @include size(margin-left, 550px);
 -    margin-top: 0em;
++    margin-top: 0;
+   }
  }
  
  .book-box-body {
-     @include size(margin-bottom, 10px);
-     position: relative;
+   @include size(margin-bottom, 10px);
+   position: relative;
  
-     .book-box-head,
-     .tags,
-     .book-box-tools {
-         @include min-screen($S_BOOK_SHORT_FULL) {
-             margin-left: 154px;
-         }
+   .book-box-head,
+   .tags,
+   .book-box-tools {
+     @include min-screen($S_BOOK_SHORT_FULL) {
+       margin-left: 154px;
      }
+   }
  
-     .book-box-head {
-         @include size(padding-top, 14px);
-         @include size(margin-bottom, 10px);
+   .book-box-head {
+     @include size(padding-top, 14px);
+     @include size(margin-bottom, 10px);
  
-         @include min-screen($S_BOOK_SHORT_FULL) {
-             @include size(min-height, 70px);
-         }
+     @include min-screen($S_BOOK_SHORT_FULL) {
+       @include size(min-height, 70px);
+     }
  
-         a {
-             color: black;
-         }
-         .author {
-             @include size(font-size, 11px);
-             @include mono;
-             @include size(line-height, 13.2px);
-             @include size(max-height, 26.4px);
-             overflow: hidden;
-             @include min-screen($S_BOOK_SHORT_FULL) {
-                 @include size(max-width, 264px);
-             }
-         }
-         .title {
-             @include size(font-size, 24px);
-             line-height: 1.2em;
-             @include size(margin-top, 7.2px);
-             @include size(margin-bottom, 12px);
-             @include min-screen($S_BOOK_SHORT_FULL) {
-                 margin-bottom: 0;
-                 @include size(height, 57.6px);
-                 overflow: hidden;
-             }
-         }
+     a {
+       color: black;
+     }
+     .author {
+       @include size(font-size, 11px);
+       @include mono;
+       @include size(line-height, 13.2px);
+       @include size(max-height, 26.4px);
+       overflow: hidden;
+       @include min-screen($S_BOOK_SHORT_FULL) {
+         @include size(max-width, 264px);
+       }
+     }
+     .title {
+       @include size(font-size, 24px);
+       line-height: 1.2em;
+       @include size(margin-top, 7.2px);
+       @include size(margin-bottom, 12px);
+       @include min-screen($S_BOOK_SHORT_FULL) {
+         margin-bottom: 0;
+         @include size(height, 57.6px);
+         overflow: hidden;
+       }
      }
+   }
  
-     .tags {
-         @include size(font-size, 11px);
-         line-height: 1.2em;
-         margin-bottom: 5px;
+   .tags {
+     @include size(font-size, 11px);
+     line-height: 1.2em;
+     margin-bottom: 5px;
  
-         @include min-screen($S_BOOK_SHORT_FULL) {
-             @include size(max-height, 57.6px);
-             overflow: hidden;
-         }
+     @include min-screen($S_BOOK_SHORT_FULL) {
+       @include size(max-height, 57.6px);
+       overflow: hidden;
+     }
  
-         .category {
-             display: block;
-             @include size(margin-top, 6px);
-             @include size(margin-bottom, 6px);
+     .category {
+       display: block;
+       @include size(margin-top, 6px);
+       @include size(margin-bottom, 6px);
  
-             @include min-screen($S_BOOK_SHORT_FULL) {
-                 display: inline;
-             }
+       @include min-screen($S_BOOK_SHORT_FULL) {
+         display: inline;
+       }
  
-             .mono {
-                 @include mono;
-             }
+       .mono {
+         @include mono;
+       }
  
-             .book-box-tag {
-                 @include size(margin-left, 4.4px);
-                 @include size(margin-right, 5.5px);
-             }
-         }
+       .book-box-tag {
+         @include size(margin-left, 4.4px);
+         @include size(margin-right, 5.5px);
+       }
      }
+   }
  
  }
  
+ .book-box-tools {
+   @include size(font-size, 11px);
+   margin: 0;
+   padding: 0;
+   list-style: none;
  
+   clear: left;
  
- .book-box-tools {
-     @include size(font-size, 11px);
-     margin: 0;
-     padding: 0;
-     list-style: none;
+   @include min-screen($S_BOOK_SHORT_MEDIUM) {
+     clear: none;
+     @include size(margin-left, 139px + 15px);
+   }
  
-     clear: left;
+   li {
+     @include mono;
+     margin-top: 0;
+   }
  
-     @include min-screen($S_BOOK_SHORT_MEDIUM) {
-         clear: none;
-         @include size(margin-left, 139px + 15px);
+   .book-box-read {
+     a {
+       @include mono;
+       display: inline-block;
+       background: #0D7E85;
+       color: white;
+       @include size(width, 200px);
+       text-align: center;
+       @include size(margin-bottom, 5px);
      }
  
-     li {
-         @include mono;
-         margin-top: 0;
+     a:before {
+       content: url("/static/img/read-white.png");
+       @include size(font-size, 25px);
+       @include size(margin-right, 3.71px);
+       vertical-align: middle;
+       font-weight: normal;
+       // ugly quick fix
+       position: relative;
+       bottom: 2px;
      }
+   }
  
-     .book-box-read {
-         a {
-             @include mono;
-         }
+   .book-box-download {
+     position: relative;
  
-         a:before {
-             content: url("/static/img/read.png");
-             @include size(font-size, 25px);
-             @include size(margin-right, 3.71px);
-             vertical-align: middle;
-             font-weight: normal;
-         }
-     }
+     a {
+       @mixin downarrow {
+         color: #0D7E85;
  
-     .book-box-download {
-         position: relative;
-         a {
-             @mixin downarrow {
-                 color: #0D7E85;
-                 &:before {
-                     content: url("/static/img/download.png");
-                     @include size(font-size, 25px);
-                     @include size(margin-right, 3.71px);
-                     vertical-align: middle;
-                     font-weight: normal;
-                     display: inline;
-                 }
-             }
-             &.downarrow {
-                 @include downarrow;
-             }
+         &:before {
+           content: url("/static/img/download.png");
+           @include size(font-size, 25px);
+           @include size(margin-right, 3.71px);
+           vertical-align: middle;
+           font-weight: normal;
+           display: inline;
          }
+       }
  
-         .book-box-formats {
-             display: inline-block;
-             max-width: 220px;
-             vertical-align: top;
-             padding-top: 6px;
-                 a {
-                     display: inline-block;
-                     @include size(padding, .2em 1em);
-                 }
-         }
+       &.downarrow {
+         @include downarrow;
+       }
      }
- }
  
+     .book-box-formats {
+       display: inline-block;
+       max-width: 220px;
+       vertical-align: top;
+       padding-top: 6px;
  
+       a {
+         display: inline-block;
+         @include size(padding, .2em 1em);
+       }
+     }
+   }
+ }
  
  .star {
-     @include size(font-size, 22.5px);
-     @include size(margin-right, 11.25px);
-     position: absolute;
-     right: 0;
-     z-index: 10;
-     button {
-         cursor: pointer;
-         &::-moz-focus-inner {
-             padding: 0;
-             border: 0;
-         }
-     }
-     .if-unlike button {
-         font-size: 1em;
-         font-family: inherit;
-         border: 0;
-         background: none;
-         margin: 0;
-         padding: 0;
-         color: #757575;
-     }
-     .if-like a {
-         display:block;
-         text-align:right;
-         padding: 0;
+   @include size(font-size, 22.5px);
+   @include size(margin-right, 11.25px);
+   position: absolute;
+   right: 0;
++  z-index: 10;
 -  button::-moz-focus-inner {
 -    padding: 0;
 -    border: 0
++  button {
++    cursor: pointer;
++    &::-moz-focus-inner {
++      padding: 0;
++      border: 0
 +    }
+   }
+   .if-unlike button {
+     font-size: 1em;
+     font-family: inherit;
+     border: 0;
+     background: none;
+     margin: 0;
+     padding: 0;
+     color: #757575;
+   }
+   .if-like a {
+     display: block;
+     text-align: right;
+     padding: 0;
+   }
  }
  .like .if-unlike {
-     display: none;
+   display: none;
  }
  .unlike .if-like {
-     display: none;
+   display: none;
  }
  
  #book-detail .see-also,
  #picture-detail .see-also {
-     h1 {
-         @include size(height, 32px);
-         margin: 0;
-         @include size(padding-top, 19px);
-         @include size(padding-left, 10px);
+   h1 {
+     @include size(height, 32px);
+     margin: 0;
+     @include size(padding-top, 19px);
+     @include size(padding-left, 10px);
  
-         @include size(font-size, 11px);
-         @include mono;
-         font-weight: normal;
+     @include size(font-size, 11px);
+     @include mono;
+     font-weight: normal;
  
-         @media screen and (min-width: 33em) {
-             @include size(padding-left, 19px);
-         }
+     @media screen and (min-width: 33em) {
+       @include size(padding-left, 19px);
      }
+   }
  }
@@@ -1,34 -1,17 +1,35 @@@
++@import "../tools";
++
  $header_bg: #191919;
  $small_logo: .9;
  
 +#banners {
 +  display: inline-block;
 +  width: 100%;
 +
 +  > a {
 +    display: block;
 +    width: 100%;
 +  }
 +
 +  img {
 +    display: block;
 +    margin: 0 auto;
 +    width: 100%
 +  }
 +}
 +
  header#main {
    @include size(line-height, 20px); /* Make links easier to click when wrapped. */
    background-color: $header_bg;
    color: #bbb;
    position: relative;
  
-   Xtext-align: center;
+   /*text-align: center;*/
  
    @media screen and (min-width: 1024px) {
      width: 975px;
      margin: auto;
    }
  
    a {
      top: 0;
    }
  
-   X#user-info {
+   /*#user-info {
      margin-top: 0;
      @include size(margin-left, 5px);
      @include size(margin-right, 5px);
        @include size(margin-right, 0);
      }
  
-     /* We want submenu on far left on small screens. */
+     !* We want submenu on far left on small screens. *!
      .hidden-box-wrapper {
        position: static;
        @media screen and (min-width: 24em) {
          color: #0D7E85;
        }
      }
-   }
+   }*/
  
    form#search-area {
      position: relative;
          @include size(border-radius, 5px);
          @include box-shadow(0 0 6.5px #444444 inset);
  
--        font-family: Georgia;
++        font-family: Georgia, serif;
          @include size(font-size, 13px);
          background-color: white;
          color: black;
  
          /* styling search placeholder */
          &::placeholder {
--          font-family: Georgia;
++          font-family: Georgia, serif;
            font-style: italic;
            color: #767676;
          }
          &::-webkit-input-placeholder {
--          font-family: Georgia;
++          font-family: Georgia, serif;
            font-style: italic;
            color: #767676;
          }
          &::-moz-placeholder {
--          font-family: Georgia;
++          font-family: Georgia, serif;
            font-style: italic;
            color: #767676;
          }
  
    #header-wrapper {
      position: relative;
-     /* Upper-half both sides dark background */
-     &:before {
-       content: " ";
-       display: block;
-       z-index: -1;
-       position: absolute;
-       top: 0;
-       @include size(bottom, 45px);
-       left: 0;
-       width: 100%;
-       background-color: $header_bg;
-     }
-     /* Left-side dark background */
-     &:after {
-       content: " ";
-       display: block;
-       z-index: -1;
-       position: absolute;
-       top: 0;
-       bottom: 0;
-       left: 0;
-       width: 50%;
-       background-color: $header_bg;
-     }
+     background-color: $header_bg;
    }
  }
@@@ -2,7 -2,6 +2,7 @@@
  {% load static from staticfiles %}
  {% load i18n catalogue_tags infopages_tags social_tags %}
  {% load ssi_include from ssify %}
 +{% load cache %}
  
  
  {% block title %}{% trans "Wolne Lektury internet library" %}{% endblock %}
  
  {% block body %}{% spaceless %}
  
 -    {% choose_cite as cite_pk %}
 -    {{ cite_pk.if }}
 -        {% ssi_include 'social_cite_main' pk=cite_pk %}
 -    {{ cite_pk.endif }}
 -
 -    <section id="main-library">
 -        <h1>W naszej cyfrowej bibliotece znajdziesz</h1>
 -        <div class="main-library-row">
 -            <div class="covers">
 -            {% for b in best %}
 -                {% ssi_include 'catalogue_book_mini' pk=b.pk %}
 -            {% endfor %}
 -            </div>
 -            <a href="{% url "book_list" %}">
 -                <div class="note white-box normal-text" style="font-size: 18px">
 -                    i wiele innych książek, wierszy, obrazów, audiobooków…
 -                </div>
 -            </a>
 -        </div>
 -    </section>
 -
 -    <section id="main-theme">
 -        <h1>Motywy i tematy</h1>
 -        <div class="white-box normal-text">
 -        <h2>{% trans "Theme" %}: {{ theme }}</h2>
 -        <p>Utwory, w których występuje ten motyw:</p>
 -        {% for book in theme_books %}
 -            {% ssi_include 'catalogue_book_mini' pk=book.pk %}
 +  {% choose_cite as cite_pk %}
 +  {{ cite_pk.if }}
 +    {% ssi_include 'social_cite_main' pk=cite_pk %}
 +  {{ cite_pk.endif }}
 +
 +  <section id="main-library">
 +    <h1>W naszej cyfrowej bibliotece znajdziesz</h1>
 +    <div class="main-library-row">
 +      <div class="covers">
 +        {% for book in best %}
 +          {% cache 86400 book_mini_box book.pk %}
 +            {% include 'catalogue/book_mini_box.html' %}
 +          {% endcache %}
 +          {#% ssi_include 'catalogue_book_mini' pk=b.pk %#}
          {% endfor %}
 -        {% if theme_fragment %}
 -            {% ssi_include 'catalogue_fragment_promo' pk=theme_fragment.pk %}
 -        {% endif %}
 +      </div>
-       <div class="note white-box normal-text" style="font-size: 18px">
-         i wiele innych książek, wierszy, obrazów, audiobooków…
-       </div>
++      <a href="{% url "book_list" %}">
++        <div class="note white-box normal-text" style="font-size: 18px">
++          i wiele innych książek, wierszy, obrazów, audiobooków…
+         </div>
 -        <a class="more" href="{% url 'theme_catalogue' %}">Zobacz katalog motywów</a>
 -    </section>
 -
 -    {% comment %}
 -    <section class="tag-box-section">
 -        <h1>Autorzy</h1>
 -      <a class="tag-box" href="{{ author.get_absolute_url }}">
 -      {% ssi_include "catalogue_tag_box" pk=author.pk %}
+       </a>
 -        <a class="more" href="{% url 'author_catalogue' %}">Zobacz katalog autorów</a>
 -    </section>
 +    </div>
 +  </section>
 +
 +  <section id="main-theme">
 +    <h1>Motywy i tematy</h1>
 +    <div class="white-box normal-text">
 +      <h2>{% trans "Theme" %}: {{ theme }}</h2>
 +      <p>Utwory, w których występuje ten motyw:</p>
 +      {% for book in theme_books %}
 +        {% cache 86400 book_mini_box book.pk %}
 +          {% include 'catalogue/book_mini_box.html' %}
 +        {% endcache %}
 +        {#% ssi_include 'catalogue_book_mini' pk=book.pk %#}
 +      {% endfor %}
 +      {% if theme_fragment %}
 +        {% ssi_include 'catalogue_fragment_promo' pk=theme_fragment.pk %}
 +      {% endif %}
 +    </div>
 +    <a class="more" href="{% url 'theme_catalogue' %}">Zobacz katalog motywów</a>
 +  </section>
 +
 +  {% comment %}
 +  <section class="tag-box-section">
 +    <h1>Autorzy</h1>
 +    <a class="tag-box" href="{{ author.get_absolute_url }}">
 +      {% ssi_include "catalogue_tag_box" pk=author.pk %}
 +    </a>
 +    <a class="more" href="{% url 'author_catalogue' %}">Zobacz katalog autorów</a>
 +  </section>
  
 -    <section class="tag-box-section">
 -        <h1>Gatunki</h1>
 -      <a class="tag-box" href="{{ genre.get_absolute_url }}">
 +  <section class="tag-box-section">
 +    <h1>Gatunki</h1>
 +    <a class="tag-box" href="{{ genre.get_absolute_url }}">
        {% ssi_include "catalogue_tag_box" pk=genre.pk %}
 -      </a>
 -        <a class="more" href="{% url 'genre_catalogue' %}">Zobacz katalog gatunków</a>
 -    </section>
 +    </a>
 +    <a class="more" href="{% url 'genre_catalogue' %}">Zobacz katalog gatunków</a>
 +  </section>
  
 -    <section class="tag-box-section">
 -        <h1>Rodzaje</h1>
 -      <a class="tag-box" href="{{ kind.get_absolute_url }}">
 +  <section class="tag-box-section">
 +    <h1>Rodzaje</h1>
 +    <a class="tag-box" href="{{ kind.get_absolute_url }}">
        {% ssi_include "catalogue_tag_box" pk=kind.pk %}
 -      </a>
 -        <a class="more" href="{% url 'kind_catalogue' %}">Zobacz katalog rodzajów</a>
 -    </section>
 +    </a>
 +    <a class="more" href="{% url 'kind_catalogue' %}">Zobacz katalog rodzajów</a>
 +  </section>
  
 -    <section class="tag-box-section">
 -        <h1>Epoki</h1>
 -      <a class="tag-box" href="{{ epoch.get_absolute_url }}">
 +  <section class="tag-box-section">
 +    <h1>Epoki</h1>
 +    <a class="tag-box" href="{{ epoch.get_absolute_url }}">
        {% ssi_include "catalogue_tag_box" pk=epoch.pk %}
 -      </a>
 -        <a class="more" href="{% url 'epoch_catalogue' %}">Zobacz katalog epok</a>
 -    </section>
 -    {% endcomment %}
 -
 -    {% if collection %}
 -        <section>
 -            <h1>Kolekcje</h1>
 -            {% ssi_include 'catalogue_collection_box' pk=collection.pk %}
 -            <a class="more" href="{% url 'catalogue_collections' %}">Zobacz katalog kolekcji</a>
 -        </section>
 -    {% endif %}
 +    </a>
 +    <a class="more" href="{% url 'epoch_catalogue' %}">Zobacz katalog epok</a>
 +  </section>
 +  {% endcomment %}
  
 +  {% if collection %}
      <section>
 -        <h1>{% trans "Recent publications" %}</h1>
 -            {% for book in last_published %}
 -                {% ssi_include 'catalogue_book_mini' pk=book.pk %}
 -            {% endfor %}
 -        <a class="more" href="{% url 'recent_list' %}">{% trans "More recent publications" %}</a>
 +      <h1>Kolekcje</h1>
 +      {% ssi_include 'catalogue_collection_box' pk=collection.pk %}
 +      <a class="more" href="{% url 'catalogue_collections' %}">Zobacz katalog kolekcji</a>
      </section>
 -
 -    <div class="clearboth"></div>
 -
 -    <section class="infopages-box">
 -        <h1>{% trans "News" %}</h1>
 -        {% ssi_include 'latest_blog_posts' %}
 -    </section>
 -
 -
 -    <section class="infopages-box">
 -        <h1>{% trans "Utilities" %}</h1>
 -
 -        <ul>
 -            <li><a href="{% url 'suggest' %}" id="suggest" class="ajaxable">{% trans "Report a bug or suggestion" %}</a></li>
 -            <!--li><a href="http://turniej.wolnelektury.pl">Turniej Elektrybałtów</a></li-->
 -            <li><a href="{% url 'reporting_catalogue_pdf' %}">{% trans "Download the catalogue in PDF format." %}</a></li>
 -          <li><a href="{% url 'dictionary_notes' %}">{% trans "Footnotes" %}</a></li>
 -            <li><a href="{% url 'suggest_publishing' %}" id="suggest-publishing" class="ajaxable">{% trans "Missing a book?" %}</a></li>
 -            <li><a href="{% url 'publish_plan' %}">{% trans "Publishing plan" %}</a></li>
 -            <li><a href="{% url 'api' %}">API</a></li>
 -            <li><a href="{% url 'oaipmh' %}">OAI-PMH</a></li>
 -            <li><a href="{% url 'lesmianator' %}" lang="pl">Leśmianator</a></li>
 -            <li><a href="http://polski.wolnelektury.pl" lang="pl">Materiały do nauki j. polskiego</a></li>
 -
 -        </ul>
 -    </section>
 -
 -
 -    <section class="infopages-box">
 -        <h1>{% trans "Information" %}</h1>
 -        <ul>
 -            <li><a href="https://nowoczesnapolska.org.pl/prywatnosc/">{% trans "Privacy policy" %}</a></li>
 -            {% infopages_on_main %}
 -        </ul>
 -
 -        <div class="social-links">
 -            <a href="https://pl-pl.facebook.com/pages/Wolne-Lektury/203084073268" title='Wolne Lektury @ Facebook'>
 -                <img src="{% static "img/social/f.png" %}" alt="Wolne Lektury @ Facebook" />
 -            </a>
 -            <a href="https://nk.pl/profile/30441509" title='Wolne Lektury @ NK'>
 -                <img src="{% static "img/social/nk.png" %}" alt="Wolne Lektury @ NK.pl" />
 -            </a>
 -        </div>
 -    </section>
 -
 +  {% endif %}
 +
 +  <section>
 +    <h1>{% trans "Recent publications" %}</h1>
 +      {% for book in last_published %}
 +        {% cache 86400 book_mini_box book.pk %}
 +          {% include 'catalogue/book_mini_box.html' %}
 +        {% endcache %}
 +        {#% ssi_include 'catalogue_book_mini' pk=book.pk %#}
 +      {% endfor %}
 +    <a class="more" href="{% url 'recent_list' %}">{% trans "More recent publications" %}</a>
 +  </section>
 +
 +  <div class="clearboth"></div>
 +
 +  <section class="infopages-box">
 +    <h1>{% trans "News" %}</h1>
 +    {% ssi_include 'latest_blog_posts' %}
 +  </section>
 +
 +
 +  <section class="infopages-box">
 +    <h1>{% trans "Utilities" %}</h1>
 +
 +    <ul>
 +      <li><a href="{% url 'suggest' %}" id="suggest" class="ajaxable">{% trans "Report a bug or suggestion" %}</a></li>
 +      <!--li><a href="http://turniej.wolnelektury.pl">Turniej Elektrybałtów</a></li-->
 +      <li><a href="{% url 'reporting_catalogue_pdf' %}">{% trans "Download the catalogue in PDF format." %}</a></li>
 +<li><a href="{% url 'dictionary_notes' %}">{% trans "Footnotes" %}</a></li>
 +      <li><a href="{% url 'suggest_publishing' %}" id="suggest-publishing" class="ajaxable">{% trans "Missing a book?" %}</a></li>
 +      <li><a href="{% url 'publish_plan' %}">{% trans "Publishing plan" %}</a></li>
 +      <li><a href="{% url 'api' %}">API</a></li>
 +      {#<li><a href="{% url 'oaipmh' %}">OAI-PMH</a></li>#}
 +      <li><a href="{% url 'lesmianator' %}" lang="pl">Leśmianator</a></li>
 +      <li><a href="http://polski.wolnelektury.pl" lang="pl">Materiały do nauki j. polskiego</a></li>
 +    </ul>
 +  </section>
 +
 +
 +  <section class="infopages-box">
 +    <h1>{% trans "Information" %}</h1>
 +    <ul>
 +      <li><a href="https://nowoczesnapolska.org.pl/prywatnosc/">{% trans "Privacy policy" %}</a></li>
 +      {% infopages_on_main %}
 +    </ul>
 +
 +    <div class="social-links">
 +      <a href="https://pl-pl.facebook.com/pages/Wolne-Lektury/203084073268" title='Wolne Lektury @ Facebook'>
 +        <img src="{% static "img/social/f.png" %}" alt="Wolne Lektury @ Facebook" />
 +      </a>
 +      <a href="https://nk.pl/profile/30441509" title='Wolne Lektury @ NK'>
 +        <img src="{% static "img/social/nk.png" %}" alt="Wolne Lektury @ NK.pl" />
 +      </a>
 +    </div>
 +  </section>
  
  {% endspaceless %}{% endblock %}
  
  
  {% block add_footer %}{% spaceless %}
 -{{ cite_pk.if }}
 +  {{ cite_pk.if }}
      <p>{% trans "Image used:" %}
 -    {% ssi_include 'social_cite_info' pk=cite_pk %}
 +      {% ssi_include 'social_cite_info' pk=cite_pk %}
      </p>
 -{{ cite_pk.endif }}
 +  {{ cite_pk.endif }}
  {% endspaceless %}{% endblock %}
@@@ -1,6 -1,6 +1,6 @@@
  <!DOCTYPE html>
  {% spaceless %}
 -<html lang="{{ LANGUAGE_CODE }}" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
 +    <html lang="{{ LANGUAGE_CODE }}" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
      {% load pipeline i18n %}
      {% load static from staticfiles %}
      {% load catalogue_tags funding_tags reporting_stats %}
      <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
-         <meta name="application-name" content="Wolne Lektury"/>
-         <meta property="og:site_name" content="Wolne Lektury"/>
-         <meta property="og:title" content="{% block ogtitle %}{{ page_title }}{% endblock %}"/>
-         <meta property="og:type" content="{% block ogtype %}website{% endblock %}"/>
-         <meta property="og:image" content="{% block ogimage %}{{ FULL_STATIC_URL }}img/wiatrak.png{% endblock %}"/>
-         <meta name="description"
-               content="{% block metadescription %}Darmowe, opracowane, pełne teksty lektur, e-booki, audiobooki i pliki DAISY na wolnej licencji.{% endblock %}"/>
+         <meta name="application-name" content="Wolne Lektury" />
+         <meta property="og:site_name" content="Wolne Lektury" />
 -        <meta property="og:title" content="{% block ogtitle %}{% endblock %}" />
++        <meta property="og:title" content="{% block ogtitle %}{{ page_title }}{% endblock %}" />
+         <meta property="og:type" content="{% block ogtype %}website{% endblock %}" />
+         <meta property="og:image" content="{% block ogimage %}{{ FULL_STATIC_URL }}img/wiatrak.jpg{% endblock %}" />
+         <meta name="description" content="{% block metadescription %}Darmowe, opracowane, pełne teksty lektur, e-booki, audiobooki i pliki DAISY na wolnej licencji.{% endblock %}" />
          {% block ogextra %}{% endblock %}
  
 -        <title>{% block title %}{% trans "Wolne Lektury" %} :: {% block titleextra %}{% endblock %}{% endblock %}</title>
 -        <link rel="icon" href="{% static 'img/favicon.png' %}" type="image/png" />
 -        <link rel="search" type="application/opensearchdescription+xml" title="Wolne Lektury" href="{% static 'opensearch.xml' %}" />
 +        <title>
 +            {% block title %}{% block titleextra %}{{ page_title }}{% endblock %} :: {% trans "Wolne Lektury" %}{% endblock %}</title>
 +        <link rel="icon" href="{% static 'img/favicon.png' %}" type="image/png"/>
 +        <link rel="search" type="application/opensearchdescription+xml" title="Wolne Lektury"
 +              href="{% static 'opensearch.xml' %}"/>
          {% stylesheet "main" %}
          {% block extrahead %}
          {% endblock %}
      </head>
      <body id="{% block bodyid %}base{% endblock %}">
  
 -        {% block bodycontent %}
 +    {% block bodycontent %}
  
          {% if not funding_no_show_current %}
              {% current_offer as current_offer %}
              {{ current_offer.if }}
 -                {% ssi_include 'funding_top_bar' pk=current_offer %}
 +            {% ssi_include 'funding_top_bar' pk=current_offer %}
              {{ current_offer.endif }}
          {% endif %}
  
          <div id="whole-header">
 -        <div id="header-wrapper">
 -        <header id="main">
 +            <div id="header-wrapper">
 +                <header id="main">
  
 -            <a href="/" id="logo">
 -                <img src="{% static 'img/logo-neon.png' %}" alt="Wolne Lektury" />
 -            </a>
 +                    <a href="/" id="logo">
 +                        <img src="{% static 'img/logo-neon.png' %}" alt="Wolne Lektury"/>
 +                    </a>
  
 -            <p id="tagline">
 -                    {% url 'book_list' as b %}
 -                    {% url 'infopage' 'prawa' as r %}
 +                    <p id="tagline">
 +                        {% url 'book_list' as b %}
 +                        {% url 'infopage' 'prawa' as r %}
                          {% count_books book_count %}
 -                    {% blocktrans count book_count as c %}
 -                    <a href='{{b}}'>{{c}}</a> free reading you have <a href='{{r}}'>right to</a>
 -                    {% plural %}
 -                    <a href='{{b}}'>{{c}}</a> free readings you have <a href='{{r}}'>right to</a>
 -                    {% endblocktrans %}
 -            </p>
 -
 -            <div id="lang-menu" class="hoverget">
 +                        {% blocktrans count book_count as c %}
 +                            <a href='{{ b }}'>{{ c }}</a> free reading you have <a href='{{ r }}'>right to</a>
 +                        {% plural %}
 +                            <a href='{{ b }}'>{{ c }}</a> free readings you have <a href='{{ r }}'>right to</a>
 +                        {% endblocktrans %}
 +                    </p>
 +
 +                    <div id="lang-menu" class="hoverget">
                  <span id='lang-button' class='hoverclick'>
                      <span class="lang-flag">⚐</span>
                      <span class="label"> {% trans "Language" %}</span>
                  </span>
 -                <div id="lang-menu-items">
 -                {% for lang in LANGUAGES %}
 -                    <form action="{% url 'django.views.i18n.set_language' %}" method="post">
 -                    {% ssi_csrf_token %}
 -                    <input type="hidden" name="language" value="{{ lang.0 }}" />
 -                    <button type="submit" lang="{{ lang.0 }}" class="{% ifequal lang.0 LANGUAGE_CODE %}active{% endifequal %}">{{ lang.1 }}</button>
 -                    </form>
 -                {% endfor %}
 -                </div>
 -            </div>
 -
 -            <a id="show-menu"></a>
 -            <nav id="menu">
 -
 -            <ul id="user-info">
 -                {% user_username as user_username %}
 -                {% user_is_staff as user_is_staff %}
 -                {{ user_username.if }}<li>
 -                        <a href="{% url 'user_settings' %}">
 -                            <strong>{{ user_username }}</strong>
 -                        </a>
 -                    </li>
 -                <li><a href="{% url 'social_my_shelf' %}" id="user-shelves-link">{% trans "My shelf" %}</a>
 -                </li>
 -                {{ user_username.endif }}
 -                {{ user_is_staff.if }}<li><a href="/admin/">{% trans "Administration" %}</a></li>
 -                {{ user_is_staff.endif }}
 -                {{ user_username.if }}<li><a href="{% url 'logout' %}?next={% block logout %}{{ request.get_full_path }}{% endblock %}">{% trans "Logout" %}</a></li>
 -                {{ user_username.else }}
 -                    <li>
 -                    <a href="{% url 'login' %}?next={{ request.path }}" id="login">{% trans "Sign in" %}</a> / <a href="{% url 'register' %}?next={{ request.path }}" id="register">{% trans "Register" %}</a>
 -                    </li>
 -                {{ user_username.endif }}
 -            </ul>
 +                        <div id="lang-menu-items">
 +                            {% for lang in LANGUAGES %}
 +                                <form action="{% url 'django.views.i18n.set_language' %}" method="post">
 +                                    {% ssi_csrf_token %}
 +                                    <input type="hidden" name="language" value="{{ lang.0 }}"/>
 +                                    <button type="submit" lang="{{ lang.0 }}"
 +                                            class="{% ifequal lang.0 LANGUAGE_CODE %}active{% endifequal %}">{{ lang.1 }}</button>
 +                                </form>
 +                            {% endfor %}
 +                        </div>
 +                    </div>
 +
 +                    <a id="show-menu"></a>
 +                    <nav id="menu">
 +
 +                        <ul id="user-info">
 +                            {% user_username as user_username %}
 +                            {% user_is_staff as user_is_staff %}
 +                            {{ user_username.if }}
 +                            <li>
 +                                <a href="{% url 'user_settings' %}">
 +                                    <strong>{{ user_username }}</strong>
 +                                </a>
 +                            </li>
 +                            <li><a href="{% url 'social_my_shelf' %}" id="user-shelves-link">{% trans "My shelf" %}</a>
 +                            </li>
 +                            {{ user_username.endif }}
 +                            {{ user_is_staff.if }}
 +                            <li><a href="/admin/">{% trans "Administration" %}</a></li>
 +                            {{ user_is_staff.endif }}
 +                            {{ user_username.if }}
 +                            <li><a href="{% url 'logout' %}?next=
 +
 +
 +                                    {% block logout %}{{ request.get_full_path }}{% endblock %}">{% trans "Logout" %}</a>
 +                            </li>
 +                            {{ user_username.else }}
 +                            <li>
 +                                <a href="{% url 'login' %}?next={{ request.path }}" id="login">{% trans "Sign in" %}</a>
 +                                / <a href="{% url 'register' %}?next={{ request.path }}"
 +                                     id="register">{% trans "Register" %}</a>
 +                            </li>
 +                            {{ user_username.endif }}
 +                        </ul>
  
  
-                         <ul id="main-menu">
-                             <li><a href="{% url 'book_list' %}">{% trans "Literature" %}</a></li>
-                             <li><a href="{% url 'theme_catalogue' %}">{% trans "Themes" %}</a></li>
-                             <li><a href="{% url 'audiobook_list' %}">{% trans "Audiobooks" %}</a></li>
-                             <li><a href="{% url 'gallery' %}">{% trans "Gallery" %}</a></li>
-                             <li><a href="{% url 'catalogue' %}">Wszystkie utwory</a></li>
-                         </ul>
+             <ul id="main-menu">
+                 <li{% if active_menu_item == 'books' %} class="active"{% endif %}>
+                     <a href="{% url 'book_list' %}">{% trans "Literature" %}</a>
+                 </li>
+                 <li{% if active_menu_item == 'theme' %} class="active"{% endif %}>
+                     <a href="{% url 'theme_catalogue' %}">{% trans "Themes" %}</a>
+                 </li>
+                 <li{% if active_menu_item == 'audiobooks' %} class="active"{% endif %}>
+                     <a href="{% url 'audiobook_list' %}">{% trans "Audiobooks" %}</a>
+                 </li>
+                 <li{% if active_menu_item == 'gallery' %} class="active"{% endif %}>
+                     <a href="{% url 'gallery' %}">{% trans "Gallery" %}</a>
+                 </li>
+                 <li{% if active_menu_item == 'all_works' %} class="active"{% endif %}>
+                     <a href="{% url 'catalogue' %}">{% trans "All works" %}</a>
+                 </li>
+             </ul>
  
  
 -            </nav>
 +                    </nav>
  
 -            <form id="search-area" action="{% url 'search' %}">
 -                <div id="search-field">
 -                    <label for="search">{{search_form.q.label}}</label>
 -                        {{search_form.q}}
 -                </div><button type='submit'>{% trans "Search" %}</button>
 -            </form>
 +                    <form id="search-area" action="{% url 'search' %}">
 +                        <div id="search-field">
 +                            <label for="search">{{ search_form.q.label }}</label>
 +                            {{ search_form.q }}
 +                        </div>
 +                        <button type='submit'>{% trans "Search" %}</button>
 +                    </form>
  
 -        </header>
 -        </div>
 +                </header>
 +            </div>
          </div>
  
  
  
          <div id="main-content">
 +            <div id="banners">
 +                <a href="https://nowoczesnapolska.org.pl/pomoz-nam/wesprzyj-nas/">
 +                    <img src="{% static 'img/banners/960x150_wolneLektury.jpg' %}"
 +                         alt="Wesprzyj działalność Nowoczesnej Polski"/>
 +                </a>
 +            </div>
              {% block body %}
              {% endblock %}
              <div class="clearboth"></div>
  
  
          <div id="footer-wrapper">
 -        <footer id="main">
 -            {% ssi_include 'chunk' key='footer' %}
 -            {% block add_footer %}{% endblock %}
 -            {% ssi_include 'sponsor_page' name='footer' %}
 -        </footer>
 +            <footer id="main">
 +                {% ssi_include 'chunk' key='footer' %}
 +                {% block add_footer %}{% endblock %}
 +                {% ssi_include 'sponsor_page' name='footer' %}
 +            </footer>
          </div>
  
  
          </div>
  
  
 -        {% endblock bodycontent %}
 +    {% endblock bodycontent %}
  
  
 -        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
 -        <script type="text/javascript">var LANGUAGE_CODE="{{ LANGUAGE_CODE }}"; var STATIC_URL="{{ STATIC_URL }}";</script>
 -        {% javascript "base" %}
 +    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
 +    <script type="text/javascript">var LANGUAGE_CODE = "{{ LANGUAGE_CODE }}";
 +    var STATIC_URL = "{{ STATIC_URL }}";</script>
 +    {% javascript "base" %}
  
 -        {% tracking_code %}
 +    {% tracking_code %}
  
 -              {% block extrabody %}
 -              {% endblock %}
 +    {% block extrabody %}
 +    {% endblock %}
  
 -        <script src="{% static "js/contrib/modernizr.custom.19652.js" %}"></script>
 +    <script src="{% static "js/contrib/modernizr.custom.19652.js" %}"></script>
      </body>
 -</html>
 +    </html>
  {% endspaceless %}