# Tags file
TAGS
+
+media
--- /dev/null
+"""
+Provides a way to create forms behaving correctly as AJAX forms
+as well as standalone forms without any Javascript.
+"""
--- /dev/null
+{% load i18n %}
+<h1>{{ title }}</h1>
+
+<form action="{{ request.get_full_path }}" method="post" accept-charset="utf-8" class="cuteform">
+<ol>
+ <div id="id___all__"></div>
+ {{ form.as_ul }}
+ <li><input type="submit" value="{{ submit }}"/></li>
+</ol>
+</form>
\ No newline at end of file
--- /dev/null
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block titleextra %}{{ title }}{% endblock %}
+
+{% block body %}
+
+ {% include ajax_template %}
+
+ {% if response_data.message %}
+ <p>{{ response_data.message }}</p>
+ {% endif %}
+
+{% endblock %}
--- /dev/null
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.utils.encoding import force_unicode
+from django.utils.functional import Promise
+from django.utils.http import urlquote_plus
+from django.utils import simplejson
+from django.utils.translation import ugettext_lazy as _
+
+
+class LazyEncoder(simplejson.JSONEncoder):
+ def default(self, obj):
+ if isinstance(obj, Promise):
+ return force_unicode(obj)
+ return obj
+
+# shortcut for JSON reponses
+class JSONResponse(HttpResponse):
+ def __init__(self, data={}, callback=None, **kwargs):
+ # get rid of mimetype
+ kwargs.pop('mimetype', None)
+ data = simplejson.dumps(data)
+ if callback:
+ data = callback + "(" + data + ");"
+ super(JSONResponse, self).__init__(data, mimetype="application/json", **kwargs)
+
+
+
+class AjaxableFormView(object):
+ """Subclass this to create an ajaxable view for any form.
+
+ In the subclass, provide at least form_class.
+
+ """
+ form_class = None
+ # override to customize form look
+ template = "ajaxable/form.html"
+ submit = _('Send')
+
+ title = ''
+ success_message = ''
+ formname = "form"
+ full_template = "ajaxable/form_on_page.html"
+
+ def __call__(self, request):
+ """A view displaying a form, or JSON if `ajax' GET param is set."""
+ ajax = request.GET.get('ajax', False)
+ if request.method == "POST":
+ form = self.form_class(data=request.POST)
+ if form.is_valid():
+ self.success(form, request)
+ redirect = request.GET.get('next')
+ if not ajax and redirect:
+ return HttpResponseRedirect(urlquote_plus(
+ redirect, safe='/?=&'))
+ response_data = {'success': True,
+ 'message': self.success_message, 'redirect': redirect}
+ else:
+ response_data = {'success': False, 'errors': form.errors}
+ if ajax:
+ return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
+ else:
+ form = self.form_class()
+ response_data = None
+
+ template = self.template if ajax else self.full_template
+ return render_to_response(template, {
+ self.formname: form,
+ "title": self.title,
+ "submit": self.submit,
+ "response_data": response_data,
+ "ajax_template": self.template,
+ },
+ context_instance=RequestContext(request))
+
+ def success(self, form, request):
+ """What to do when the form is valid.
+
+ By default, just save the form.
+
+ """
+ return form.save(request)
from api.models import Deleted
from catalogue.forms import BookImportForm
from catalogue.models import Book, Tag, BookMedia, Fragment
+from picture.models import Picture
+from picture.forms import PictureImportForm
from stats.utils import piwik_track
"""
allowed_methods = ['GET']
- fields = ['title', 'parent'] + Book.file_types + [
+ fields = ['title', 'parent'] + Book.formats + [
'media', 'url'] + category_singular.keys()
@piwik_track
def read(self, request, slug):
- """ Returns details of a book, identified by a slug. """
-
+ """ Returns details of a book, identified by a slug and lang. """
try:
return Book.objects.get(slug=slug)
except Book.DoesNotExist:
else:
return ''
return get_file
-for format in Book.file_types:
+for format in Book.formats:
setattr(BooksHandler, format, _file_getter(format))
except KeyError, e:
return rc.NOT_FOUND
- tags = Tag.objects.filter(category=category_sng)
- tags = [t for t in tags if t.get_count() > 0]
- if tags:
+ tags = Tag.objects.filter(category=category_sng).exclude(book_count=0)
+ if tags.exists():
return tags
else:
return rc.NOT_FOUND
@piwik_track
def read(self, request, slug, anchor):
""" Returns details of a fragment, identified by book slug and anchor. """
-
try:
return Fragment.objects.get(book__slug=slug, anchor=anchor)
except Fragment.DoesNotExist:
def href(cls, fragment):
""" Returns URI in the API for the fragment. """
- return API_BASE + reverse("api_fragment", args=[fragment.book.slug, fragment.anchor])
+ return API_BASE + reverse("api_fragment",
+ args=[fragment.book.slug, fragment.anchor])
@classmethod
def url(cls, fragment):
def book_dict(book, fields=None):
all_fields = ['url', 'title', 'description',
'gazeta_link', 'wiki_link',
- ] + Book.file_types + [
- 'mp3', 'ogg', 'daisy',
+ ] + Book.formats + BookMedia.formats + [
'parent', 'parent_number',
'tags',
'license', 'license_description', 'source_name',
obj = {}
for field in fields:
- if field in Book.file_types:
+ if field in Book.formats:
f = getattr(book, field+'_file')
if f:
obj[field] = {
'size': f.size,
}
- elif field in ('mp3', 'ogg', 'daisy'):
+ elif field in BookMedia.formats:
media = []
for m in book.media.filter(type=field):
media.append({
changed_at__gte=since,
changed_at__lt=until):
# only serve non-empty tags
- if tag.get_count():
+ if tag.book_count:
tag_d = cls.tag_dict(tag, fields)
updated.append(tag_d)
elif tag.created_at < since:
@piwik_track
def read(self, request, since):
return self.changes(request, since)
+
+
+class PictureHandler(BaseHandler):
+ model = Picture
+ fields = ('slug', 'title')
+ allowed_methods = ('POST',)
+
+ def create(self, request):
+ if not request.user.has_perm('picture.add_picture'):
+ return rc.FORBIDDEN
+
+ data = json.loads(request.POST.get('data'))
+ form = PictureImportForm(data)
+ if form.is_valid():
+ form.save()
+ return rc.CREATED
+ else:
+ return rc.NOT_FOUND
db = init_db(last_checked)
for b in Book.objects.all():
add_book(db, b)
- for t in Tag.objects.exclude(category__in=('book', 'set', 'theme')):
+ for t in Tag.objects.exclude(
+ category__in=('book', 'set', 'theme')).exclude(book_count=0):
# only add non-empty tags
- if t.get_count():
- add_tag(db, t)
+ add_tag(db, t)
db.commit()
db.close()
current(last_checked)
from api.helpers import timestamp
from catalogue.models import Book, Tag
+from picture.tests.utils import RequestFactory
+from picture.forms import PictureImportForm
+from picture.models import Picture, picture_storage
+import picture.tests
+from django.core.files.uploadedfile import SimpleUploadedFile
+
+
+from os import path
class ApiTest(TestCase):
tag = json.loads(self.client.get('/api/authors/joe/').content)
self.assertEqual(tag['name'], self.tag.name,
'Wrong tag details.')
+
+
+class PictureTests(ApiTest):
+ def test_publish(self):
+ slug = "kandinsky-composition-viii"
+ xml = SimpleUploadedFile('composition8.xml', open(path.join(picture.tests.__path__[0], "files", slug + ".xml")).read())
+ img = SimpleUploadedFile('kompozycja-8.png', open(path.join(picture.tests.__path__[0], "files", slug + ".png")).read())
+
+ import_form = PictureImportForm({}, {
+ 'picture_xml_file': xml,
+ 'picture_image_file': img
+ })
+
+ assert import_form.is_valid()
+ if import_form.is_valid():
+ import_form.save()
+
+ pic = Picture.objects.get(slug=slug)
+
from piston.resource import Resource
from api import handlers
-
+from catalogue.models import Book
auth = OAuthAuthentication(realm="Wolne Lektury")
fragment_resource = Resource(handler=handlers.FragmentDetailHandler)
fragment_list_resource = Resource(handler=handlers.FragmentsHandler)
+picture_resource = Resource(handler=handlers.PictureHandler, authentication=auth)
urlpatterns = patterns(
'piston.authentication',
# objects details
- url(r'^books/(?P<slug>[a-z0-9-]+)/$', book_resource, name="api_book"),
+ url(r'^books/(?P<book>[a-z0-9-]+)/$', book_resource, name="api_book"),
url(r'^(?P<category>[a-z0-9-]+)/(?P<slug>[a-z0-9-]+)/$',
tag_resource, name="api_tag"),
- url(r'^books/(?P<slug>[a-z0-9-]+)/fragments/(?P<anchor>[a-z0-9-]+)/$',
+ url(r'^books/(?P<book>[a-z0-9-]+)/fragments/(?P<anchor>[a-z0-9-]+)/$',
fragment_resource, name="api_fragment"),
# books by tags
url(r'^(?P<tags>(?:(?:[a-z0-9-]+/){2}){0,6})books/$', book_list_resource),
url(r'^(?P<tags>(?:(?:[a-z0-9-]+/){2}){0,6})parent_books/$', book_list_resource, {"top_level": True}),
+ url(r'^pictures/$', picture_resource),
+
# fragments by book, tags, themes
# this should be paged
url(r'^(?P<tags>(?:(?:[a-z0-9-]+/){2}){1,6})fragments/$', fragment_list_resource),
class TagAdmin(admin.ModelAdmin):
- list_display = ('name', 'slug', 'sort_key', 'category', 'has_description', 'main_page',)
+ list_display = ('name', 'slug', 'sort_key', 'category', 'has_description',)
list_filter = ('category',)
search_fields = ('name',)
ordering = ('name',)
class JQueryAutoCompleteWidget(forms.TextInput):
- def __init__(self, source, options=None, *args, **kwargs):
- self.source = source
- self.options = None
- if options:
- self.options = dumps(options)
+ def __init__(self, options, *args, **kwargs):
+ self.options = dumps(options)
super(JQueryAutoCompleteWidget, self).__init__(*args, **kwargs)
- def render_js(self, field_id):
- source = "'%s'" % escape(self.source)
- options = ''
- if self.options:
- options += ', %s' % self.options
-
- return u'$(\'#%s\').autocomplete(%s%s).result(autocomplete_result_handler);' % (field_id, source, options)
+ def render_js(self, field_id, options):
+ return u'$(\'#%s\').autocomplete(%s).result(autocomplete_result_handler);' % (field_id, options)
def render(self, name, value=None, attrs=None):
final_attrs = self.build_attrs(attrs, name=name)
<script type="text/javascript">//<!--
%(js)s//--></script>
''' % {
- 'attrs' : flatatt(final_attrs),
- 'js' : self.render_js(final_attrs['id']),
+ 'attrs': flatatt(final_attrs),
+ 'js' : self.render_js(final_attrs['id'], self.options),
}
return mark_safe(html)
+class JQueryAutoCompleteSearchWidget(JQueryAutoCompleteWidget):
+ def __init__(self, *args, **kwargs):
+ super(JQueryAutoCompleteSearchWidget, self).__init__(*args, **kwargs)
+
+ def render_js(self, field_id, options):
+ return u""
+
+
class JQueryAutoCompleteField(forms.CharField):
- def __init__(self, source, options=None, *args, **kwargs):
+ def __init__(self, source, options={}, *args, **kwargs):
if 'widget' not in kwargs:
- kwargs['widget'] = JQueryAutoCompleteWidget(source, options)
+ options['source'] = source
+ kwargs['widget'] = JQueryAutoCompleteWidget(options)
super(JQueryAutoCompleteField, self).__init__(*args, **kwargs)
+class JQueryAutoCompleteSearchField(forms.CharField):
+ def __init__(self, options={}, *args, **kwargs):
+ if 'widget' not in kwargs:
+ kwargs['widget'] = JQueryAutoCompleteSearchWidget(options)
+
+ super(JQueryAutoCompleteSearchField, self).__init__(*args, **kwargs)
+
+
class OverwritingFieldFile(FieldFile):
"""
Deletes the old file before saving the new one.
from slughifi import slughifi
from catalogue.models import Tag, Book
-from catalogue.fields import JQueryAutoCompleteField
+from catalogue.fields import JQueryAutoCompleteSearchField
from catalogue import utils
class SearchForm(forms.Form):
- q = JQueryAutoCompleteField('/katalog/tags/', {'minChars': 2, 'selectFirst': True, 'cacheLength': 50, 'matchContains': "word"})
- tags = forms.CharField(widget=forms.HiddenInput, required=False)
+ q = JQueryAutoCompleteSearchField() # {'minChars': 2, 'selectFirst': True, 'cacheLength': 50, 'matchContains': "word"})
- def __init__(self, *args, **kwargs):
- tags = kwargs.pop('tags', [])
+ def __init__(self, source, *args, **kwargs):
+ kwargs['auto_id'] = False
super(SearchForm, self).__init__(*args, **kwargs)
- self.fields['q'].widget.attrs['title'] = _('title, author, theme/topic, epoch, kind, genre')
- #self.fields['q'].widget.attrs['style'] = ''
- self.fields['tags'].initial = '/'.join(tag.url_chunk for tag in Tag.get_tag_list(tags))
+ self.fields['q'].widget.attrs['id'] = _('search')
+ self.fields['q'].widget.attrs['autocomplete'] = _('off')
+ self.fields['q'].widget.attrs['data-source'] = _(source)
+ if not 'q' in self.data:
+ self.fields['q'].widget.attrs['title'] = _('title, author, theme/topic, epoch, kind, genre, phrase')
class UserSetsForm(forms.Form):
self.fields['set_ids'] = forms.MultipleChoiceField(
label=_('Shelves'),
required=False,
- choices=[(tag.id, "%s (%s)" % (tag.name, tag.get_count())) for tag in Tag.objects.filter(category='set', user=user)],
+ choices=[(tag.id, "%s (%s)" % (tag.name, tag.book_count)) for tag in Tag.objects.filter(category='set', user=user)],
initial=[tag.id for tag in obj.tags.filter(category='set', user=user)],
widget=forms.CheckboxSelectMultiple
)
return new_set
-FORMATS = (
- ('mp3', 'MP3'),
- ('ogg', 'OGG'),
- ('pdf', 'PDF'),
- ('odt', 'ODT'),
- ('txt', 'TXT'),
- ('epub', 'EPUB'),
- ('daisy', 'DAISY'),
- ('mobi', 'MOBI'),
-)
+FORMATS = [(f, f.upper()) for f in Book.ebook_formats]
class DownloadFormatsForm(forms.Form):
- formats = forms.MultipleChoiceField(required=False, choices=FORMATS, widget=forms.CheckboxSelectMultiple)
+ formats = forms.MultipleChoiceField(required=False, choices=FORMATS,
+ widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
super(DownloadFormatsForm, self).__init__(*args, **kwargs)
+
+PDF_PAGE_SIZES = (
+ ('a4paper', _('A4')),
+ ('a5paper', _('A5')),
+)
+
+
+PDF_LEADINGS = (
+ ('', _('Normal leading')),
+ ('onehalfleading', _('One and a half leading')),
+ ('doubleleading', _('Double leading')),
+ )
+
+PDF_FONT_SIZES = (
+ ('11pt', _('Default')),
+ ('13pt', _('Big'))
+ )
+
+
+class CustomPDFForm(forms.Form):
+ nofootnotes = forms.BooleanField(required=False, label=_("Don't show footnotes"))
+ nothemes = forms.BooleanField(required=False, label=_("Don't disply themes"))
+ nowlfont = forms.BooleanField(required=False, label=_("Don't use our custom font"))
+ ## pagesize = forms.ChoiceField(PDF_PAGE_SIZES, required=True, label=_("Paper size"))
+ leading = forms.ChoiceField(PDF_LEADINGS, required=False, label=_("Leading"))
+ fontsize = forms.ChoiceField(PDF_FONT_SIZES, required=True, label=_("Font size"))
+
+ @property
+ def customizations(self):
+ c = []
+ if self.cleaned_data['nofootnotes']:
+ c.append('nofootnotes')
+
+ if self.cleaned_data['nothemes']:
+ c.append('nothemes')
+
+ if self.cleaned_data['nowlfont']:
+ c.append('nowlfont')
+
+ ## c.append(self.cleaned_data['pagesize'])
+ c.append(self.cleaned_data['fontsize'])
+
+ if self.cleaned_data['leading']:
+ c.append(self.cleaned_data['leading'])
+
+ c.sort()
+
+ return c
+
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from librarian import DocProvider
+
+class ORMDocProvider(DocProvider):
+ """Used for getting books' children."""
+
+ def __init__(self, book):
+ self.book = book
+
+ def by_slug(self, slug):
+ if slug == self.book.slug:
+ return open(self.book.xml_file.path)
+ else:
+ return type(self.book).objects.get(slug=slug).xml_file
\ No newline at end of file
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-01-10 13:04+0100\n"
-"PO-Revision-Date: 2012-01-10 13:05+0100\n"
+"POT-Creation-Date: 2011-10-11 15:44+0200\n"
+"PO-Revision-Date: 2011-10-11 15:44+0100\n"
"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
msgid "Enter a valid JSON value. Error: %s"
msgstr "Wprowadź prawidłową wartość JSON. Błąd: %s"
-#: forms.py:26
+#: forms.py:25
msgid "Please supply an XML."
msgstr "Proszę podać XML."
-#: forms.py:40
+#: forms.py:39
msgid "title, author, theme/topic, epoch, kind, genre"
msgstr "tytuł, autor, motyw/temat, epoka, rodzaj, gatunek"
-#: forms.py:57
+#: forms.py:56
msgid "Shelves"
msgstr "Półki"
-#: forms.py:70
+#: forms.py:69
msgid "Name of the new shelf"
msgstr "nazwa nowej półki"
-#: models.py:29
+#: models.py:35
msgid "author"
msgstr "autor"
-#: models.py:30
+#: models.py:36
msgid "epoch"
msgstr "epoka"
-#: models.py:31
+#: models.py:37
msgid "kind"
msgstr "rodzaj"
-#: models.py:32
+#: models.py:38
msgid "genre"
msgstr "gatunek"
-#: models.py:33
+#: models.py:39
msgid "theme"
msgstr "motyw"
-#: models.py:34
+#: models.py:40
msgid "set"
msgstr "półka"
-#: models.py:35
-#: models.py:319
+#: models.py:41 models.py:314
msgid "book"
msgstr "książka"
-#: models.py:39
+#: models.py:45
msgid "ODT file"
msgstr "Plik ODT"
-#: models.py:40
+#: models.py:46
msgid "MP3 file"
msgstr "Plik MP3"
-#: models.py:41
+#: models.py:47
msgid "OGG file"
msgstr "Plik OGG"
-#: models.py:42
+#: models.py:48
msgid "DAISY file"
msgstr "Plik DAISY"
-#: models.py:59
-#: models.py:194
+#: models.py:65 models.py:198
msgid "name"
msgstr "nazwa"
-#: models.py:60
-#: models.py:294
-#: models.py:951
-#: models.py:968
-#: models.py:971
+#: models.py:66 models.py:287 models.py:876
msgid "slug"
msgstr "slug"
-#: models.py:61
-#: models.py:293
+#: models.py:67 models.py:286
msgid "sort key"
msgstr "klucz sortowania"
-#: models.py:62
+#: models.py:68
msgid "category"
msgstr "kategoria"
-#: models.py:64
-#: models.py:106
-#: models.py:295
-#: models.py:444
-#: models.py:969
+#: models.py:70 models.py:112 models.py:288 models.py:469
msgid "description"
msgstr "opis"
-#: models.py:68
+#: models.py:71
+msgid "main page"
+msgstr "strona główna"
+
+#: models.py:71
+msgid "Show tag on main page"
+msgstr "Pokazuj tag na stronie głównej"
+
+#: models.py:74
msgid "book count"
msgstr "liczba książek"
-#: models.py:72
-#: models.py:73
-#: models.py:196
-#: models.py:296
-#: models.py:297
+#: models.py:78 models.py:79 models.py:200 models.py:289 models.py:290
msgid "creation date"
msgstr "data utworzenia"
-#: models.py:90
+#: models.py:96
msgid "tag"
msgstr "tag"
-#: models.py:91
+#: models.py:97
msgid "tags"
msgstr "tagi"
-#: models.py:193
-#: models.py:952
+#: models.py:197 models.py:877
msgid "type"
msgstr "typ"
-#: models.py:195
+#: models.py:199
msgid "file"
msgstr "plik"
-#: models.py:197
-#: models.py:299
+#: models.py:201 models.py:292
msgid "extra information"
msgstr "dodatkowe informacje"
-#: models.py:206
-#: models.py:207
+#: models.py:210 models.py:211
msgid "book media"
msgstr "media książki"
-#: models.py:292
-#: models.py:967
+#: models.py:285
msgid "title"
msgstr "tytuł"
-#: models.py:298
+#: models.py:291
msgid "parent number"
msgstr "numer rodzica"
-#: models.py:320
+#: models.py:296
+msgid "XML file"
+msgstr "Plik XML"
+
+#: models.py:297
+msgid "HTML file"
+msgstr "Plik HTML"
+
+#: models.py:298
+msgid "PDF file"
+msgstr "Plik PDF"
+
+#: models.py:299
+msgid "EPUB file"
+msgstr "Plik EPUB"
+
+#: models.py:300
+msgid "TXT file"
+msgstr "Plik TXT"
+
+#: models.py:315
msgid "books"
msgstr "książki"
-#: models.py:408
+#: models.py:435
msgid "Read online"
msgstr "Czytaj online"
-#: models.py:672
+#: models.py:656
#, python-format
msgid "Book with slug = \"%s\" does not exist."
msgstr "Książki ο slug = \"%s\" nie istnieje."
-#: models.py:685
+#: models.py:669
#, python-format
msgid "Book %s already exists"
msgstr "Książka %s już istnieje"
-#: models.py:900
-#, python-format
-msgid "%s file"
-msgstr "plik %s"
-
-#: models.py:919
+#: models.py:844
msgid "fragment"
msgstr "fragment"
-#: models.py:920
+#: models.py:845
msgid "fragments"
msgstr "fragmenty"
-#: models.py:953
+#: models.py:878
msgid "sha-1 hash"
msgstr "hash sha-1"
-#: models.py:954
+#: models.py:879
msgid "time"
msgstr "czas"
-#: models.py:958
+#: models.py:883
msgid "file record"
msgstr ""
-#: models.py:959
+#: models.py:884
msgid "file records"
msgstr ""
-#: models.py:972
-msgid "book slugs"
-msgstr "slugi książek"
-
-#: models.py:976
-msgid "collection"
-msgstr "kolekcja"
-
-#: models.py:977
-msgid "collections"
-msgstr "kolekcje"
-
-#: views.py:509
+#: views.py:531
msgid "<p>To maintain your shelves you need to be logged in.</p>"
msgstr "<p>Aby zarządzać swoimi półkami, musisz się zalogować.</p>"
-#: views.py:531
+#: views.py:553
msgid "<p>Shelves were sucessfully saved.</p>"
msgstr "<p>Półki zostały zapisane.</p>"
-#: views.py:555
+#: views.py:577
msgid "Book was successfully removed from the shelf"
msgstr "Usunięto"
-#: views.py:557
+#: views.py:579
msgid "This book is not on the shelf"
msgstr "Książki nie ma na półce"
-#: views.py:676
+#: views.py:689
#, python-format
msgid "<p>Shelf <strong>%s</strong> was successfully removed</p>"
msgstr "<p>Półka <strong>%s</strong> została usunięta</p>"
-#: views.py:738
+#: views.py:748
#, python-format
msgid ""
"An error occurred: %(exception)s\n"
"\n"
"%(tb)s"
-#: views.py:739
+#: views.py:749
msgid "Book imported successfully"
msgstr "Książka zaimportowana"
-#: views.py:741
+#: views.py:751
#, python-format
msgid "Error importing file: %r"
msgstr "Błąd podczas importowania pliku: %r"
-#~ msgid "main page"
-#~ msgstr "strona główna"
-
-#~ msgid "Show tag on main page"
-#~ msgstr "Pokazuj tag na stronie głównej"
-
-#~ msgid "XML file"
-#~ msgstr "Plik XML"
-
-#~ msgid "HTML file"
-#~ msgstr "Plik HTML"
-
-#~ msgid "PDF file"
-#~ msgstr "Plik PDF"
-
-#~ msgid "EPUB file"
-#~ msgstr "Plik EPUB"
-
-#~ msgid "TXT file"
-#~ msgstr "Plik TXT"
-
#, fuzzy
#~ msgid "sort_key"
#~ msgstr "klucz sortowania"
#~ msgid "book stub"
#~ msgstr "zapowiedź książki"
+#~ msgid "book stubs"
+#~ msgstr "zapowiedzi książek"
+
#~ msgid "<p>Shelf <strong>%s</strong> was successfully created</p>"
#~ msgstr "<p>Półka <strong>%s</strong> została utworzona</p>"
from django.core.files import File
from catalogue.models import Book
+from picture.models import Picture
class Command(BaseCommand):
help='Don\'t build TXT file'),
make_option('-P', '--no-build-pdf', action='store_false', dest='build_pdf', default=True,
help='Don\'t build PDF file'),
+ make_option('-S', '--no-search-index', action='store_false', dest='search_index', default=True,
+ help='Don\'t build PDF file'),
make_option('-w', '--wait-until', dest='wait_until', metavar='TIME',
help='Wait until specified time (Y-M-D h:m:s)'),
+ make_option('-p', '--picture', action='store_true', dest='import_picture', default=False,
+ help='Import pictures'),
)
help = 'Imports books from the specified directories.'
args = 'directory [directory ...]'
+ def import_book(self, file_path, options):
+ verbose = options.get('verbose')
+ file_base, ext = os.path.splitext(file_path)
+ book = Book.from_xml_file(file_path, overwrite=options.get('force'),
+ build_epub=options.get('build_epub'),
+ build_txt=options.get('build_txt'),
+ build_pdf=options.get('build_pdf'),
+ build_mobi=options.get('build_mobi'),
+ search_index=options.get('search_index'))
+ for ebook_format in Book.ebook_formats:
+ if os.path.isfile(file_base + '.' + ebook_format):
+ getattr(book, '%s_file' % ebook_format).save(
+ '%s.%s' % (book.slug, ebook_format),
+ File(file(file_base + '.' + ebook_format)))
+ if verbose:
+ print "Importing %s.%s" % (file_base, ebook_format)
+
+ book.save()
+
+ def import_picture(self, file_path, options):
+ picture = Picture.from_xml_file(file_path, overwrite=options.get('force'))
+ return picture
+
def handle(self, *directories, **options):
from django.db import transaction
verbose = options.get('verbose')
force = options.get('force')
show_traceback = options.get('traceback', False)
+ import_picture = options.get('import_picture')
wait_until = None
if options.get('wait_until'):
wait_until = time.mktime(time.strptime(options.get('wait_until'), '%Y-%m-%d %H:%M:%S'))
if verbose > 0:
print "Will wait until %s; it's %f seconds from now" % (
- time.strftime('%Y-%m-%d %H:%M:%S',
+ time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(wait_until)), wait_until - time.time())
# Start transaction management.
# Import book files
try:
- book = Book.from_xml_file(file_path, overwrite=force,
- build_epub=options.get('build_epub'),
- build_txt=options.get('build_txt'),
- build_pdf=options.get('build_pdf'),
- build_mobi=options.get('build_mobi'))
+ if import_picture:
+ self.import_picture(file_path, options)
+ else:
+ self.import_book(file_path, options)
files_imported += 1
- if os.path.isfile(file_base + '.pdf'):
- book.pdf_file.save('%s.pdf' % book.slug, File(file(file_base + '.pdf')))
- if verbose:
- print "Importing %s.pdf" % file_base
- if os.path.isfile(file_base + '.mobi'):
- book.mobi_file.save('%s.mobi' % book.slug, File(file(file_base + '.mobi')))
- if verbose:
- print "Importing %s.mobi" % file_base
- if os.path.isfile(file_base + '.epub'):
- book.epub_file.save('%s.epub' % book.slug, File(file(file_base + '.epub')))
- if verbose:
- print "Importing %s.epub" % file_base
- if os.path.isfile(file_base + '.txt'):
- book.txt_file.save('%s.txt' % book.slug, File(file(file_base + '.txt')))
- if verbose:
- print "Importing %s.txt" % file_base
-
- book.save()
-
- except Book.AlreadyExists, msg:
- print self.style.ERROR('%s: Book already imported. Skipping. To overwrite use --force.' %
+ except (Book.AlreadyExists, Picture.AlreadyExists):
+ print self.style.ERROR('%s: Book or Picture already imported. Skipping. To overwrite use --force.' %
file_path)
files_skipped += 1
make_option('-e', '--exclude', dest='exclude', metavar='SLUG,...',
help='Exclude specific books by slug')
)
- help = 'Prepare data for Lesmianator.'
+ help = 'Prepare ZIP package with files of given type.'
args = '[%s] output_path.zip' % '|'.join(ftypes)
def handle(self, ftype, path, **options):
include = options.get('include')
exclude = options.get('exclude')
- if ftype in Book.file_types:
+ if ftype in Book.formats:
field = "%s_file" % ftype
else:
print self.style.ERROR('Unknown file type.')
+++ /dev/null
-# encoding: utf-8
-import datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-class Migration(SchemaMigration):
-
- def forwards(self, orm):
-
- # Adding model 'Collection'
- db.create_table('catalogue_collection', (
- ('title', self.gf('django.db.models.fields.CharField')(max_length=120, db_index=True)),
- ('slug', self.gf('django.db.models.fields.SlugField')(max_length=120, primary_key=True, db_index=True)),
- ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
- ('book_slugs', self.gf('django.db.models.fields.TextField')()),
- ))
- db.send_create_signal('catalogue', ['Collection'])
-
- if not db.dry_run:
- from django.core.management import call_command
- call_command("loaddata", "collection-boy.json")
-
- def backwards(self, orm):
-
- # Deleting model 'Collection'
- db.delete_table('catalogue_collection')
-
-
- models = {
- 'auth.group': {
- 'Meta': {'object_name': 'Group'},
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
- 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
- },
- 'auth.permission': {
- 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
- 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
- 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
- },
- 'auth.user': {
- 'Meta': {'object_name': 'User'},
- 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
- 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
- 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
- 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
- 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
- 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
- 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
- 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
- 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
- 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
- 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
- },
- 'catalogue.book': {
- 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'},
- 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
- 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
- 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
- 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
- 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
- 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
- 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
- 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
- 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
- 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
- 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
- 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
- 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
- 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
- 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
- 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
- },
- 'catalogue.bookmedia': {
- 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
- 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
- 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
- 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
- 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
- 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
- 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
- },
- 'catalogue.collection': {
- 'Meta': {'ordering': "('title',)", 'object_name': 'Collection'},
- 'book_slugs': ('django.db.models.fields.TextField', [], {}),
- 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
- 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'primary_key': 'True', 'db_index': 'True'}),
- 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'})
- },
- 'catalogue.filerecord': {
- 'Meta': {'ordering': "('-time', '-slug', '-type')", 'object_name': 'FileRecord'},
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'sha1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
- 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
- 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
- 'type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'})
- },
- 'catalogue.fragment': {
- 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
- 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
- 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'short_text': ('django.db.models.fields.TextField', [], {}),
- 'text': ('django.db.models.fields.TextField', [], {})
- },
- 'catalogue.tag': {
- 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
- 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
- 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
- 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
- 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
- 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
- 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
- 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
- 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
- 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
- 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
- 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
- },
- 'catalogue.tagrelation': {
- 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
- 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
- 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
- },
- 'contenttypes.contenttype': {
- 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
- 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
- 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
- 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
- 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
- }
- }
-
- complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Removing unique constraint on 'Book', fields ['slug']
+ db.delete_unique('catalogue_book', ['slug'])
+
+ # Adding field 'Book.language'
+ db.add_column('catalogue_book', 'language', self.gf('django.db.models.fields.CharField')(default='pol', max_length=3, db_index=True), keep_default=False)
+
+ # Adding unique constraint on 'Book', fields ['slug', 'language']
+ db.create_unique('catalogue_book', ['slug', 'language'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'Book', fields ['slug', 'language']
+ db.delete_unique('catalogue_book', ['slug', 'language'])
+
+ # Deleting field 'Book.language'
+ db.delete_column('catalogue_book', 'language')
+
+ # Adding unique constraint on 'Book', fields ['slug']
+ db.create_unique('catalogue_book', ['slug'])
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "[['slug', 'language']]", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.filerecord': {
+ 'Meta': {'ordering': "('-time', '-slug', '-type')", 'object_name': 'FileRecord'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'sha1': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting model 'FileRecord'
+ db.delete_table('catalogue_filerecord')
+
+
+ def backwards(self, orm):
+
+ # Adding model 'FileRecord'
+ db.create_table('catalogue_filerecord', (
+ ('sha1', self.gf('django.db.models.fields.CharField')(max_length=40)),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('time', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ('type', self.gf('django.db.models.fields.CharField')(max_length=20, db_index=True)),
+ ('slug', self.gf('django.db.models.fields.SlugField')(max_length=120, db_index=True)),
+ ))
+ db.send_create_signal('catalogue', ['FileRecord'])
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "[['slug', 'language']]", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'Book.cover'
+ db.add_column('catalogue_book', 'cover', self.gf('django.db.models.fields.files.FileField')(max_length=100, null=True, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'Book.cover'
+ db.delete_column('catalogue_book', 'cover')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "[['slug', 'language']]", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'cover': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'main_page': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'Tag.main_page'
+ db.delete_column('catalogue_tag', 'main_page')
+
+
+ def backwards(self, orm):
+
+ # Adding field 'Tag.main_page'
+ db.add_column('catalogue_tag', 'main_page', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True), keep_default=False)
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "[['slug', 'language']]", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'cover': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ from StringIO import StringIO
+ from django.core.files.base import ContentFile
+ from librarian import ValidationError
+ from librarian.cover import WLCover
+ from librarian.dcparser import BookInfo
+
+ for book in orm.Book.objects.filter(cover=None):
+ try:
+ book_info = BookInfo.from_file(book.xml_file.path)
+ except ValidationError:
+ pass
+ else:
+ cover = WLCover(book_info).image()
+ imgstr = StringIO()
+ cover.save(imgstr, 'png')
+ book.cover.save('book/png/%s.png' % book.slug,
+ ContentFile(imgstr.getvalue()))
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "[['slug', 'language']]", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'cover': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Removing unique constraint on 'Book', fields ['slug', 'language']
+ db.delete_unique('catalogue_book', ['slug', 'language'])
+
+ # Adding field 'Book.common_slug'
+ db.add_column('catalogue_book', 'common_slug', self.gf('django.db.models.fields.SlugField')(default='-', max_length=120, db_index=True), keep_default=False)
+
+ # Adding unique constraint on 'Book', fields ['slug']
+ db.create_unique('catalogue_book', ['slug'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'Book', fields ['slug']
+ db.delete_unique('catalogue_book', ['slug'])
+
+ # Deleting field 'Book.common_slug'
+ db.delete_column('catalogue_book', 'common_slug')
+
+ # Adding unique constraint on 'Book', fields ['slug', 'language']
+ db.create_unique('catalogue_book', ['slug', 'language'])
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'common_slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'cover': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ orm.Book.objects.all().update(common_slug=models.F('slug'))
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ pass
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'common_slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'cover': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Collection'
+ db.create_table('catalogue_collection', (
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=120, db_index=True)),
+ ('slug', self.gf('django.db.models.fields.SlugField')(max_length=120, primary_key=True, db_index=True)),
+ ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ('book_slugs', self.gf('django.db.models.fields.TextField')()),
+ ))
+ db.send_create_signal('catalogue', ['Collection'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Collection'
+ db.delete_table('catalogue_collection')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'catalogue.book': {
+ 'Meta': {'ordering': "('sort_key',)", 'object_name': 'Book'},
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'common_slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'cover': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'epub_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'html_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'default': "'pol'", 'max_length': '3', 'db_index': 'True'}),
+ 'mobi_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['catalogue.Book']"}),
+ 'parent_number': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'pdf_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'txt_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'xml_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'})
+ },
+ 'catalogue.bookmedia': {
+ 'Meta': {'ordering': "('type', 'name')", 'object_name': 'BookMedia'},
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'media'", 'to': "orm['catalogue.Book']"}),
+ 'extra_info': ('catalogue.fields.JSONField', [], {'default': "'{}'"}),
+ 'file': ('catalogue.fields.OverwritingFileField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'source_sha1': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': "'100'"}),
+ 'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
+ },
+ 'catalogue.collection': {
+ 'Meta': {'ordering': "('title',)", 'object_name': 'Collection'},
+ 'book_slugs': ('django.db.models.fields.TextField', [], {}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'primary_key': 'True', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'})
+ },
+ 'catalogue.fragment': {
+ 'Meta': {'ordering': "('book', 'anchor')", 'object_name': 'Fragment'},
+ 'anchor': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
+ 'book': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'fragments'", 'to': "orm['catalogue.Book']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'short_text': ('django.db.models.fields.TextField', [], {}),
+ 'text': ('django.db.models.fields.TextField', [], {})
+ },
+ 'catalogue.tag': {
+ 'Meta': {'ordering': "('sort_key',)", 'unique_together': "(('slug', 'category'),)", 'object_name': 'Tag'},
+ 'book_count': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'changed_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'gazeta_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'sort_key': ('django.db.models.fields.CharField', [], {'max_length': '120', 'db_index': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'wiki_link': ('django.db.models.fields.CharField', [], {'max_length': '240', 'blank': 'True'})
+ },
+ 'catalogue.tagrelation': {
+ 'Meta': {'unique_together': "(('tag', 'content_type', 'object_id'),)", 'object_name': 'TagRelation', 'db_table': "'catalogue_tag_relation'"},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['catalogue.Tag']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['catalogue']
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-from datetime import datetime
+from collections import namedtuple
from django.db import models
from django.db.models import permalink, Q
import django.dispatch
from django.core.cache import cache
+from django.core.files.storage import DefaultStorage
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from newtagging.models import TagBase, tags_updated
from newtagging import managers
from catalogue.fields import JSONField, OverwritingFileField
-from catalogue.utils import create_zip
+from catalogue.utils import create_zip, split_tags
+from catalogue.tasks import touch_tag, index_book
+from shutil import copy
+from glob import glob
+import re
+from os import path
+import search
+
+# Those are hard-coded here so that makemessages sees them.
TAG_CATEGORIES = (
('author', _('author')),
('epoch', _('epoch')),
('book', _('book')),
)
-MEDIA_FORMATS = (
- ('odt', _('ODT file')),
- ('mp3', _('MP3 file')),
- ('ogg', _('OGG file')),
- ('daisy', _('DAISY file')),
-)
-
# not quite, but Django wants you to set a timeout
CACHE_FOREVER = 2419200 # 28 days
category = models.CharField(_('category'), max_length=50, blank=False, null=False,
db_index=True, choices=TAG_CATEGORIES)
description = models.TextField(_('description'), blank=True)
- main_page = models.BooleanField(_('main page'), default=False, db_index=True, help_text=_('Show tag on main page'))
user = models.ForeignKey(User, blank=True, null=True)
book_count = models.IntegerField(_('book count'), blank=True, null=True)
has_description.boolean = True
def get_count(self):
- """ returns global book count for book tags, fragment count for themes """
-
- if self.book_count is None:
- if self.category == 'book':
- # never used
- objects = Book.objects.none()
- elif self.category == 'theme':
- objects = Fragment.tagged.with_all((self,))
- else:
- objects = Book.tagged.with_all((self,)).order_by()
- if self.category != 'set':
- # eliminate descendants
- l_tags = Tag.objects.filter(slug__in=[book.book_tag_slug() for book in objects])
- descendants_keys = [book.pk for book in Book.tagged.with_any(l_tags)]
- if descendants_keys:
- objects = objects.exclude(pk__in=descendants_keys)
- self.book_count = objects.count()
- self.save()
- return self.book_count
+ """Returns global book count for book tags, fragment count for themes."""
+
+ if self.category == 'book':
+ # never used
+ objects = Book.objects.none()
+ elif self.category == 'theme':
+ objects = Fragment.tagged.with_all((self,))
+ else:
+ objects = Book.tagged.with_all((self,)).order_by()
+ if self.category != 'set':
+ # eliminate descendants
+ l_tags = Tag.objects.filter(slug__in=[book.book_tag_slug() for book in objects])
+ descendants_keys = [book.pk for book in Book.tagged.with_any(l_tags)]
+ if descendants_keys:
+ objects = objects.exclude(pk__in=descendants_keys)
+ return objects.count()
@staticmethod
def get_tag_list(tags):
def url_chunk(self):
return '/'.join((Tag.categories_dict[self.category], self.slug))
+ @staticmethod
+ def tags_from_info(info):
+ from slughifi import slughifi
+ from sortify import sortify
+ meta_tags = []
+ categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
+ for field_name, category in categories:
+ try:
+ tag_names = getattr(info, field_name)
+ except:
+ try:
+ tag_names = [getattr(info, category)]
+ except:
+ # For instance, Pictures do not have 'genre' field.
+ continue
+ for tag_name in tag_names:
+ tag_sort_key = tag_name
+ if category == 'author':
+ tag_sort_key = tag_name.last_name
+ tag_name = tag_name.readable()
+ tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
+ if created:
+ tag.name = tag_name
+ tag.sort_key = sortify(tag_sort_key.lower())
+ tag.save()
+ meta_tags.append(tag)
+ return meta_tags
+
+
+
+def get_dynamic_path(media, filename, ext=None, maxlen=100):
+ from slughifi import slughifi
+
+ # how to put related book's slug here?
+ if not ext:
+ # BookMedia case
+ ext = media.formats[media.type].ext
+ if media is None or not media.name:
+ name = slughifi(filename.split(".")[0])
+ else:
+ name = slughifi(media.name)
+ return 'book/%s/%s.%s' % (ext, name[:maxlen-len('book/%s/.%s' % (ext, ext))-4], ext)
+
# TODO: why is this hard-coded ?
def book_upload_path(ext=None, maxlen=100):
- def get_dynamic_path(media, filename, ext=ext):
- from slughifi import slughifi
+ return lambda *args: get_dynamic_path(*args, ext=ext, maxlen=maxlen)
- # how to put related book's slug here?
- if not ext:
- if media.type == 'daisy':
- ext = 'daisy.zip'
- else:
- ext = media.type
- if not media.name:
- name = slughifi(filename.split(".")[0])
- else:
- name = slughifi(media.name)
- return 'book/%s/%s.%s' % (ext, name[:maxlen-len('book/%s/.%s' % (ext, ext))-4], ext)
- return get_dynamic_path
+
+def get_customized_pdf_path(book, customizations):
+ """
+ Returns a MEDIA_ROOT relative path for a customized pdf. The name will contain a hash of customization options.
+ """
+ customizations.sort()
+ h = hash(tuple(customizations))
+
+ pdf_name = '%s-custom-%s' % (book.slug, h)
+ pdf_file = get_dynamic_path(None, pdf_name, ext='pdf')
+
+ return pdf_file
+
+
+def get_existing_customized_pdf(book):
+ """
+ Returns a list of paths to generated customized pdf of a book
+ """
+ pdf_glob = '%s-custom-' % (book.slug,)
+ pdf_glob = get_dynamic_path(None, pdf_glob, ext='pdf')
+ pdf_glob = re.sub(r"[.]([a-z0-9]+)$", "*.\\1", pdf_glob)
+ return glob(path.join(settings.MEDIA_ROOT, pdf_glob))
class BookMedia(models.Model):
- type = models.CharField(_('type'), choices=MEDIA_FORMATS, max_length="100")
+ FileFormat = namedtuple("FileFormat", "name ext")
+ formats = SortedDict([
+ ('mp3', FileFormat(name='MP3', ext='mp3')),
+ ('ogg', FileFormat(name='Ogg Vorbis', ext='ogg')),
+ ('daisy', FileFormat(name='DAISY', ext='daisy.zip')),
+ ])
+ format_choices = [(k, _('%s file') % t.name)
+ for k, t in formats.items()]
+
+ type = models.CharField(_('type'), choices=format_choices, max_length="100")
name = models.CharField(_('name'), max_length="100")
file = OverwritingFileField(_('file'), upload_to=book_upload_path())
uploaded_at = models.DateTimeField(_('creation date'), auto_now_add=True, editable=False)
try:
old = BookMedia.objects.get(pk=self.pk)
except BookMedia.DoesNotExist, e:
- pass
+ old = None
else:
# if name changed, change the file name, too
if slughifi(self.name) != slughifi(old.name):
super(BookMedia, self).save(*args, **kwargs)
# remove the zip package for book with modified media
- remove_zip(self.book.slug)
+ if old:
+ remove_zip("%s_%s" % (old.book.slug, old.type))
+ remove_zip("%s_%s" % (self.book.slug, self.type))
extra_info = self.get_extra_info_value()
extra_info.update(self.read_meta())
class Book(models.Model):
title = models.CharField(_('title'), max_length=120)
sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False)
- slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
+ slug = models.SlugField(_('slug'), max_length=120, db_index=True,
+ unique=True)
+ common_slug = models.SlugField(_('slug'), max_length=120, db_index=True)
+ language = models.CharField(_('language code'), max_length=3, db_index=True,
+ default=settings.CATALOGUE_DEFAULT_LANGUAGE)
description = models.TextField(_('description'), blank=True)
created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
wiki_link = models.CharField(blank=True, max_length=240)
# files generated during publication
- file_types = ['epub', 'html', 'mobi', 'pdf', 'txt', 'xml']
-
+ cover = models.FileField(_('cover'), upload_to=book_upload_path('png'),
+ null=True, blank=True)
+ ebook_formats = ['pdf', 'epub', 'mobi', 'txt']
+ formats = ebook_formats + ['html', 'xml']
+
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
objects = models.Manager()
tagged = managers.ModelTaggedItemManager(Tag)
return book_tag
def has_media(self, type):
- if type in Book.file_types:
+ if type in Book.formats:
return bool(getattr(self, "%s_file" % type))
else:
return self.media.filter(type=type).exists()
def get_media(self, type):
if self.has_media(type):
- if type in Book.file_types:
+ if type in Book.formats:
return getattr(self, "%s_file" % type)
else:
return self.media.filter(type=type)
cache_key = "Book.short_html/%d/%s"
for lang, langname in settings.LANGUAGES:
cache.delete(cache_key % (self.id, lang))
+ cache.delete("Book.mini_box/%d" % (self.id, ))
# Fragment.short_html relies on book's tags, so reset it here too
for fragm in self.fragments.all():
fragm.reset_short_html()
if short_html is not None:
return mark_safe(short_html)
else:
- tags = self.tags.filter(~Q(category__in=('set', 'theme', 'book')))
- tags = [mark_safe(u'<a href="%s">%s</a>' % (tag.get_absolute_url(), tag.name)) for tag in tags]
+ tags = self.tags.filter(category__in=('author', 'kind', 'genre', 'epoch'))
+ tags = split_tags(tags)
- formats = []
+ formats = {}
# files generated during publication
- if self.has_media("html"):
- formats.append(u'<a href="%s">%s</a>' % (reverse('book_text', kwargs={'slug': self.slug}), _('Read online')))
- if self.has_media("pdf"):
- formats.append(u'<a href="%s">PDF</a>' % self.get_media('pdf').url)
- if self.has_media("mobi"):
- formats.append(u'<a href="%s">MOBI</a>' % self.get_media('mobi').url)
- if self.root_ancestor.has_media("epub"):
- formats.append(u'<a href="%s">EPUB</a>' % self.root_ancestor.get_media('epub').url)
- if self.has_media("txt"):
- formats.append(u'<a href="%s">TXT</a>' % self.get_media('txt').url)
- # other files
- for m in self.media.order_by('type'):
- formats.append(u'<a href="%s">%s</a>' % (m.file.url, m.type.upper()))
-
- formats = [mark_safe(format) for format in formats]
+ for ebook_format in self.ebook_formats:
+ if self.has_media(ebook_format):
+ formats[ebook_format] = self.get_media(ebook_format)
+
short_html = unicode(render_to_string('catalogue/book_short.html',
{'book': self, 'tags': tags, 'formats': formats}))
cache.set(cache_key, short_html, CACHE_FOREVER)
return mark_safe(short_html)
- @property
- def root_ancestor(self):
- """ returns the oldest ancestor """
+ def mini_box(self):
+ if self.id:
+ cache_key = "Book.mini_box/%d" % (self.id, )
+ short_html = cache.get(cache_key)
+ else:
+ short_html = None
- if not hasattr(self, '_root_ancestor'):
- book = self
- while book.parent:
- book = book.parent
- self._root_ancestor = book
- return self._root_ancestor
+ if short_html is None:
+ authors = self.tags.filter(category='author')
+ short_html = unicode(render_to_string('catalogue/book_mini_box.html',
+ {'book': self, 'authors': authors, 'STATIC_URL': settings.STATIC_URL}))
+
+ if self.id:
+ cache.set(cache_key, short_html, CACHE_FOREVER)
+ return mark_safe(short_html)
def has_description(self):
return len(self.description) > 0
has_description.boolean = True
# ugly ugly ugly
- def has_odt_file(self):
- return bool(self.has_media("odt"))
- has_odt_file.short_description = 'ODT'
- has_odt_file.boolean = True
-
def has_mp3_file(self):
return bool(self.has_media("mp3"))
has_mp3_file.short_description = 'MP3'
has_daisy_file.short_description = 'DAISY'
has_daisy_file.boolean = True
- def build_pdf(self):
- """ (Re)builds the pdf file.
+ def wldocument(self, parse_dublincore=True):
+ from catalogue.import_utils import ORMDocProvider
+ from librarian.parser import WLDocument
+
+ return WLDocument.from_file(self.xml_file.path,
+ provider=ORMDocProvider(self),
+ parse_dublincore=parse_dublincore)
+
+ def build_cover(self, book_info=None):
+ """(Re)builds the cover image."""
+ from StringIO import StringIO
+ from django.core.files.base import ContentFile
+ from librarian.cover import WLCover
+
+ if book_info is None:
+ book_info = self.wldocument().book_info
+ cover = WLCover(book_info).image()
+ imgstr = StringIO()
+ cover.save(imgstr, 'png')
+ self.cover.save(None, ContentFile(imgstr.getvalue()))
+
+ def build_pdf(self, customizations=None, file_name=None):
+ """ (Re)builds the pdf file.
+ customizations - customizations which are passed to LaTeX class file.
+ file_name - save the pdf file under a different name and DO NOT save it in db.
"""
- from tempfile import NamedTemporaryFile
from os import unlink
from django.core.files import File
- from librarian import pdf
- from catalogue.utils import ORMDocProvider, remove_zip
+ from catalogue.utils import remove_zip
- try:
- pdf_file = NamedTemporaryFile(delete=False)
- pdf.transform(ORMDocProvider(self),
- file_path=str(self.xml_file.path),
- output_file=pdf_file,
- )
+ pdf = self.wldocument().as_pdf(customizations=customizations)
- self.pdf_file.save('%s.pdf' % self.slug, File(open(pdf_file.name)))
- finally:
- unlink(pdf_file.name)
+ if file_name is None:
+ # we'd like to be sure not to overwrite changes happening while
+ # (timely) pdf generation is taking place (async celery scenario)
+ current_self = Book.objects.get(id=self.id)
+ current_self.pdf_file.save('%s.pdf' % self.slug,
+ File(open(pdf.get_filename())))
+ self.pdf_file = current_self.pdf_file
- # remove zip with all pdf files
- remove_zip(settings.ALL_PDF_ZIP)
+ # remove cached downloadables
+ remove_zip(settings.ALL_PDF_ZIP)
+
+ for customized_pdf in get_existing_customized_pdf(self):
+ unlink(customized_pdf)
+ else:
+ print "saving %s" % file_name
+ print "to: %s" % DefaultStorage().path(file_name)
+ DefaultStorage().save(file_name, File(open(pdf.get_filename())))
def build_mobi(self):
""" (Re)builds the MOBI file.
"""
- from tempfile import NamedTemporaryFile
- from os import unlink
from django.core.files import File
- from librarian import mobi
- from catalogue.utils import ORMDocProvider, remove_zip
+ from catalogue.utils import remove_zip
- try:
- mobi_file = NamedTemporaryFile(suffix='.mobi', delete=False)
- mobi.transform(ORMDocProvider(self), verbose=1,
- file_path=str(self.xml_file.path),
- output_file=mobi_file.name,
- )
+ mobi = self.wldocument().as_mobi()
- self.mobi_file.save('%s.mobi' % self.slug, File(open(mobi_file.name)))
- finally:
- unlink(mobi_file.name)
+ self.mobi_file.save('%s.mobi' % self.slug, File(open(mobi.get_filename())))
# remove zip with all mobi files
remove_zip(settings.ALL_MOBI_ZIP)
- def build_epub(self, remove_descendants=True):
- """ (Re)builds the epub file.
- If book has a parent, does nothing.
- Unless remove_descendants is False, descendants' epubs are removed.
- """
- from StringIO import StringIO
- from hashlib import sha1
- from django.core.files.base import ContentFile
- from librarian import epub, NoDublinCore
- from catalogue.utils import ORMDocProvider, remove_zip
-
- if self.parent:
- # don't need an epub
- return
+ def build_epub(self):
+ """(Re)builds the epub file."""
+ from django.core.files import File
+ from catalogue.utils import remove_zip
- epub_file = StringIO()
- try:
- epub.transform(ORMDocProvider(self), self.slug, output_file=epub_file)
- self.epub_file.save('%s.epub' % self.slug, ContentFile(epub_file.getvalue()))
- FileRecord(slug=self.slug, type='epub', sha1=sha1(epub_file.getvalue()).hexdigest()).save()
- except NoDublinCore:
- pass
+ epub = self.wldocument().as_epub()
- book_descendants = list(self.children.all())
- while len(book_descendants) > 0:
- child_book = book_descendants.pop(0)
- if remove_descendants and child_book.has_epub_file():
- child_book.epub_file.delete()
- # save anyway, to refresh short_html
- child_book.save()
- book_descendants += list(child_book.children.all())
+ self.epub_file.save('%s.epub' % self.slug,
+ File(open(epub.get_filename())))
# remove zip package with all epub files
remove_zip(settings.ALL_EPUB_ZIP)
def build_txt(self):
- from StringIO import StringIO
from django.core.files.base import ContentFile
- from librarian import text
- out = StringIO()
- text.transform(open(self.xml_file.path), out)
- self.txt_file.save('%s.txt' % self.slug, ContentFile(out.getvalue()))
+ text = self.wldocument().as_text()
+ self.txt_file.save('%s.txt' % self.slug, ContentFile(text.get_string()))
def build_html(self):
- from tempfile import NamedTemporaryFile
from markupstring import MarkupString
- from django.core.files import File
+ from django.core.files.base import ContentFile
from slughifi import slughifi
from librarian import html
category__in=('author', 'epoch', 'genre', 'kind')))
book_tag = self.book_tag()
- html_file = NamedTemporaryFile()
- if html.transform(self.xml_file.path, html_file, parse_dublincore=False):
- self.html_file.save('%s.html' % self.slug, File(html_file))
+ html_output = self.wldocument(parse_dublincore=False).as_html()
+ if html_output:
+ self.html_file.save('%s.html' % self.slug,
+ ContentFile(html_output.get_string()))
# get ancestor l-tags for adding to new fragments
ancestor_tags = []
getattr(settings, "ALL_%s_ZIP" % format_.upper()))
return result.wait()
- def zip_audiobooks(self):
- bm = BookMedia.objects.filter(book=self, type='mp3')
+ def zip_audiobooks(self, format_):
+ bm = BookMedia.objects.filter(book=self, type=format_)
paths = map(lambda bm: (None, bm.file.path), bm)
- result = create_zip.delay(paths, self.slug)
+ result = create_zip.delay(paths, "%s_%s" % (self.slug, format_))
return result.wait()
+ def search_index(self, book_info=None, reuse_index=False):
+ if reuse_index:
+ idx = search.ReusableIndex()
+ else:
+ idx = search.Index()
+
+ idx.open()
+ try:
+ idx.index_book(self, book_info)
+ idx.index_tags()
+ finally:
+ idx.close()
+
@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,
- build_epub=True, build_txt=True, build_pdf=True, build_mobi=True):
+ build_epub=True, build_txt=True, build_pdf=True, build_mobi=True,
+ search_index=True):
import re
- from slughifi import slughifi
from sortify import sortify
# check for parts before we do anything
children = []
if hasattr(book_info, 'parts'):
for part_url in book_info.parts:
- base, slug = part_url.rsplit('/', 1)
try:
- children.append(Book.objects.get(slug=slug))
+ children.append(Book.objects.get(slug=part_url.slug))
except Book.DoesNotExist, e:
- raise Book.DoesNotExist(_('Book with slug = "%s" does not exist.') % slug)
+ raise Book.DoesNotExist(_('Book "%s" does not exist.') %
+ part_url.slug)
# Read book metadata
- book_base, book_slug = book_info.url.rsplit('/', 1)
- if re.search(r'[^a-zA-Z0-9-]', book_slug):
+ book_slug = book_info.url.slug
+ if re.search(r'[^a-z0-9-]', book_slug):
raise ValueError('Invalid characters in slug')
book, created = Book.objects.get_or_create(slug=book_slug)
book_shelves = []
else:
if not overwrite:
- raise Book.AlreadyExists(_('Book %s already exists') % book_slug)
+ raise Book.AlreadyExists(_('Book %s already exists') % (
+ book_slug))
# Save shelves for this book
book_shelves = list(book.tags.filter(category='set'))
+ book.language = book_info.language
book.title = book_info.title
+ if book_info.variant_of:
+ book.common_slug = book_info.variant_of.slug
+ else:
+ book.common_slug = book.slug
book.set_extra_info_value(book_info.to_dict())
book.save()
- meta_tags = []
- categories = (('kinds', 'kind'), ('genres', 'genre'), ('authors', 'author'), ('epochs', 'epoch'))
- for field_name, category in categories:
- try:
- tag_names = getattr(book_info, field_name)
- except:
- tag_names = [getattr(book_info, category)]
- for tag_name in tag_names:
- tag_sort_key = tag_name
- if category == 'author':
- tag_sort_key = tag_name.last_name
- tag_name = ' '.join(tag_name.first_names) + ' ' + tag_name.last_name
- tag, created = Tag.objects.get_or_create(slug=slughifi(tag_name), category=category)
- if created:
- tag.name = tag_name
- tag.sort_key = sortify(tag_sort_key.lower())
- tag.save()
- meta_tags.append(tag)
+ meta_tags = Tag.tags_from_info(book_info)
book.tags = set(meta_tags + book_shelves)
if not settings.NO_BUILD_TXT and build_txt:
book.build_txt()
+ book.build_cover(book_info)
+
if not settings.NO_BUILD_EPUB and build_epub:
- book.root_ancestor.build_epub()
+ book.build_epub()
if not settings.NO_BUILD_PDF and build_pdf:
- book.root_ancestor.build_pdf()
+ book.build_pdf()
if not settings.NO_BUILD_MOBI and build_mobi:
book.build_mobi()
+ if not settings.NO_SEARCH_INDEX and search_index:
+ index_book.delay(book.id, book_info)
+
book_descendants = list(book.children.all())
+ descendants_tags = set()
# add l-tag to descendants and their fragments
- # delete unnecessary EPUB files
while len(book_descendants) > 0:
child_book = book_descendants.pop(0)
+ descendants_tags.update(child_book.tags)
child_book.tags = list(child_book.tags) + [book_tag]
child_book.save()
for fragment in child_book.fragments.all():
fragment.tags = set(list(fragment.tags) + [book_tag])
book_descendants += list(child_book.children.all())
+ for tag in descendants_tags:
+ touch_tag.delay(tag)
+
book.save()
# refresh cache
"""
books_by_parent = {}
- books = cls.objects.all().order_by('parent_number', 'sort_key').only('title', 'parent', 'slug')
+ books = cls.objects.all().order_by('parent_number', 'sort_key').only(
+ 'title', 'parent', 'slug')
if filter:
books = books.filter(filter).distinct()
book_ids = set((book.pk for book in books))
return books_by_author, orphans, books_by_parent
+ _audiences_pl = {
+ "SP1": (1, u"szkoła podstawowa"),
+ "SP2": (1, u"szkoła podstawowa"),
+ "P": (1, u"szkoła podstawowa"),
+ "G": (2, u"gimnazjum"),
+ "L": (3, u"liceum"),
+ "LP": (3, u"liceum"),
+ }
+ def audiences_pl(self):
+ audiences = self.get_extra_info_value().get('audiences', [])
+ audiences = sorted(set([self._audiences_pl[a] for a in audiences]))
+ return [a[1] for a in audiences]
+
def _has_factory(ftype):
has = lambda self: bool(getattr(self, "%s_file" % ftype))
# add the file fields
-for t in Book.file_types:
+for t in Book.formats:
field_name = "%s_file" % t
models.FileField(_("%s file" % t.upper()),
upload_to=book_upload_path(t),
verbose_name_plural = _('fragments')
def get_absolute_url(self):
- return '%s#m%s' % (reverse('book_text', kwargs={'slug': self.book.slug}), self.anchor)
+ return '%s#m%s' % (reverse('book_text', args=[self.book.slug]), self.anchor)
def reset_short_html(self):
if self.id is None:
return mark_safe(short_html)
-class FileRecord(models.Model):
- slug = models.SlugField(_('slug'), max_length=120, db_index=True)
- type = models.CharField(_('type'), max_length=20, db_index=True)
- sha1 = models.CharField(_('sha-1 hash'), max_length=40)
- time = models.DateTimeField(_('time'), auto_now_add=True)
-
- class Meta:
- ordering = ('-time','-slug', '-type')
- verbose_name = _('file record')
- verbose_name_plural = _('file records')
-
- def __unicode__(self):
- return "%s %s.%s" % (self.sha1, self.slug, self.type)
-
-
class Collection(models.Model):
"""A collection of books, which might be defined before publishing them."""
title = models.CharField(_('title'), max_length=120, db_index=True)
def _tags_updated_handler(sender, affected_tags, **kwargs):
# reset tag global counter
# we want Tag.changed_at updated for API to know the tag was touched
- Tag.objects.filter(pk__in=[tag.pk for tag in affected_tags]).update(book_count=None, changed_at=datetime.now())
+ for tag in affected_tags:
+ touch_tag.delay(tag)
# if book tags changed, reset book tag counter
if isinstance(sender, Book) and \
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from datetime import datetime
+from celery.task import task
+import catalogue.models
+
+@task
+def touch_tag(tag):
+ update_dict = {
+ 'book_count': tag.get_count(),
+ 'changed_at': datetime.now(),
+ }
+
+ type(tag).objects.filter(pk=tag.pk).update(**update_dict)
+
+
+@task
+def index_book(book_id, book_info=None):
+ return catalogue.models.Book.objects.get(id=book_id).search_index(book_info)
from django.utils.translation import ugettext as _
from catalogue.forms import SearchForm
+from catalogue.utils import split_tags
register = template.Library()
def book_tree_texml(book_list, books_by_parent, depth=1):
return "".join("""
<cmd name='hspace'><parm>%(depth)dem</parm></cmd>%(title)s
+ <spec cat='align' /><cmd name="note"><parm>%(audiences)s</parm></cmd>
<spec cat='align' /><cmd name="note"><parm>%(audiobook)s</parm></cmd>
<ctrl ch='\\' />
%(children)s
""" % {
"depth": depth,
"title": book.title,
+ "audiences": ", ".join(book.audiences_pl()),
"audiobook": "audiobook" if book.has_media('mp3') else "",
"children": book_tree_texml(books_by_parent.get(book.id, ()), books_by_parent, depth + 1)
} for book in book_list)
return LoginForm(prefix='login').as_ul()
-@register.inclusion_tag('catalogue/search_form.html')
-def search_form():
- return {"form": SearchForm()}
-
-@register.inclusion_tag('catalogue/breadcrumbs.html')
-def breadcrumbs(tags, search_form=True):
- context = {'tag_list': tags}
- try:
- max_tag_list = settings.MAX_TAG_LIST
- except AttributeError:
- max_tag_list = -1
- if search_form and (max_tag_list == -1 or len(tags) < max_tag_list):
- context['search_form'] = SearchForm(tags=tags)
- return context
-
-
@register.tag
def catalogue_url(parser, token):
bits = token.split_contents()
one_tag = tags[0]
return locals()
-
-@register.inclusion_tag('catalogue/folded_tag_list.html')
-def folded_tag_list(tags, title='', choices=None):
- tags = [tag for tag in tags if tag.count]
+@register.inclusion_tag('catalogue/inline_tag_list.html')
+def inline_tag_list(tags, choices=None):
if choices is None:
choices = []
- some_tags_hidden = False
- tag_count = len(tags)
-
- if tag_count == 1:
+ if len(tags) == 1:
one_tag = tags[0]
- else:
- shown_tags = [tag for tag in tags if tag.main_page]
- if tag_count > len(shown_tags):
- some_tags_hidden = True
return locals()
@register.inclusion_tag('catalogue/book_info.html')
def book_info(book):
return locals()
+
+
+@register.inclusion_tag('catalogue/book_wide.html')
+def book_wide(book):
+ tags = book.tags.filter(category__in=('author', 'kind', 'genre', 'epoch'))
+ tags = split_tags(tags)
+
+ formats = {}
+ # files generated during publication
+ for ebook_format in book.ebook_formats:
+ if book.has_media(ebook_format):
+ formats[ebook_format] = book.get_media(ebook_format)
+
+ extra_info = book.get_extra_info_value()
+
+ has_media = {}
+ for media_format in ['mp3', 'ogg']:
+ has_media[media_format] = book.has_media(media_format)
+
+ return locals()
import shutil
import tempfile
from slughifi import slughifi
+from librarian import WLURI
class WLTestCase(TestCase):
"""
self._MEDIA_ROOT, settings.MEDIA_ROOT = settings.MEDIA_ROOT, tempfile.mkdtemp(prefix='djangotest_')
settings.NO_BUILD_PDF = settings.NO_BUILD_MOBI = settings.NO_BUILD_EPUB = settings.NO_BUILD_TXT = True
settings.CELERY_ALWAYS_EAGER = True
+ self._CACHE_BACKEND, settings.CACHE_BACKEND = settings.CACHE_BACKEND, 'dummy://'
def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT, True)
settings.MEDIA_ROOT = self._MEDIA_ROOT
+ settings.CACHE_BACKEND = self._CACHE_BACKEND
class PersonStub(object):
self.first_names = first_names
self.last_name = last_name
+ def readable(self):
+ return " ".join(self.first_names + (self.last_name,))
+
class BookInfoStub(object):
+ _empty_fields = ['cover_url', 'variant_of']
+ # allow single definition for multiple-value fields
+ _salias = {
+ 'authors': 'author',
+ }
def __init__(self, **kwargs):
self.__dict = kwargs
return object.__setattr__(self, key, value)
def __getattr__(self, key):
- return self.__dict[key]
+ try:
+ return self.__dict[key]
+ except KeyError:
+ if key in self._empty_fields:
+ return None
+ elif key in self._salias:
+ return [getattr(self, self._salias[key])]
+ else:
+ raise
def to_dict(self):
return dict((key, unicode(value)) for key, value in self.__dict.items())
-def info_args(title):
+def info_args(title, language=None):
""" generate some keywords for comfortable BookInfoCreation """
slug = unicode(slughifi(title))
+ if language is None:
+ language = u'pol'
return {
'title': unicode(title),
- 'slug': slug,
- 'url': u"http://wolnelektury.pl/example/%s" % slug,
+ 'url': WLURI.from_slug(slug),
'about': u"http://wolnelektury.pl/example/URI/%s" % slug,
+ 'language': language,
}
from django.core.files.base import ContentFile, File
from catalogue.test_utils import *
from catalogue import models
+from librarian import WLURI
from nose.tools import raises
import tempfile
-from os import unlink,path
+from os import unlink, path, makedirs
class BookImportLogicTests(WLTestCase):
def setUp(self):
WLTestCase.setUp(self)
self.book_info = BookInfoStub(
- url=u"http://wolnelektury.pl/example/default-book",
+ url=WLURI.from_slug(u"default-book"),
about=u"http://wolnelektury.pl/example/URI/default_book",
title=u"Default Book",
author=PersonStub(("Jim",), "Lazy"),
kind="X-Kind",
genre="X-Genre",
epoch="X-Epoch",
+ language=u"pol",
)
self.expected_tags = [
@raises(ValueError)
def test_book_with_invalid_slug(self):
""" Book with invalid characters in slug shouldn't be imported """
- self.book_info.url = "http://wolnelektury.pl/example/default_book"
+ self.book_info.url = WLURI.from_slug(u"default_book")
BOOK_TEXT = "<utwor />"
book = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.book_info)
'wrong related theme list')
+class MultilingualBookImportTest(WLTestCase):
+ def setUp(self):
+ WLTestCase.setUp(self)
+ common_uri = WLURI.from_slug('common-slug')
+
+ self.pol_info = BookInfoStub(
+ genre='X-Genre',
+ epoch='X-Epoch',
+ kind='X-Kind',
+ author=PersonStub(("Joe",), "Doe"),
+ variant_of=common_uri,
+ **info_args(u"Książka")
+ )
+
+ self.eng_info = BookInfoStub(
+ genre='X-Genre',
+ epoch='X-Epoch',
+ kind='X-Kind',
+ author=PersonStub(("Joe",), "Doe"),
+ variant_of=common_uri,
+ **info_args("A book", "eng")
+ )
+
+ def test_multilingual_import(self):
+ BOOK_TEXT = """<utwor><opowiadanie><akap>A</akap></opowiadanie></utwor>"""
+
+ book1 = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.pol_info)
+ book2 = models.Book.from_text_and_meta(ContentFile(BOOK_TEXT), self.eng_info)
+
+ self.assertEqual(
+ set([b.language for b in models.Book.objects.all()]),
+ set(['pol', 'eng']),
+ 'Books imported in wrong languages.'
+ )
+
+
class BookImportGenerateTest(WLTestCase):
def setUp(self):
WLTestCase.setUp(self)
parent = models.Book.from_xml_file(input)
parent.build_pdf()
self.assertTrue(path.exists(parent.pdf_file.path))
+
+ def test_custom_pdf(self):
+ out = models.get_dynamic_path(None, 'test-custom', ext='pdf')
+ absoulute_path = path.join(settings.MEDIA_ROOT, out)
+
+ if not path.exists(path.dirname(absoulute_path)):
+ makedirs(path.dirname(absoulute_path))
+
+ self.book.build_pdf(customizations=['nofootnotes', '13pt', 'a4paper'], file_name=out)
+ self.assertTrue(path.exists(absoulute_path))
bm.file.save(None, self.file)
bm.save()
- zip_url = self.book.zip_audiobooks()
- self.assertEqual('zip/'+self.book.slug+'.zip', zip_url)
+ zip_url = self.book.zip_audiobooks('ogg')
+ self.assertEqual('zip/'+self.book.slug+'_ogg.zip', zip_url)
self.assertTrue(exists(join(settings.MEDIA_ROOT, zip_url)))
bm2 = models.BookMedia(book=self.book, type='ogg', name="Other title")
<dc:subject.genre xml:lang="pl">Fraszka</dc:subject.genre>
<dc:description xml:lang="pl"></dc:description>
-<dc:identifier.url xml:lang="pl">http://wolnelektury.pl/lektura/fraszki</dc:identifier.url>
+<dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/fraszki</dc:identifier.url>
<dc:source xml:lang="pl"></dc:source>
<dc:rights xml:lang="pl">Domena publiczna - Jan Kochanowski zm. 1584</dc:rights>
<dc:date.pd xml:lang="pl">1584</dc:date.pd>
from catalogue.test_utils import *
from django.core.files.base import ContentFile
-from nose.tools import raises
-
-
class BooksByTagTests(WLTestCase):
""" tests the /katalog/category/tag page for found books """
['Child'])
-
+from django.test import Client
class TagRelatedTagsTests(WLTestCase):
""" tests the /katalog/category/tag/ page for related tags """
def setUp(self):
WLTestCase.setUp(self)
+ self.client = Client()
author = PersonStub(("Common",), "Man")
gchild_info = BookInfoStub(author=author, genre="GchildGenre", epoch='Epoch', kind="Kind",
def test_related_differ(self):
""" related tags shouldn't include filtering tags """
- cats = self.client.get('/katalog/rodzaj/kind/').context['categories']
+ response = self.client.get('/katalog/rodzaj/kind/')
+ cats = response.context['categories']
self.assertFalse('Kind' in [tag.name for tag in cats['kind']],
'filtering tag wrongly included in related')
cats = self.client.get('/katalog/motyw/theme/').context['categories']
self.assertFalse('Theme' in [tag.name for tag in cats['theme']],
'filtering theme wrongly included in related')
-
def test_parent_tag_once(self):
""" if parent and descendants have a common tag, count it only once """
#
from django.conf.urls.defaults import *
from catalogue.feeds import AudiobookFeed
+from catalogue.models import Book
+from picture.models import Picture
+from catalogue.views import CustomPDFFormView
-urlpatterns = patterns('catalogue.views',
- url(r'^$', 'main_page', name='main_page'),
+SLUG = r'[a-z0-9-]*'
+
+urlpatterns = patterns('picture.views',
+ # pictures - currently pictures are coupled with catalogue, hence the url is here
+ url(r'^obraz/?$', 'picture_list'),
+ url(r'^obraz/(?P<picture>%s)/?$' % SLUG, 'picture_detail')
+ ) + \
+ patterns('catalogue.views',
+ url(r'^$', 'catalogue', name='catalogue'),
url(r'^polki/(?P<shelf>[a-zA-Z0-9-]+)/formaty/$', 'shelf_book_formats', name='shelf_book_formats'),
- url(r'^polki/(?P<shelf>[a-zA-Z0-9-]+)/(?P<book>[a-zA-Z0-9-0-]+)/usun$', 'remove_from_shelf', name='remove_from_shelf'),
+ url(r'^polki/(?P<shelf>[a-zA-Z0-9-]+)/(?P<slug>%s)/usun$' % SLUG, 'remove_from_shelf', name='remove_from_shelf'),
url(r'^polki/$', 'user_shelves', name='user_shelves'),
url(r'^polki/(?P<slug>[a-zA-Z0-9-]+)/usun/$', 'delete_shelf', name='delete_shelf'),
url(r'^polki/(?P<slug>[a-zA-Z0-9-]+)\.zip$', 'download_shelf', name='download_shelf'),
url(r'^lektury/(?P<slug>[a-zA-Z0-9-]+)/$', 'collection', name='collection'),
url(r'^audiobooki/$', 'audiobook_list', name='audiobook_list'),
url(r'^daisy/$', 'daisy_list', name='daisy_list'),
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/polki/', 'book_sets', name='book_shelves'),
+ url(r'^lektura/(?P<book>%s)/polki/' % SLUG, 'book_sets', name='book_shelves'),
url(r'^polki/nowa/$', 'new_set', name='new_set'),
url(r'^tags/$', 'tags_starting_with', name='hint'),
url(r'^jtags/$', 'json_tags_starting_with', name='jhint'),
- url(r'^szukaj/$', 'search', name='search'),
+ url(r'^szukaj/$', 'search', name='old_search'),
# zip
- #url(r'^zip/pdf\.zip$', 'download_zip', {'format': 'pdf', 'slug': None}, 'download_zip_pdf'),
- #url(r'^zip/epub\.zip$', 'download_zip', {'format': 'epub', 'slug': None}, 'download_zip_epub'),
- #url(r'^zip/mobi\.zip$', 'download_zip', {'format': 'mobi', 'slug': None}, 'download_zip_mobi'),
- #url(r'^zip/audiobook/(?P<slug>[a-zA-Z0-9-]+)\.zip', 'download_zip', {'format': 'audiobook'}, 'download_zip_audiobook'),
-
- # tools
- url(r'^zegar/$', 'clock', name='clock'),
+ url(r'^zip/pdf\.zip$', 'download_zip', {'format': 'pdf', 'slug': None}, 'download_zip_pdf'),
+ url(r'^zip/epub\.zip$', 'download_zip', {'format': 'epub', 'slug': None}, 'download_zip_epub'),
+ url(r'^zip/mobi\.zip$', 'download_zip', {'format': 'mobi', 'slug': None}, 'download_zip_mobi'),
+ url(r'^zip/mp3/(?P<slug>%s)\.zip' % SLUG, 'download_zip', {'format': 'mp3'}, 'download_zip_mp3'),
+ url(r'^zip/ogg/(?P<slug>%s)\.zip' % SLUG, 'download_zip', {'format': 'ogg'}, 'download_zip_ogg'),
# Public interface. Do not change this URLs.
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)\.html$', 'book_text', name='book_text'),
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/$', 'book_detail', name='book_detail'),
- url(r'^lektura/(?P<book_slug>[a-zA-Z0-9-]+)/motyw/(?P<theme_slug>[a-zA-Z0-9-]+)/$',
+ url(r'^lektura/(?P<slug>%s)\.html$' % SLUG, 'book_text', name='book_text'),
+ url(r'^lektura/(?P<slug>%s)/audiobook/$' % SLUG, 'player', name='book_player'),
+ url(r'^lektura/(?P<slug>%s)/$' % SLUG, 'book_detail', name='book_detail'),
+ url(r'^lektura/(?P<slug>%s)/motyw/(?P<theme_slug>[a-zA-Z0-9-]+)/$' % SLUG,
'book_fragments', name='book_fragments'),
url(r'^(?P<tags>[a-zA-Z0-9-/]*)/$', 'tagged_object_list', name='tagged_object_list'),
url(r'^audiobooki/(?P<type>mp3|ogg|daisy|all).xml$', AudiobookFeed(), name='audiobook_feed'),
-)
+ url(r'^custompdf$', CustomPDFFormView(), name='custom_pdf_form'),
+ url(r'^custompdf/(?P<slug>%s).pdf' % SLUG, 'download_custom_pdf'),
+
+)
import time
from base64 import urlsafe_b64encode
+from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponsePermanentRedirect
from django.core.files.uploadedfile import UploadedFile
+from django.core.files.base import File
+from django.core.files.storage import DefaultStorage
from django.utils.hashcompat import sha_constructor
from django.conf import settings
from celery.task import task
from fcntl import flock, LOCK_EX
from zipfile import ZipFile
-from librarian import DocProvider
-
+from reporting.utils import read_chunks
+from celery.task import task
+import catalogue.models
# Use the system (hardware-based) random number generator if it exists.
if hasattr(random, 'SystemRandom'):
pass
-class ORMDocProvider(DocProvider):
- """Used for getting books' children."""
-
- def __init__(self, book):
- self.book = book
-
- def by_slug(self, slug):
- if slug == self.book.slug:
- return self.book.xml_file
- else:
- return type(self.book).objects.get(slug=slug).xml_file
-
-
class LockFile(object):
"""
A file lock monitor class; createas an ${objname}.lock
except OSError as oe:
if oe.errno != ENOENT:
raise oe
+
+
+class AttachmentHttpResponse(HttpResponse):
+ """Response serving a file to be downloaded.
+ """
+ def __init__ (self, file_path, file_name, mimetype):
+ super(AttachmentHttpResponse, self).__init__(mimetype=mimetype)
+ self['Content-Disposition'] = 'attachment; filename=%s' % file_name
+ self.file_path = file_path
+ self.file_name = file_name
+
+ with open(DefaultStorage().path(self.file_path)) as f:
+ for chunk in read_chunks(f):
+ self.write(chunk)
+
+@task
+def async_build_pdf(book_id, customizations, file_name):
+ """
+ A celery task to generate pdf files.
+ Accepts the same args as Book.build_pdf, but with book id as first parameter
+ instead of Book instance
+ """
+ book = catalogue.models.Book.objects.get(id=book_id)
+ print "will gen %s" % DefaultStorage().path(file_name)
+ if not DefaultStorage().exists(file_name):
+ book.build_pdf(customizations=customizations, file_name=file_name)
+ print "done."
+
+
+class MultiQuerySet(object):
+ def __init__(self, *args, **kwargs):
+ self.querysets = args
+ self._count = None
+
+ def count(self):
+ if not self._count:
+ self._count = sum(len(qs) for qs in self.querysets)
+ return self._count
+
+ def __len__(self):
+ return self.count()
+
+ def __getitem__(self, item):
+ try:
+ indices = (offset, stop, step) = item.indices(self.count())
+ except AttributeError:
+ # it's not a slice - make it one
+ return self[item : item + 1][0]
+ items = []
+ total_len = stop - offset
+ for qs in self.querysets:
+ if len(qs) < offset:
+ offset -= len(qs)
+ else:
+ items += list(qs[offset:stop])
+ if len(items) >= total_len:
+ return items
+ else:
+ offset = 0
+ stop = total_len - len(items)
+ continue
\ No newline at end of file
from django.views.decorators.http import require_POST
from django.contrib import auth
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
-from django.utils import simplejson
-from django.utils.functional import Promise
-from django.utils.encoding import force_unicode
from django.utils.http import urlquote_plus
from django.views.decorators import cache
from django.utils import translation
from django.utils.translation import ugettext as _
from django.views.generic.list_detail import object_list
+from ajaxable.utils import LazyEncoder, JSONResponse, AjaxableFormView
+
from catalogue import models
from catalogue import forms
-from catalogue.utils import split_tags
+from catalogue.utils import (split_tags, AttachmentHttpResponse,
+ async_build_pdf, MultiQuerySet)
+from catalogue.tasks import touch_tag
from pdcounter import models as pdcounter_models
from pdcounter import views as pdcounter_views
from suggest.forms import PublishingSuggestForm
+from picture.models import Picture
+from os import path
staff_required = user_passes_test(lambda user: user.is_staff)
-class LazyEncoder(simplejson.JSONEncoder):
- def default(self, obj):
- if isinstance(obj, Promise):
- return force_unicode(obj)
- return obj
-
-# shortcut for JSON reponses
-class JSONResponse(HttpResponse):
- def __init__(self, data={}, callback=None, **kwargs):
- # get rid of mimetype
- kwargs.pop('mimetype', None)
- data = simplejson.dumps(data)
- if callback:
- data = callback + "(" + data + ");"
- super(JSONResponse, self).__init__(data, mimetype="application/json", **kwargs)
-
-
-def main_page(request):
- if request.user.is_authenticated():
- shelves = models.Tag.objects.filter(category='set', user=request.user)
- new_set_form = forms.NewSetForm()
-
- tags = models.Tag.objects.exclude(category__in=('set', 'book'))
+def catalogue(request):
+ tags = models.Tag.objects.exclude(
+ category__in=('set', 'book')).exclude(book_count=0)
+ tags = list(tags)
for tag in tags:
- tag.count = tag.get_count()
+ tag.count = tag.book_count
categories = split_tags(tags)
fragment_tags = categories.get('theme', [])
- form = forms.SearchForm()
- return render_to_response('catalogue/main_page.html', locals(),
+ return render_to_response('catalogue/catalogue.html', locals(),
context_instance=RequestContext(request))
context=None):
""" generates a listing of all books, optionally filtered with a test function """
- form = forms.SearchForm()
-
books_by_author, orphans, books_by_parent = models.Book.book_list(filter)
books_nav = SortedDict()
for tag in books_by_author:
def tagged_object_list(request, tags=''):
+ # import pdb; pdb.set_trace()
try:
tags = models.Tag.get_tag_list(tags)
except models.Tag.DoesNotExist:
only_author = len(tags) == 1 and tags[0].category == 'author'
objects = models.Book.objects.none()
- return object_list(
- request,
- objects,
- template_name='catalogue/tagged_object_list.html',
- extra_context={
+ # Add pictures
+ objects = MultiQuerySet(Picture.tagged.with_all(tags), objects)
+
+ return render_to_response('catalogue/tagged_object_list.html',
+ {
+ 'object_list': objects,
'categories': categories,
'only_shelf': only_shelf,
'only_author': only_author,
'only_my_shelf': only_my_shelf,
'formats_form': forms.DownloadFormatsForm(),
'tags': tags,
- }
- )
+ },
+ context_instance=RequestContext(request))
-def book_fragments(request, book_slug, theme_slug):
- book = get_object_or_404(models.Book, slug=book_slug)
- book_tag = get_object_or_404(models.Tag, slug='l-' + book_slug, category='book')
+def book_fragments(request, slug, theme_slug):
+ book = get_object_or_404(models.Book, slug=slug)
+
+ book_tag = book.book_tag()
theme = get_object_or_404(models.Tag, slug=theme_slug, category='theme')
fragments = models.Fragment.tagged.with_all([book_tag, theme])
- form = forms.SearchForm()
return render_to_response('catalogue/book_fragments.html', locals(),
context_instance=RequestContext(request))
try:
book = models.Book.objects.get(slug=slug)
except models.Book.DoesNotExist:
- return pdcounter_views.book_stub_detail(request, slug)
+ return pdcounter_views.book_stub_detail(request, kwargs['slug'])
book_tag = book.book_tag()
tags = list(book.tags.filter(~Q(category='set')))
categories = split_tags(tags)
book_children = book.children.all().order_by('parent_number', 'sort_key')
-
+
_book = book
parents = []
while _book.parent:
extra_info = book.get_extra_info_value()
hide_about = extra_info.get('about', '').startswith('http://wiki.wolnepodreczniki.pl')
+ custom_pdf_form = forms.CustomPDFForm()
+ return render_to_response('catalogue/book_detail.html', locals(),
+ context_instance=RequestContext(request))
+
+
+def player(request, slug):
+ book = get_object_or_404(models.Book, slug=slug)
+ if not book.has_media('mp3'):
+ raise Http404
+
+ ogg_files = {}
+ for m in book.media.filter(type='ogg').order_by():
+ ogg_files[m.name] = m
+
+ audiobooks = []
+ have_oggs = True
projects = set()
- for m in book.media.filter(type='mp3'):
+ for mp3 in book.media.filter(type='mp3'):
# ogg files are always from the same project
- meta = m.get_extra_info_value()
+ meta = mp3.get_extra_info_value()
project = meta.get('project')
if not project:
# temporary fallback
project = u'CzytamySłuchając'
projects.add((project, meta.get('funded_by', '')))
+
+ media = {'mp3': mp3}
+
+ ogg = ogg_files.get(mp3.name)
+ if ogg:
+ media['ogg'] = ogg
+ else:
+ have_oggs = False
+ audiobooks.append(media)
+ print audiobooks
+
projects = sorted(projects)
- form = forms.SearchForm()
- return render_to_response('catalogue/book_detail.html', locals(),
+ return render_to_response('catalogue/player.html', locals(),
context_instance=RequestContext(request))
def book_text(request, slug):
book = get_object_or_404(models.Book, slug=slug)
+
if not book.has_html_file():
raise Http404
book_themes = {}
def find_best_matches(query, user=None):
- """ Finds a Book, Tag, BookStub or Author best matching a query.
+ """ Finds a models.Book, Tag, models.BookStub or Author best matching a query.
Returns a with:
- zero elements when nothing is found,
context_instance=RequestContext(request))
else:
form = PublishingSuggestForm(initial={"books": prefix + ", "})
- return render_to_response('catalogue/search_no_hits.html',
+ return render_to_response('catalogue/search_no_hits.html',
{'tags':tag_list, 'prefix':prefix, "pubsuggest_form": form},
context_instance=RequestContext(request))
if len(prefix) < 2:
return HttpResponse('')
tags_list = []
- result = ""
+ result = ""
for tag in _tags_starting_with(prefix, request.user):
if not tag.name in tags_list:
result += "\n" + tag.name
return HttpResponse(_('<p>To maintain your shelves you need to be logged in.</p>'))
book = get_object_or_404(models.Book, slug=slug)
+
user_sets = models.Tag.objects.filter(category='set', user=request.user)
book_sets = book.tags.filter(category='set', user=request.user)
new_shelves = [models.Tag.objects.get(pk=id) for id in form.cleaned_data['set_ids']]
for shelf in [shelf for shelf in old_shelves if shelf not in new_shelves]:
- shelf.book_count = None
- shelf.save()
+ touch_tag(shelf)
for shelf in [shelf for shelf in new_shelves if shelf not in old_shelves]:
- shelf.book_count = None
- shelf.save()
+ touch_tag(shelf)
book.tags = new_shelves + list(book.tags.filter(~Q(category='set') | ~Q(user=request.user)))
if request.is_ajax():
@login_required
@require_POST
@cache.never_cache
-def remove_from_shelf(request, shelf, book):
- book = get_object_or_404(models.Book, slug=book)
+def remove_from_shelf(request, shelf, slug):
+ book = get_object_or_404(models.Book, slug=slug)
+
shelf = get_object_or_404(models.Tag, slug=shelf, category='set', user=request.user)
if shelf in book.tags:
models.Tag.objects.remove_tag(book, shelf)
-
- shelf.book_count = None
- shelf.save()
+ touch_tag(shelf)
return HttpResponse(_('Book was successfully removed from the shelf'))
else:
if form.is_valid():
formats = form.cleaned_data['formats']
if len(formats) == 0:
- formats = ['pdf', 'epub', 'mobi', 'odt', 'txt']
+ formats = models.Book.ebook_formats
# Create a ZIP archive
temp = tempfile.TemporaryFile()
archive = zipfile.ZipFile(temp, 'w')
- already = set()
for book in collect_books(models.Book.tagged.with_all(shelf)):
- if 'pdf' in formats and book.pdf_file:
- filename = book.pdf_file.path
- archive.write(filename, str('%s.pdf' % book.slug))
- if 'mobi' in formats and book.mobi_file:
- filename = book.mobi_file.path
- archive.write(filename, str('%s.mobi' % book.slug))
- if book.root_ancestor not in already and 'epub' in formats and book.root_ancestor.epub_file:
- filename = book.root_ancestor.epub_file.path
- archive.write(filename, str('%s.epub' % book.root_ancestor.slug))
- already.add(book.root_ancestor)
- if 'odt' in formats and book.has_media("odt"):
- for file in book.get_media("odt"):
- filename = file.file.path
- archive.write(filename, str('%s.odt' % slughifi(file.name)))
- if 'txt' in formats and book.txt_file:
- filename = book.txt_file.path
- archive.write(filename, str('%s.txt' % book.slug))
+ for ebook_format in models.Book.ebook_formats:
+ if ebook_format in formats and book.has_media(ebook_format):
+ filename = book.get_media(ebook_format).path
+ archive.write(filename, str('%s.%s' % (book.slug, ebook_format)))
archive.close()
response = HttpResponse(content_type='application/zip', mimetype='application/x-zip-compressed')
"""
shelf = get_object_or_404(models.Tag, slug=shelf, category='set')
- formats = {'pdf': False, 'epub': False, 'mobi': False, 'odt': False, 'txt': False}
+ formats = {}
+ for ebook_format in models.Book.ebook_formats:
+ formats[ebook_format] = False
for book in collect_books(models.Book.tagged.with_all(shelf)):
- if book.pdf_file:
- formats['pdf'] = True
- if book.root_ancestor.epub_file:
- formats['epub'] = True
- if book.mobi_file:
- formats['mobi'] = True
- if book.txt_file:
- formats['txt'] = True
- for format in ('odt',):
- if book.has_media(format):
- formats[format] = True
+ for ebook_format in models.Book.ebook_formats:
+ if book.has_media(ebook_format):
+ formats[ebook_format] = True
return HttpResponse(LazyEncoder().encode(formats))
return HttpResponseRedirect('/')
-# ==================
-# = Authentication =
-# ==================
-@require_POST
-@cache.never_cache
-def login(request):
- form = AuthenticationForm(data=request.POST, prefix='login')
- if form.is_valid():
- auth.login(request, form.get_user())
- response_data = {'success': True, 'errors': {}}
- else:
- response_data = {'success': False, 'errors': form.errors}
- return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
-
-
-@require_POST
-@cache.never_cache
-def register(request):
- registration_form = UserCreationForm(request.POST, prefix='registration')
- if registration_form.is_valid():
- user = registration_form.save()
- user = auth.authenticate(
- username=registration_form.cleaned_data['username'],
- password=registration_form.cleaned_data['password1']
- )
- auth.login(request, user)
- response_data = {'success': True, 'errors': {}}
- else:
- response_data = {'success': False, 'errors': registration_form.errors}
- return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
-
-
-@cache.never_cache
-def logout_then_redirect(request):
- auth.logout(request)
- return HttpResponseRedirect(urlquote_plus(request.GET.get('next', '/'), safe='/?='))
-
-
-
# =========
# = Admin =
# =========
return HttpResponse(_("Error importing file: %r") % book_import_form.errors)
-
-def clock(request):
- """ Provides server time for jquery.countdown,
- in a format suitable for Date.parse()
- """
- return HttpResponse(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
-
-
# info views for API
def book_info(request, id, lang='pl'):
return HttpResponse(tag.description)
-def download_zip(request, format, slug):
+def download_zip(request, format, slug=None):
url = None
- if format in ('pdf', 'epub', 'mobi'):
+ if format in models.Book.ebook_formats:
url = models.Book.zip_format(format)
- elif format == 'audiobook' and slug is not None:
- book = models.Book.objects.get(slug=slug)
- url = book.zip_audiobooks()
+ elif format in ('mp3', 'ogg') and slug is not None:
+ book = get_object_or_404(models.Book, slug=slug)
+ url = book.zip_audiobooks(format)
else:
raise Http404('No format specified for zip package')
return HttpResponseRedirect(urlquote_plus(settings.MEDIA_URL + url, safe='/?='))
+
+
+def download_custom_pdf(request, slug, method='GET'):
+ book = get_object_or_404(models.Book, slug=slug)
+
+ if request.method == method:
+ form = forms.CustomPDFForm(method == 'GET' and request.GET or request.POST)
+ if form.is_valid():
+ cust = form.customizations
+ pdf_file = models.get_customized_pdf_path(book, cust)
+
+ if not path.exists(pdf_file):
+ result = async_build_pdf.delay(book.id, cust, pdf_file)
+ result.wait()
+ return AttachmentHttpResponse(file_name=("%s.pdf" % book.slug), file_path=pdf_file, mimetype="application/pdf")
+ else:
+ raise Http404(_('Incorrect customization options for PDF'))
+ else:
+ raise Http404(_('Bad method'))
+
+
+class CustomPDFFormView(AjaxableFormView):
+ form_class = forms.CustomPDFForm
+ title = _('Download custom PDF')
+ submit = _('Download')
+
+ def __call__(self, request):
+ from copy import copy
+ if request.method == 'POST':
+ request.GET = copy(request.GET)
+ request.GET['next'] = "%s?%s" % (reverse('catalogue.views.download_custom_pdf', args=[request.GET['slug']]),
+ request.POST.urlencode())
+ return super(CustomPDFFormView, self).__call__(request)
+
+
+ def success(self, *args):
+ pass
{% extends "base.html" %}
{% load i18n pagination_tags %}
-{% load catalogue_tags %}
{% block bodyid %}footnotes{% endblock %}
-{% block title %}{% trans "Footnotes on WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{% trans "Footnotes" %}{% endblock %}
{% block body %}
<h1>{% trans "Footnotes" %}</h1>
- {% search_form %}
+<div class="normal-text">
<p>
{% trans "By first letter" %}:
{% endif %}
+</div>
+
{% endblock %}
from dictionary.models import Note
def letter_notes(request, letter=None):
- form = SearchForm()
letters = ["0-9"] + [chr(a) for a in range(ord('a'), ord('z')+1)]
objects = Note.objects.all()
if letter == "0-9":
from infopages.models import InfoPage
class InfoPageAdmin(TranslationAdmin):
- list_display = ('title',)
+ list_display = ('title', 'slug', 'main_page')
admin.site.register(InfoPage, InfoPageAdmin)
\ No newline at end of file
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'InfoPage.page_title'
+ db.delete_column('infopages_infopage', 'page_title')
+
+ # Deleting field 'InfoPage.page_title_en'
+ db.delete_column('infopages_infopage', 'page_title_en')
+
+ # Deleting field 'InfoPage.page_title_es'
+ db.delete_column('infopages_infopage', 'page_title_es')
+
+ # Deleting field 'InfoPage.page_title_fr'
+ db.delete_column('infopages_infopage', 'page_title_fr')
+
+ # Deleting field 'InfoPage.page_title_uk'
+ db.delete_column('infopages_infopage', 'page_title_uk')
+
+ # Deleting field 'InfoPage.page_title_de'
+ db.delete_column('infopages_infopage', 'page_title_de')
+
+ # Deleting field 'InfoPage.page_title_lt'
+ db.delete_column('infopages_infopage', 'page_title_lt')
+
+ # Deleting field 'InfoPage.page_title_pl'
+ db.delete_column('infopages_infopage', 'page_title_pl')
+
+ # Deleting field 'InfoPage.page_title_ru'
+ db.delete_column('infopages_infopage', 'page_title_ru')
+
+ # Adding field 'InfoPage.main_page'
+ db.add_column('infopages_infopage', 'main_page', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Adding field 'InfoPage.page_title'
+ db.add_column('infopages_infopage', 'page_title', self.gf('django.db.models.fields.CharField')(default='', max_length=120, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_en'
+ db.add_column('infopages_infopage', 'page_title_en', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_es'
+ db.add_column('infopages_infopage', 'page_title_es', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_fr'
+ db.add_column('infopages_infopage', 'page_title_fr', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_uk'
+ db.add_column('infopages_infopage', 'page_title_uk', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_de'
+ db.add_column('infopages_infopage', 'page_title_de', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_lt'
+ db.add_column('infopages_infopage', 'page_title_lt', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_pl'
+ db.add_column('infopages_infopage', 'page_title_pl', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Adding field 'InfoPage.page_title_ru'
+ db.add_column('infopages_infopage', 'page_title_ru', self.gf('django.db.models.fields.CharField')(max_length=120, null=True, blank=True), keep_default=False)
+
+ # Deleting field 'InfoPage.main_page'
+ db.delete_column('infopages_infopage', 'main_page')
+
+
+ models = {
+ 'infopages.infopage': {
+ 'Meta': {'ordering': "('main_page', 'slug')", 'object_name': 'InfoPage'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'left_column': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'left_column_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'left_column_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'main_page': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'right_column': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'right_column_de': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_en': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_es': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_fr': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_lt': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_pl': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_ru': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'right_column_uk': ('django.db.models.fields.TextField', [], {'null': True, 'blank': True}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '120', 'db_index': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
+ 'title_de': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_en': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_es': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_fr': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_lt': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_pl': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_ru': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True}),
+ 'title_uk': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': True, 'blank': True})
+ }
+ }
+
+ complete_apps = ['infopages']
from django.utils.translation import ugettext_lazy as _
class InfoPage(models.Model):
- """
- An InfoPage is used to display a two-column flatpage
- """
+ """An InfoPage is used to display a two-column flatpage."""
- page_title = models.CharField(_('page title'), max_length=120, blank=True)
+ main_page = models.IntegerField(_('main page priority'), null=True, blank=True)
slug = models.SlugField(_('slug'), max_length=120, unique=True, db_index=True)
title = models.CharField(_('title'), max_length=120, blank=True)
left_column = models.TextField(_('left column'), blank=True)
right_column = models.TextField(_('right column'), blank=True)
class Meta:
- ordering = ('slug',)
+ ordering = ('main_page', 'slug',)
verbose_name = _('info page')
verbose_name_plural = _('info pages')
def __unicode__(self):
return self.title
+ @models.permalink
+ def get_absolute_url(self):
+ return ('infopage', [self.slug])
--- /dev/null
+{% extends "base.html" %}
+{% load i18n %}
+{% load chunks %}
+
+{% block titleextra %}{{ page.title }}{% endblock %}
+
+{% block metadescription %}{{ left_column|striptags|truncatewords:10 }}{% endblock %}
+
+{% block body %}
+ <h1>{{ page.title }}</h1>
+
+ {% autoescape off %}
+ <div class="left-column">
+ <div class="normal-text">
+ {{ left_column }}
+ </div>
+ </div>
+ <div class="right-column">
+ <div class="normal-text">
+ {{ right_column }}
+ </div>
+ </div>
+ {% endautoescape %}
+{% endblock %}
--- /dev/null
+<ul>
+{% for page in objects %}
+ <li><a href="{{ page.get_absolute_url }}">{{ page.title }}</a></li>
+{% endfor %}
+</ul>
--- /dev/null
+# -*- coding: utf-8 -*-
+# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django import template
+from infopages.models import InfoPage
+
+register = template.Library()
+
+
+@register.inclusion_tag('infopages/on_main.html')
+def infopages_on_main():
+ objects = InfoPage.objects.exclude(main_page=None)
+ return {"objects": objects}
--- /dev/null
+# -*- coding: utf-8 -*-
+# 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.urls.defaults import *
+
+
+urlpatterns = patterns('infopages.views',
+ url(r'^(?P<slug>[a-zA-Z0-9_-]+)/$', 'infopage', name='infopage'),
+)
+
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-from django.shortcuts import render_to_response
-from django.template import RequestContext
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext, Template, TemplateSyntaxError
-from catalogue.forms import SearchForm
from infopages.models import InfoPage
+
def infopage(request, slug):
- form = SearchForm()
- object = InfoPage.objects.get(slug=slug)
+ page = get_object_or_404(InfoPage, slug=slug)
+ rc = RequestContext(request)
+ try:
+ left_column = Template(page.left_column).render(rc)
+ except TemplateSyntaxError:
+ left_column = ''
+
+ try:
+ right_column = Template(page.right_column).render(rc)
+ except TemplateSyntaxError:
+ left_column = ''
- return render_to_response('info/base.html', locals(),
- context_instance=RequestContext(request))
\ No newline at end of file
+ return render_to_response('infopages/infopage.html', locals(),
+ context_instance=RequestContext(request))
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django.conf.urls.defaults import *
+from catalogue.models import Book
urlpatterns = patterns('lesmianator.views',
url(r'^$', 'main_page', name='lesmianator'),
url(r'^wiersz/$', 'new_poem', name='new_poem'),
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/$', 'poem_from_book', name='poem_from_book'),
+ url(r'^lektura/(?P<slug>[a-z0-9-]+)/$', 'poem_from_book', name='poem_from_book'),
url(r'^polka/(?P<shelf>[a-zA-Z0-9-]+)/$', 'poem_from_set', name='poem_from_set'),
url(r'^wiersz/(?P<poem>[a-zA-Z0-9-]+)/$', 'get_poem', name='get_poem'),
)
# Create your views here.
+from django.http import Http404
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from catalogue.utils import get_random_hash
from catalogue.models import Book, Tag
-from catalogue import forms
from lesmianator.models import Poem, Continuations
def main_page(request):
last = Poem.objects.all().order_by('-created_at')[:10]
- form = forms.SearchForm()
shelves = Tag.objects.filter(user__username='lesmianator')
return render_to_response('lesmianator/lesmianator.html',
- {"last": last, "form": form, "shelves": shelves},
+ {"last": last, "shelves": shelves},
context_instance=RequestContext(request))
urlpatterns = patterns('',
url(r'^$', 'django.views.generic.simple.direct_to_template', {
'template': 'lessons/document_list.html',
- 'extra_context': {
- 'form': forms.SearchForm(),
- },
}, name='lessons_document_list'),
url(r'^(?P<slug>[a-zA-Z0-9_-]+)/$', 'lessons.views.document_detail', name='lessons_document_detail'),
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django.views.generic.list_detail import object_detail
-from catalogue import forms
from lessons import models
slug_field='slug',
queryset=models.Document.objects.all(),
template_name=template_name,
- extra_context={
- 'form': forms.SearchForm(),
- })
+ )
from base64 import b64encode
import os.path
from urlparse import urljoin
+from urllib2 import unquote
from django.contrib.syndication.views import Feed
from django.core.urlresolvers import reverse
from basicauth import logged_in_or_basicauth, factory_decorator
from catalogue.models import Book, Tag
-from catalogue.views import books_starting_with
+
+from search import Search, SearchResult, JVM
+from lucene import Term, QueryWrapperFilter, TermQuery
+
+import re
from stats.utils import piwik_track
return feed['title']
def items(self, feed):
- return (tag for tag in Tag.objects.filter(category=feed['category']) if tag.get_count() > 0)
+ return Tag.objects.filter(category=feed['category']).exclude(book_count=0)
def item_title(self, item):
return item.name
return u"Półki użytkownika %s" % user.username
def items(self, user):
- return (tag for tag in Tag.objects.filter(category='set', user=user) if tag.get_count() > 0)
+ return Tag.objects.filter(category='set', user=user).exclude(book_count=0)
def item_title(self, item):
return item.name
# no class decorators in python 2.5
#UserSetFeed = factory_decorator(logged_in_or_basicauth())(UserSetFeed)
+
@piwik_track
class SearchFeed(AcquisitionFeed):
description = u"Wyniki wyszukiwania na stronie WolneLektury.pl"
title = u"Wyniki wyszukiwania"
+
+ INLINE_QUERY_RE = re.compile(r"(author:(?P<author>[^ ]+)|title:(?P<title>[^ ]+)|categories:(?P<categories>[^ ]+)|description:(?P<description>[^ ]+))")
def get_object(self, request):
- return request.GET.get('q', '')
+ """
+ For OPDS 1.1 We should handle a query for search terms
+ and criteria provided either as opensearch or 'inline' query.
+ OpenSearch defines fields: atom:author, atom:contributor (treated as translator),
+ atom:title. Inline query provides author, title, categories (treated as book tags),
+ description (treated as content search terms).
+
+ if search terms are provided, we shall search for books
+ according to Hint information (from author & contributror & title).
+
+ but if search terms are empty, we should do a different search
+ (perhaps for is_book=True)
+
+ """
+ JVM.attachCurrentThread()
+
+ query = request.GET.get('q', '')
+
+ inline_criteria = re.findall(self.INLINE_QUERY_RE, query)
+ if inline_criteria:
+ def get_criteria(criteria, name, position):
+ e = filter(lambda el: el[0][0:len(name)] == name, criteria)
+ print e
+ if not e:
+ return None
+ c = e[0][position]
+ print c
+ if c[0] == '"' and c[-1] == '"':
+ c = c[1:-1]
+ c = c.replace('+', ' ')
+ return c
+
+ #import pdb; pdb.set_trace()
+ author = get_criteria(inline_criteria, 'author', 1)
+ title = get_criteria(inline_criteria, 'title', 2)
+ translator = None
+ categories = get_criteria(inline_criteria, 'categories', 3)
+ query = get_criteria(inline_criteria, 'description', 4)
+ else:
+ author = request.GET.get('author', '')
+ title = request.GET.get('title', '')
+ translator = request.GET.get('translator', '')
+ categories = None
+ fuzzy = False
+
+
+ srch = Search()
+ hint = srch.hint()
+
+ # Scenario 1: full search terms provided.
+ # Use auxiliarry information to narrow it and make it better.
+ if query:
+ filters = []
+
+ if author:
+ print "narrow to author %s" % author
+ hint.tags(srch.search_tags(author, filter=srch.term_filter(Term('tag_category', 'author'))))
+
+ if translator:
+ print "filter by translator %s" % translator
+ filters.append(QueryWrapperFilter(
+ srch.make_phrase(srch.get_tokens(translator, field='translators'),
+ field='translators')))
+
+ if categories:
+ filters.append(QueryWrapperFilter(
+ srch.make_phrase(srch.get_tokens(categories, field="tag_name_pl"),
+ field='tag_name_pl')))
+
+ flt = srch.chain_filters(filters)
+ if title:
+ print "hint by book title %s" % title
+ q = srch.make_phrase(srch.get_tokens(title, field='title'), field='title')
+ hint.books(*srch.search_books(q, filter=flt))
+
+ toks = srch.get_tokens(query)
+ print "tokens: %s" % toks
+ # import pdb; pdb.set_trace()
+ results = SearchResult.aggregate(srch.search_perfect_book(toks, fuzzy=fuzzy, hint=hint),
+ srch.search_perfect_parts(toks, fuzzy=fuzzy, hint=hint),
+ srch.search_everywhere(toks, fuzzy=fuzzy, hint=hint))
+ results.sort(reverse=True)
+ return [r.book for r in results]
+ else:
+ # Scenario 2: since we no longer have to figure out what the query term means to the user,
+ # we can just use filters and not the Hint class.
+ filters = []
+
+ fields = {
+ 'author': author,
+ 'translators': translator,
+ 'title': title
+ }
+
+ for fld, q in fields.items():
+ if q:
+ filters.append(QueryWrapperFilter(
+ srch.make_phrase(srch.get_tokens(q, field=fld), field=fld)))
+
+ flt = srch.chain_filters(filters)
+ books = srch.search_books(TermQuery(Term('is_book', 'true')), filter=flt)
+ return books
def get_link(self, query):
- return "%s?q=%s" % (reverse('search'), query)
+ return "%s?q=%s" % (reverse('search'), query)
- def items(self, query):
+ def items(self, books):
try:
- return books_starting_with(query)
+ return books
except ValueError:
# too short a query
return []
+++ /dev/null
-# -*- coding: utf-8 -*-
-# 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.urls.defaults import *
-
-
-urlpatterns = patterns('catalogue.views',
- url(r'^$', 'main_page', name='main_page'),
- url(r'^polki/(?P<shelf>[a-zA-Z0-9-]+)/formaty/$', 'shelf_book_formats', name='shelf_book_formats'),
- url(r'^polki/(?P<shelf>[a-zA-Z0-9-]+)/(?P<book>[a-zA-Z0-9-0-]+)/usun$', 'remove_from_shelf', name='remove_from_shelf'),
- url(r'^polki/$', 'user_shelves', name='user_shelves'),
- url(r'^polki/(?P<slug>[a-zA-Z0-9-]+)/usun/$', 'delete_shelf', name='delete_shelf'),
- url(r'^polki/(?P<slug>[a-zA-Z0-9-]+)\.zip$', 'download_shelf', name='download_shelf'),
- url(r'^lektury/', 'book_list', name='book_list'),
- url(r'^audiobooki/', 'audiobook_list', name='audiobook_list'),
- url(r'^daisy/', 'daisy_list', name='daisy_list'),
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/polki/', 'book_sets', name='book_shelves'),
- url(r'^polki/nowa/$', 'new_set', name='new_set'),
- url(r'^tags/$', 'tags_starting_with', name='hint'),
- url(r'^jtags/$', 'json_tags_starting_with', name='jhint'),
- url(r'^szukaj/$', 'search', name='search'),
-
- # tools
- url(r'^zegar/$', 'clock', name='clock'),
- url(r'^xmls.zip$', 'xmls', name='xmls'),
- url(r'^epubs.tar$', 'epubs', name='epubs'),
-
- # Public interface. Do not change this URLs.
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)\.html$', 'book_text', name='book_text'),
- url(r'^lektura/(?P<slug>[a-zA-Z0-9-]+)/$', 'book_detail', name='book_detail'),
- url(r'^lektura/(?P<book_slug>[a-zA-Z0-9-]+)/motyw/(?P<theme_slug>[a-zA-Z0-9-]+)/$',
- 'book_fragments', name='book_fragments'),
- url(r'^(?P<tags>[a-zA-Z0-9-/]*)/$', 'tagged_object_list', name='tagged_object_list'),
-)
-
from django.template import RequestContext
from django.shortcuts import render_to_response, get_object_or_404
from pdcounter import models
-from catalogue import forms
from suggest.forms import PublishingSuggestForm
def book_stub_detail(request, slug):
book = get_object_or_404(models.BookStub, slug=slug)
pd_counter = book.pd
- form = forms.SearchForm()
- pubsuggest_form = PublishingSuggestForm(
+ form = PublishingSuggestForm(
initial={"books": u"%s — %s, \n" % (book.author, book.title)})
return render_to_response('pdcounter/book_stub_detail.html', locals(),
def author_detail(request, slug):
author = get_object_or_404(models.Author, slug=slug)
pd_counter = author.goes_to_pd()
- form = forms.SearchForm()
- pubsuggest_form = PublishingSuggestForm(initial={"books": author.name + ", \n"})
+ form = PublishingSuggestForm(initial={"books": author.name + ", \n"})
return render_to_response('pdcounter/author_detail.html', locals(),
context_instance=RequestContext(request))
--- /dev/null
+
+from django.contrib import admin
+from picture.models import Picture
+from sorl.thumbnail.admin import AdminImageMixin
+
+class PictureAdmin(AdminImageMixin, admin.ModelAdmin):
+ pass
+
+admin.site.register(Picture, PictureAdmin)
--- /dev/null
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+from picture.models import Picture
+
+
+class PictureImportForm(forms.Form):
+ picture_xml_file = forms.FileField(required=False)
+ picture_xml = forms.CharField(required=False)
+ picture_image_file = forms.FileField(required=False)
+ picture_image_data = forms.CharField(required=False)
+
+ def clean(self):
+ from base64 import b64decode
+ from django.core.files.base import ContentFile
+
+ if not self.cleaned_data['picture_xml_file']:
+ if self.cleaned_data['picture_xml']:
+ self.cleaned_data['picture_xml_file'] = \
+ ContentFile(self.cleaned_data['picture_xml'].encode('utf-8'))
+ else:
+ raise forms.ValidationError(_("Please supply an XML."))
+
+ if not self.cleaned_data['picture_image_file']:
+ if self.cleaned_data['picture_image_data']:
+ self.cleaned_data['picture_image_file'] = \
+ ContentFile(b64decode(
+ self.cleaned_data['picture_image_data']))
+ else:
+ raise forms.ValidationError(_("Please supply an image."))
+
+ return super(PictureImportForm, self).clean()
+
+ def save(self, commit=True, **kwargs):
+ return Picture.from_xml_file(self.cleaned_data['picture_xml_file'], image_file=self.cleaned_data['picture_image_file'],
+ overwrite=True, **kwargs)
--- /dev/null
+from django.db import models
+import catalogue.models
+from django.db.models import permalink
+from sorl.thumbnail import ImageField
+from django.conf import settings
+from django.core.files.storage import FileSystemStorage
+from django.utils.datastructures import SortedDict
+from django.template.loader import render_to_string
+from django.core.cache import cache
+from catalogue.utils import split_tags
+from django.utils.safestring import mark_safe
+from slughifi import slughifi
+
+from django.utils.translation import ugettext_lazy as _
+from newtagging import managers
+from os import path
+
+
+picture_storage = FileSystemStorage(location=path.join(settings.MEDIA_ROOT, 'pictures'), base_url=settings.MEDIA_URL + "pictures/")
+
+
+class Picture(models.Model):
+ """
+ Picture resource.
+
+ """
+ title = models.CharField(_('title'), max_length=120)
+ slug = models.SlugField(_('slug'), max_length=120, db_index=True, unique=True)
+ sort_key = models.CharField(_('sort key'), max_length=120, db_index=True, editable=False)
+ created_at = models.DateTimeField(_('creation date'), auto_now_add=True, db_index=True)
+ changed_at = models.DateTimeField(_('creation date'), auto_now=True, db_index=True)
+ xml_file = models.FileField('xml_file', upload_to="xml", storage=picture_storage)
+ image_file = ImageField(_('image_file'), upload_to="images", storage=picture_storage)
+ objects = models.Manager()
+ tagged = managers.ModelTaggedItemManager(catalogue.models.Tag)
+ tags = managers.TagDescriptor(catalogue.models.Tag)
+
+ class AlreadyExists(Exception):
+ pass
+
+ class Meta:
+ ordering = ('sort_key',)
+
+ verbose_name = _('picture')
+ verbose_name_plural = _('pictures')
+
+ def save(self, force_insert=False, force_update=False, reset_short_html=True, **kwargs):
+ from sortify import sortify
+
+ self.sort_key = sortify(self.title)
+
+ ret = super(Picture, self).save(force_insert, force_update)
+
+ if reset_short_html:
+ self.reset_short_html()
+
+ return ret
+
+ def __unicode__(self):
+ return self.title
+
+ @permalink
+ def get_absolute_url(self):
+ return ('picture.views.picture_detail', [self.slug])
+
+ @classmethod
+ def from_xml_file(cls, xml_file, image_file=None, overwrite=False):
+ """
+ Import xml and it's accompanying image file.
+ If image file is missing, it will be fetched by librarian.picture.ImageStore
+ which looks for an image file in the same directory the xml is, with extension matching
+ its mime type.
+ """
+ from sortify import sortify
+ from django.core.files import File
+ from librarian.picture import WLPicture, ImageStore
+ close_xml_file = False
+ close_image_file = False
+ # class SimpleImageStore(object):
+ # def path(self_, slug, mime_type):
+ # """Returns the image file. Ignores slug ad mime_type."""
+ # return image_file
+
+ if image_file is not None and not isinstance(image_file, File):
+ image_file = File(open(image_file))
+ close_image_file = True
+
+ if not isinstance(xml_file, File):
+ xml_file = File(open(xml_file))
+ close_xml_file = True
+
+ try:
+ # use librarian to parse meta-data
+ picture_xml = WLPicture.from_file(xml_file,
+ image_store=ImageStore(picture_storage.path('images')))
+ # image_store=SimpleImageStore
+
+ picture, created = Picture.objects.get_or_create(slug=picture_xml.slug)
+ if not created and not overwrite:
+ raise Picture.AlreadyExists('Picture %s already exists' % picture_xml.slug)
+
+ picture.title = picture_xml.picture_info.title
+
+ motif_tags = set()
+ for part in picture_xml.partiter():
+ for motif in part['themes']:
+ tag, created = catalogue.models.Tag.objects.get_or_create(slug=slughifi(motif), category='theme')
+ if created:
+ tag.name = motif
+ tag.sort_key = sortify(tag.name)
+ tag.save()
+ motif_tags.add(tag)
+
+ picture.tags = catalogue.models.Tag.tags_from_info(picture_xml.picture_info) + \
+ list(motif_tags)
+
+ if image_file is not None:
+ img = image_file
+ else:
+ img = picture_xml.image_file()
+
+ # FIXME: hardcoded extension
+ picture.image_file.save(path.basename(picture_xml.image_path), File(img))
+
+ picture.xml_file.save("%s.xml" % picture.slug, File(xml_file))
+ picture.save()
+ finally:
+ if close_xml_file:
+ xml_file.close()
+ if close_image_file:
+ image_file.close()
+ return picture
+
+ @classmethod
+ def picture_list(cls, filter=None):
+ """Generates a hierarchical listing of all pictures
+ Pictures are optionally filtered with a test function.
+ """
+
+ pics = cls.objects.all().order_by('sort_key')\
+ .only('title', 'slug', 'image_file')
+
+ if filter:
+ pics = pics.filter(filter).distinct()
+
+ pics_by_author = SortedDict()
+ orphans = []
+ for tag in catalogue.models.Tag.objects.filter(category='author'):
+ pics_by_author[tag] = []
+
+ for pic in pics:
+ authors = list(pic.tags.filter(category='author'))
+ if authors:
+ for author in authors:
+ pics_by_author[author].append(pic)
+ else:
+ orphans.append(pic)
+
+ return pics_by_author, orphans
+
+ @property
+ def info(self):
+ if not hasattr(self, '_info'):
+ from librarian import dcparser
+ from librarian import picture
+ info = dcparser.parse(self.xml_file.path, picture.PictureInfo)
+ self._info = info
+ return self._info
+
+ def reset_short_html(self):
+ if self.id is None:
+ return
+
+ cache_key = "Picture.short_html/%d" % (self.id)
+ cache.delete(cache_key)
+
+ def short_html(self):
+ if self.id:
+ cache_key = "Picture.short_html/%d" % (self.id)
+ short_html = cache.get(cache_key)
+ else:
+ short_html = None
+
+ if short_html is not None:
+ return mark_safe(short_html)
+ else:
+ tags = self.tags.filter(category__in=('author', 'kind', 'epoch'))
+ tags = split_tags(tags)
+
+ short_html = unicode(render_to_string('picture/picture_short.html',
+ {'picture': self, 'tags': tags}))
+
+ if self.id:
+ cache.set(cache_key, short_html, catalogue.models.CACHE_FOREVER)
+ return mark_safe(short_html)
--- /dev/null
+{% extends "admin/change_list.html" %}
+{% load i18n %}
+
+{% block content %}
+ <form action="{% url import_picture %}" method="post" enctype="multipart/form-data">
+ <p>XML: <input type="file" id="id_picture_xml_file" name="picture_xml_file" /><br/>
+ {% trans "Image" %}: <input type="file" id="id_picture_image_file" name="picture_image_file" /><br/>
+ <input type="submit" value="{% trans "Import picture" %}"/></p>
+ </form>
+ {{ block.super }}
+{% endblock content %}
\ No newline at end of file
--- /dev/null
+from picture.tests.picture_import import *
--- /dev/null
+<picture>
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/Lektury:Andersen/Brzydkie_kaczątko">
+ <dc:creator xml:lang="pl">Kandinsky, Vasily</dc:creator>
+ <dc:title xml:lang="la">composition 8</dc:title>
+ <dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+ <dc:contributor.editor xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Sekuła, Aleksandra</dc:contributor.editor>
+ <dc:contributor.editor xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Kwiatkowska, Katarzyna</dc:contributor.editor>
+ <dc:contributor.technical_editor xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Trzeciak, Weronika</dc:contributor.technical_editor>
+ <dc:subject.period xml:lang="pl">Modernizm</dc:subject.period>
+ <dc:subject.type xml:lang="pl">Obraz</dc:subject.type>
+ <dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+ <dc:description.dimensions xml:lang="pl">55 1/8 x 79 1/8 inches</dc:description.dimensions>
+ <dc:description.medium xml:lang="pl">Olej na płótnie</dc:description.medium>
+ <dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/obraz/kandinsky-composition-viii</dc:identifier.url>
+ <dc:source.URL xml:lang="pl">http://www.ibiblio.org/wm/paint/auth/kandinsky/kandinsky.comp-8.jpg</dc:source.URL>
+ <dc:source xml:lang="pl">Muzeum Narodowe, inw. 00000001.</dc:source>
+ <dc:rights xml:lang="pl">Domena publiczna - Vasily Kandinsky zm. ?</dc:rights>
+ <dc:date.pd xml:lang="pl">1940</dc:date.pd>
+ <dc:type>Image</dc:type>
+ <dc:format xml:lang="pl">image/png</dc:format>
+ <dc:format.dimensions xml:lang="pl">1090 x 755 px</dc:format.dimensions>
+ <dc:format.checksum.sha1 xml:lang="pl">122b590510ce70cc80e617557f82048ce20f1d7b</dc:format.checksum.sha1>
+ <dc:date xml:lang="pl">1923</dc:date>
+ <dc:language xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">eng</dc:language>
+ </rdf:Description>
+ </rdf:RDF>
+
+ <sem type="object" object="kosmos">
+ <div type="area" x1="17" y1="31" x2="275" y2="309"/>
+ </sem>
+ <sem type="theme" theme="nieporządek">
+ <div type="area" x1="300" y1="138" x2="976" y2="514"/>
+ </sem>
+
+</picture>
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import with_statement
+
+from django.core.files.base import ContentFile, File
+from catalogue.test_utils import *
+from catalogue import models
+from librarian import WLURI
+from picture.models import Picture
+
+from nose.tools import raises
+import tempfile
+from os import unlink, path, makedirs
+
+
+class PictureTest(TestCase):
+
+ def test_import(self):
+ picture = Picture.from_xml_file(path.join(path.dirname(__file__), "files/kandinsky-composition-viii.xml"))
+
+ motifs = set([tag.name for tag in picture.tags if tag.category == 'theme'])
+ assert motifs == set([u'nieporządek']), 'theme tags are wrong. %s' % motifs
+
+ picture.delete()
+
+ def test_import_with_explicit_image(self):
+ picture = Picture.from_xml_file(path.join(path.dirname(__file__), "files/kandinsky-composition-viii.xml"),
+ path.join(path.dirname(__file__), "files/kandinsky-composition-viii.png"))
+
+ picture.delete()
+
--- /dev/null
+from picture.models import Picture
+from django.contrib.auth.decorators import permission_required
+from django.utils.datastructures import SortedDict
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext
+
+
+def picture_list(request, filter=None, template_name='catalogue/picture_list.html'):
+ """ generates a listing of all books, optionally filtered with a test function """
+
+ pictures_by_author, orphans = Picture.picture_list()
+ books_nav = SortedDict()
+ for tag in pictures_by_author:
+ if pictures_by_author[tag]:
+ books_nav.setdefault(tag.sort_key[0], []).append(tag)
+
+ # import pdb; pdb.set_trace()
+ return render_to_response(template_name, locals(),
+ context_instance=RequestContext(request))
+
+
+def picture_detail(request, picture):
+ picture = get_object_or_404(Picture, slug=picture)
+
+ categories = SortedDict()
+ for tag in picture.tags:
+ categories.setdefault(tag.category, []).append(tag)
+
+ picture_themes = []
+
+ return render_to_response("catalogue/picture_detail.html", locals(),
+ context_instance=RequestContext(request))
+
+# =========
+# = Admin =
+# =========
+@permission_required('picture.add_picture')
+def import_picture(request):
+ """docstring for import_book"""
+ from django.http import HttpResponse
+ from picture.forms import PictureImportForm
+ from django.utils.translation import ugettext as _
+
+ import_form = PictureImportForm(request.POST, request.FILES)
+ if import_form.is_valid():
+ try:
+ import_form.save()
+ except:
+ import sys
+ import pprint
+ import traceback
+ info = sys.exc_info()
+ exception = pprint.pformat(info[1])
+ tb = '\n'.join(traceback.format_tb(info[2]))
+ return HttpResponse(_("An error occurred: %(exception)s\n\n%(tb)s") % {'exception':exception, 'tb':tb}, mimetype='text/plain')
+ return HttpResponse(_("Picture imported successfully"))
+ else:
+ return HttpResponse(_("Error importing file: %r") % import_form.errors)
\setlength{\leftmargin}{0em}
\setlength{\rightmargin}{0em}
\setlength{\textheight}{24cm}
-\setlength{\textwidth}{17cm}
+\setlength{\textwidth}{17.5cm}
\pagestyle{fancy}
\end{flushright}
\end{minipage}
- \begin{longtable}{p{15cm} p{2cm}}
+ \begin{longtable}{p{9.5cm} p{5.5cm}r p{2cm}}
<TeXML escape="1">
{% book_tree_texml orphans books_by_parent %}
{% load i18n %}
{% load reporting_stats catalogue_tags %}
-{% block title %}Statystyka w WolneLektury.pl{% endblock %}
+{% block titleextra %}{% trans "Reports" %}{% endblock %}
{% block bodyid %}reports-stats{% endblock %}
{% block body %}
<h1>Statystyka</h1>
- {% search_form %}
- <p><a href="{% url reporting_catalogue_pdf %}">Katalog biblioteki w formacie PDF.</a></p>
+ <div class="normal-text">
<table class="stats">
<tr><th>Utwory</th></tr>
- <tr><td>Wszystkie utwory:</td><td>{% count_books_all %}</td></tr>
- <tr><td>Utwory z własną treścią:</td><td>{% count_books_nonempty %}</td></tr>
- <tr><td>Utwory bez własnej treści:</td><td>{% count_books_empty %}</td></tr>
+ <tr><td>Utwory:</td><td>{% count_books %}</td></tr>
<tr><td>Niezależne książki:</td><td>{% count_books_root %}</td></tr>
+ <tr><td>Utwory nadrzędne:</td><td>{% count_books_parent %}</td></tr>
+ <tr><td>Wszystkie utwory:</td><td>{% count_books_all %}</td></tr>
<tr><th>Media</th><th>Liczba</th><th>Rozmiar</th><th>Do wymiany</th></tr>
{% for mt in media_types %}
<td>{{ mt.size|filesizeformat }}</td>
<td>{{ mt.deprecated }}
{% for m in mt.deprecated_files %}
- <br/><a href="{{ m.book.get_absolute_url }}">{{ m }}</a>
+ <br/><a href="{{ m.book.get_absolute_url }}">{% book_title m.book %}: {{ m }}</a>
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
+ </div>
+
{% endblock %}
return Book.objects.all().count()
@register_counter
-def count_books_nonempty():
+def count_books():
return Book.objects.exclude(html_file='').count()
@register_counter
-def count_books_empty():
+def count_books_parent():
return Book.objects.filter(html_file='').count()
@register_counter
--- /dev/null
+import lucene
+
+from index import Index, Search, ReusableIndex, SearchResult, JVM, IndexChecker, IndexStore
--- /dev/null
+
+from catalogue.forms import SearchForm
+from django.core.urlresolvers import reverse
+
+
+def search_form(request):
+ return { 'search_form': SearchForm(reverse('search.views.hint'), request.GET) }
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from django.conf import settings
+from lucene import SimpleFSDirectory, IndexWriter, CheckIndex, \
+ File, Field, Integer, \
+ NumericField, Version, Document, JavaError, IndexSearcher, \
+ QueryParser, PerFieldAnalyzerWrapper, \
+ SimpleAnalyzer, PolishAnalyzer, ArrayList, \
+ KeywordAnalyzer, NumericRangeQuery, NumericRangeFilter, BooleanQuery, \
+ BlockJoinQuery, BlockJoinCollector, Filter, TermsFilter, ChainedFilter, \
+ HashSet, BooleanClause, Term, CharTermAttribute, \
+ PhraseQuery, MultiPhraseQuery, StringReader, TermQuery, \
+ FuzzyQuery, FuzzyTermEnum, PrefixTermEnum, Sort, Integer, \
+ SimpleHTMLFormatter, Highlighter, QueryScorer, TokenSources, TextFragment, \
+ BooleanFilter, TermsFilter, FilterClause, QueryWrapperFilter, \
+ initVM, CLASSPATH, JArray, JavaError
+ # KeywordAnalyzer
+
+# Initialize jvm
+JVM = initVM(CLASSPATH)
+
+import sys
+import os
+import re
+import errno
+from librarian import dcparser
+from librarian.parser import WLDocument
+import catalogue.models
+from multiprocessing.pool import ThreadPool
+from threading import current_thread
+import atexit
+import traceback
+
+
+class WLAnalyzer(PerFieldAnalyzerWrapper):
+ def __init__(self):
+ polish = PolishAnalyzer(Version.LUCENE_34)
+ # polish_gap.setPositionIncrementGap(999)
+
+ simple = SimpleAnalyzer(Version.LUCENE_34)
+ # simple_gap.setPositionIncrementGap(999)
+
+ keyword = KeywordAnalyzer(Version.LUCENE_34)
+
+ # not sure if needed: there's NOT_ANALYZED meaning basically the same
+
+ PerFieldAnalyzerWrapper.__init__(self, polish)
+
+ self.addAnalyzer("tags", simple)
+ self.addAnalyzer("technical_editors", simple)
+ self.addAnalyzer("editors", simple)
+ self.addAnalyzer("url", keyword)
+ self.addAnalyzer("source_url", keyword)
+ self.addAnalyzer("source_name", simple)
+ self.addAnalyzer("publisher", simple)
+ self.addAnalyzer("authors", simple)
+ self.addAnalyzer("title", simple)
+
+ self.addAnalyzer("is_book", keyword)
+ # shouldn't the title have two forms? _pl and simple?
+
+ self.addAnalyzer("themes", simple)
+ self.addAnalyzer("themes_pl", polish)
+
+ self.addAnalyzer("tag_name", simple)
+ self.addAnalyzer("tag_name_pl", polish)
+
+ self.addAnalyzer("translators", simple)
+
+ self.addAnalyzer("KEYWORD", keyword)
+ self.addAnalyzer("SIMPLE", simple)
+ self.addAnalyzer("POLISH", polish)
+
+
+class IndexStore(object):
+ """
+ Provides access to search index.
+
+ self.store - lucene index directory
+ """
+ def __init__(self):
+ self.make_index_dir()
+ self.store = SimpleFSDirectory(File(settings.SEARCH_INDEX))
+
+ def make_index_dir(self):
+ try:
+ os.makedirs(settings.SEARCH_INDEX)
+ except OSError as exc:
+ if exc.errno == errno.EEXIST:
+ pass
+ else: raise
+
+
+class IndexChecker(IndexStore):
+ def __init__(self):
+ IndexStore.__init__(self)
+
+ def check(self):
+ checker = CheckIndex(self.store)
+ status = checker.checkIndex()
+ return status
+
+
+class Snippets(object):
+ """
+ This class manages snippet files for indexed object (book)
+ the snippets are concatenated together, and their positions and
+ lengths are kept in lucene index fields.
+ """
+ SNIPPET_DIR = "snippets"
+
+ def __init__(self, book_id):
+ try:
+ os.makedirs(os.path.join(settings.SEARCH_INDEX, self.SNIPPET_DIR))
+ except OSError as exc:
+ if exc.errno == errno.EEXIST:
+ pass
+ else: raise
+ self.book_id = book_id
+ self.file = None
+
+ def open(self, mode='r'):
+ """
+ Open the snippet file. Call .close() afterwards.
+ """
+ if not 'b' in mode:
+ mode += 'b'
+ self.file = open(os.path.join(settings.SEARCH_INDEX, self.SNIPPET_DIR, str(self.book_id)), mode)
+ self.position = 0
+ return self
+
+ def add(self, snippet):
+ """
+ Append a snippet (unicode) to the snippet file.
+ Return a (position, length) tuple
+ """
+ txt = snippet.encode('utf-8')
+ l = len(txt)
+ self.file.write(txt)
+ pos = (self.position, l)
+ self.position += l
+ return pos
+
+ def get(self, pos):
+ """
+ Given a tuple of (position, length) return an unicode
+ of the snippet stored there.
+ """
+ self.file.seek(pos[0], 0)
+ txt = self.file.read(pos[1]).decode('utf-8')
+ return txt
+
+ def close(self):
+ """Close snippet file"""
+ self.file.close()
+
+
+class BaseIndex(IndexStore):
+ """
+ Base index class.
+ Provides basic operations on index: opening, closing, optimizing.
+ """
+ def __init__(self, analyzer=None):
+ super(BaseIndex, self).__init__()
+ self.index = None
+ if not analyzer:
+ analyzer = WLAnalyzer()
+ self.analyzer = analyzer
+
+ def open(self, analyzer=None):
+ if self.index:
+ raise Exception("Index is already opened")
+ self.index = IndexWriter(self.store, self.analyzer,\
+ IndexWriter.MaxFieldLength.LIMITED)
+ return self.index
+
+ def optimize(self):
+ self.index.optimize()
+
+ def close(self):
+ try:
+ self.index.optimize()
+ except JavaError, je:
+ print "Error during optimize phase, check index: %s" % je
+
+ self.index.close()
+ self.index = None
+
+ def __enter__(self):
+ self.open()
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.close()
+
+
+class Index(BaseIndex):
+ """
+ Class indexing books.
+ """
+ def __init__(self, analyzer=None):
+ super(Index, self).__init__(analyzer)
+
+ def index_tags(self):
+ """
+ Re-index global tag list.
+ Removes all tags from index, then index them again.
+ Indexed fields include: id, name (with and without polish stems), category
+ """
+ q = NumericRangeQuery.newIntRange("tag_id", 0, Integer.MAX_VALUE, True, True)
+ self.index.deleteDocuments(q)
+
+ for tag in catalogue.models.Tag.objects.all():
+ doc = Document()
+ doc.add(NumericField("tag_id", Field.Store.YES, True).setIntValue(tag.id))
+ doc.add(Field("tag_name", tag.name, Field.Store.NO, Field.Index.ANALYZED))
+ doc.add(Field("tag_name_pl", tag.name, Field.Store.NO, Field.Index.ANALYZED))
+ doc.add(Field("tag_category", tag.category, Field.Store.NO, Field.Index.NOT_ANALYZED))
+ self.index.addDocument(doc)
+
+ def create_book_doc(self, book):
+ """
+ Create a lucene document referring book id.
+ """
+ doc = Document()
+ doc.add(NumericField("book_id", Field.Store.YES, True).setIntValue(book.id))
+ if book.parent is not None:
+ doc.add(NumericField("parent_id", Field.Store.YES, True).setIntValue(book.parent.id))
+ return doc
+
+ def remove_book(self, book):
+ """Removes a book from search index.
+ book - Book instance."""
+ q = NumericRangeQuery.newIntRange("book_id", book.id, book.id, True, True)
+ self.index.deleteDocuments(q)
+
+ def index_book(self, book, book_info=None, overwrite=True):
+ """
+ Indexes the book.
+ Creates a lucene document for extracted metadata
+ and calls self.index_content() to index the contents of the book.
+ """
+ if overwrite:
+ self.remove_book(book)
+
+ book_doc = self.create_book_doc(book)
+ meta_fields = self.extract_metadata(book, book_info)
+ for f in meta_fields.values():
+ if isinstance(f, list) or isinstance(f, tuple):
+ for elem in f:
+ book_doc.add(elem)
+ else:
+ book_doc.add(f)
+
+ self.index.addDocument(book_doc)
+ del book_doc
+
+ self.index_content(book, book_fields=[meta_fields['title'], meta_fields['authors']])
+
+ master_tags = [
+ 'opowiadanie',
+ 'powiesc',
+ 'dramat_wierszowany_l',
+ 'dramat_wierszowany_lp',
+ 'dramat_wspolczesny', 'liryka_l', 'liryka_lp',
+ 'wywiad'
+ ]
+
+ skip_header_tags = ['autor_utworu', 'nazwa_utworu', 'dzielo_nadrzedne']
+
+ def extract_metadata(self, book, book_info=None):
+ """
+ Extract metadata from book and returns a map of fields keyed by fieldname
+ """
+ fields = {}
+
+ if book_info is None:
+ book_info = dcparser.parse(open(book.xml_file.path))
+
+ fields['slug'] = Field("slug", book.slug, Field.Store.NO, Field.Index.ANALYZED_NO_NORMS)
+ fields['tags'] = self.add_gaps([Field("tags", t.name, Field.Store.NO, Field.Index.ANALYZED) for t in book.tags], 'tags')
+ fields['is_book'] = Field("is_book", 'true', Field.Store.NO, Field.Index.NOT_ANALYZED)
+
+ # validator, name
+ for field in dcparser.BookInfo.FIELDS:
+ if hasattr(book_info, field.name):
+ if not getattr(book_info, field.name):
+ continue
+ # since no type information is available, we use validator
+ type_indicator = field.validator
+ if type_indicator == dcparser.as_unicode:
+ s = getattr(book_info, field.name)
+ if field.multiple:
+ s = ', '.join(s)
+ try:
+ fields[field.name] = Field(field.name, s, Field.Store.NO, Field.Index.ANALYZED)
+ except JavaError as je:
+ raise Exception("failed to add field: %s = '%s', %s(%s)" % (field.name, s, je.message, je.args))
+ elif type_indicator == dcparser.as_person:
+ p = getattr(book_info, field.name)
+ if isinstance(p, dcparser.Person):
+ persons = unicode(p)
+ else:
+ persons = ', '.join(map(unicode, p))
+ fields[field.name] = Field(field.name, persons, Field.Store.NO, Field.Index.ANALYZED)
+ elif type_indicator == dcparser.as_date:
+ dt = getattr(book_info, field.name)
+ fields[field.name] = Field(field.name, "%04d%02d%02d" %\
+ (dt.year, dt.month, dt.day), Field.Store.NO, Field.Index.NOT_ANALYZED)
+
+ return fields
+
+ def add_gaps(self, fields, fieldname):
+ """
+ Interposes a list of fields with gap-fields, which are indexed spaces and returns it.
+ This allows for doing phrase queries which do not overlap the gaps (when slop is 0).
+ """
+ def gap():
+ while True:
+ yield Field(fieldname, ' ', Field.Store.NO, Field.Index.NOT_ANALYZED)
+ return reduce(lambda a, b: a + b, zip(fields, gap()))[0:-1]
+
+ def get_master(self, root):
+ """
+ Returns the first master tag from an etree.
+ """
+ for master in root.iter():
+ if master.tag in self.master_tags:
+ return master
+
+ def index_content(self, book, book_fields=[]):
+ """
+ Walks the book XML and extract content from it.
+ Adds parts for each header tag and for each fragment.
+ """
+ wld = WLDocument.from_file(book.xml_file.path, parse_dublincore=False)
+ root = wld.edoc.getroot()
+
+ master = self.get_master(root)
+ if master is None:
+ return []
+
+ def walker(node):
+ yield node, None
+ for child in list(node):
+ for b, e in walker(child):
+ yield b, e
+ yield None, node
+ return
+
+ def fix_format(text):
+ return re.sub("(?m)/$", "", text)
+
+ def add_part(snippets, **fields):
+ doc = self.create_book_doc(book)
+ for f in book_fields:
+ doc.add(f)
+
+ doc.add(NumericField('header_index', Field.Store.YES, True).setIntValue(fields["header_index"]))
+ doc.add(NumericField("header_span", Field.Store.YES, True)\
+ .setIntValue('header_span' in fields and fields['header_span'] or 1))
+ doc.add(Field('header_type', fields["header_type"], Field.Store.YES, Field.Index.NOT_ANALYZED))
+
+ doc.add(Field('content', fields["content"], Field.Store.NO, Field.Index.ANALYZED, \
+ Field.TermVector.WITH_POSITIONS_OFFSETS))
+
+ snip_pos = snippets.add(fields["content"])
+ doc.add(NumericField("snippets_position", Field.Store.YES, True).setIntValue(snip_pos[0]))
+ doc.add(NumericField("snippets_length", Field.Store.YES, True).setIntValue(snip_pos[1]))
+
+ if 'fragment_anchor' in fields:
+ doc.add(Field("fragment_anchor", fields['fragment_anchor'],
+ Field.Store.YES, Field.Index.NOT_ANALYZED))
+
+ if 'themes' in fields:
+ themes, themes_pl = zip(*[
+ (Field("themes", theme, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS),
+ Field("themes_pl", theme, Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS))
+ for theme in fields['themes']])
+
+ themes = self.add_gaps(themes, 'themes')
+ themes_pl = self.add_gaps(themes_pl, 'themes_pl')
+
+ for t in themes:
+ doc.add(t)
+ for t in themes_pl:
+ doc.add(t)
+
+ return doc
+
+ def give_me_utf8(s):
+ if isinstance(s, unicode):
+ return s.encode('utf-8')
+ else:
+ return s
+
+ fragments = {}
+ snippets = Snippets(book.id).open('w')
+ try:
+ for header, position in zip(list(master), range(len(master))):
+
+ if header.tag in self.skip_header_tags:
+ continue
+
+ content = u' '.join([t for t in header.itertext()])
+ content = fix_format(content)
+
+ doc = add_part(snippets, header_index=position, header_type=header.tag, content=content)
+
+ self.index.addDocument(doc)
+
+ for start, end in walker(header):
+ if start is not None and start.tag == 'begin':
+ fid = start.attrib['id'][1:]
+ fragments[fid] = {'content': [], 'themes': [], 'start_section': position, 'start_header': header.tag}
+ fragments[fid]['content'].append(start.tail)
+ elif start is not None and start.tag == 'motyw':
+ fid = start.attrib['id'][1:]
+ if start.text is not None:
+ fragments[fid]['themes'] += map(str.strip, map(give_me_utf8, start.text.split(',')))
+ fragments[fid]['content'].append(start.tail)
+ elif start is not None and start.tag == 'end':
+ fid = start.attrib['id'][1:]
+ if fid not in fragments:
+ continue # a broken <end> node, skip it
+ frag = fragments[fid]
+ if frag['themes'] == []:
+ continue # empty themes list.
+ del fragments[fid]
+
+ def jstr(l):
+ return u' '.join(map(
+ lambda x: x == None and u'(none)' or unicode(x),
+ l))
+
+ doc = add_part(snippets,
+ header_type=frag['start_header'],
+ header_index=frag['start_section'],
+ header_span=position - frag['start_section'] + 1,
+ fragment_anchor=fid,
+ content=u' '.join(filter(lambda s: s is not None, frag['content'])),
+ themes=frag['themes'])
+
+ self.index.addDocument(doc)
+ elif start is not None:
+ for frag in fragments.values():
+ frag['content'].append(start.text)
+ elif end is not None:
+ for frag in fragments.values():
+ frag['content'].append(end.tail)
+ finally:
+ snippets.close()
+
+
+def log_exception_wrapper(f):
+ def _wrap(*a):
+ try:
+ f(*a)
+ except Exception, e:
+ print("Error in indexing thread: %s" % e)
+ traceback.print_exc()
+ raise e
+ return _wrap
+
+
+class ReusableIndex(Index):
+ """
+ Works like index, but does not close/optimize Lucene index
+ until program exit (uses atexit hook).
+ This is usefull for importbooks command.
+
+ if you cannot rely on atexit, use ReusableIndex.close_reusable() yourself.
+ """
+ index = None
+
+ def open(self, analyzer=None, threads=4):
+ if ReusableIndex.index is not None:
+ self.index = ReusableIndex.index
+ else:
+ print("opening index")
+ Index.open(self, analyzer)
+ ReusableIndex.index = self.index
+ atexit.register(ReusableIndex.close_reusable)
+
+ # def index_book(self, *args, **kw):
+ # job = ReusableIndex.pool.apply_async(log_exception_wrapper(Index.index_book), (self,) + args, kw)
+ # ReusableIndex.pool_jobs.append(job)
+
+ @staticmethod
+ def close_reusable():
+ if ReusableIndex.index is not None:
+ ReusableIndex.index.optimize()
+ ReusableIndex.index.close()
+ ReusableIndex.index = None
+
+ def close(self):
+ pass
+
+
+class JoinSearch(object):
+ """
+ This mixin could be used to handle block join queries.
+ (currently unused)
+ """
+ def __init__(self, *args, **kw):
+ super(JoinSearch, self).__init__(*args, **kw)
+
+ def wrapjoins(self, query, fields=[]):
+ """
+ This functions modifies the query in a recursive way,
+ so Term and Phrase Queries contained, which match
+ provided fields are wrapped in a BlockJoinQuery,
+ and so delegated to children documents.
+ """
+ if BooleanQuery.instance_(query):
+ qs = BooleanQuery.cast_(query)
+ for clause in qs:
+ clause = BooleanClause.cast_(clause)
+ clause.setQuery(self.wrapjoins(clause.getQuery(), fields))
+ return qs
+ else:
+ termset = HashSet()
+ query.extractTerms(termset)
+ for t in termset:
+ t = Term.cast_(t)
+ if t.field() not in fields:
+ return query
+ return BlockJoinQuery(query, self.parent_filter,
+ BlockJoinQuery.ScoreMode.Total)
+
+ def bsearch(self, query, max_results=50):
+ q = self.query(query)
+ bjq = BlockJoinQuery(q, self.parent_filter, BlockJoinQuery.ScoreMode.Avg)
+
+ tops = self.searcher.search(bjq, max_results)
+ bks = []
+ for found in tops.scoreDocs:
+ doc = self.searcher.doc(found.doc)
+ bks.append(catalogue.models.Book.objects.get(id=doc.get("book_id")))
+ return (bks, tops.totalHits)
+
+
+class SearchResult(object):
+ def __init__(self, searcher, scoreDocs, score=None, how_found=None, snippets=None):
+ if score:
+ self.score = score
+ else:
+ self.score = scoreDocs.score
+
+ self._hits = []
+ self.hits = None # processed hits
+
+ stored = searcher.doc(scoreDocs.doc)
+ self.book_id = int(stored.get("book_id"))
+
+ header_type = stored.get("header_type")
+ if not header_type:
+ return
+
+ sec = (header_type, int(stored.get("header_index")))
+ header_span = stored.get('header_span')
+ header_span = header_span is not None and int(header_span) or 1
+
+ fragment = stored.get("fragment_anchor")
+
+ hit = (sec + (header_span,), fragment, scoreDocs.score, {'how_found': how_found, 'snippets': snippets and [snippets] or []})
+
+ self._hits.append(hit)
+
+ def merge(self, other):
+ if self.book_id != other.book_id:
+ raise ValueError("this search result is or book %d; tried to merge with %d" % (self.book_id, other.book_id))
+ self._hits += other._hits
+ if other.score > self.score:
+ self.score = other.score
+ return self
+
+ def get_book(self):
+ return catalogue.models.Book.objects.get(id=self.book_id)
+
+ book = property(get_book)
+
+ def process_hits(self):
+ POSITION = 0
+ FRAGMENT = 1
+ POSITION_INDEX = 1
+ POSITION_SPAN = 2
+ SCORE = 2
+ OTHER = 3
+
+ # to sections and fragments
+ frags = filter(lambda r: r[FRAGMENT] is not None, self._hits)
+ sect = filter(lambda r: r[FRAGMENT] is None, self._hits)
+ sect = filter(lambda s: 0 == len(filter(
+ lambda f: s[POSITION][POSITION_INDEX] >= f[POSITION][POSITION_INDEX]
+ and s[POSITION][POSITION_INDEX] < f[POSITION][POSITION_INDEX] + f[POSITION][POSITION_SPAN],
+ frags)), sect)
+
+ hits = []
+
+ # remove duplicate fragments
+ fragments = {}
+ for f in frags:
+ fid = f[FRAGMENT]
+ if fid in fragments:
+ if fragments[fid][SCORE] >= f[SCORE]:
+ continue
+ fragments[fid] = f
+ frags = fragments.values()
+
+ # remove duplicate sections
+ sections = {}
+
+ for s in sect:
+ si = s[POSITION][POSITION_INDEX]
+ # skip existing
+ if si in sections:
+ if sections[si]['score'] >= s[SCORE]:
+ continue
+
+ m = {'score': s[SCORE],
+ 'section_number': s[POSITION][POSITION_INDEX] + 1,
+ }
+ m.update(s[OTHER])
+ sections[si] = m
+
+ hits = sections.values()
+
+ for f in frags:
+ frag = catalogue.models.Fragment.objects.get(anchor=f[FRAGMENT])
+ m = {'score': f[SCORE],
+ 'fragment': frag,
+ 'themes': frag.tags.filter(category='theme')
+ }
+ m.update(f[OTHER])
+ hits.append(m)
+
+ hits.sort(lambda a, b: cmp(a['score'], b['score']), reverse=True)
+
+ self.hits = hits
+
+ return self
+
+ def __unicode__(self):
+ return u'SearchResult(book_id=%d, score=%d)' % (self.book_id, self.score)
+
+ @staticmethod
+ def aggregate(*result_lists):
+ books = {}
+ for rl in result_lists:
+ for r in rl:
+ if r.book_id in books:
+ books[r.book_id].merge(r)
+ #print(u"already have one with score %f, and this one has score %f" % (books[book.id][0], found.score))
+ else:
+ books[r.book_id] = r
+ return books.values()
+
+ def __cmp__(self, other):
+ return cmp(self.score, other.score)
+
+
+class Hint(object):
+ """
+ Given some hint information (information we already know about)
+ our search target - like author, title (specific book), epoch, genre, kind
+ we can narrow down search using filters.
+ """
+ def __init__(self, search):
+ """
+ Accepts a Searcher instance.
+ """
+ self.search = search
+ self.book_tags = {}
+ self.part_tags = []
+ self._books = []
+
+ def books(self, *books):
+ """
+ Give a hint that we search these books.
+ """
+ self._books = books
+
+ def tags(self, tags):
+ """
+ Give a hint that these Tag objects (a list of)
+ is necessary.
+ """
+ for t in tags:
+ if t.category in ['author', 'title', 'epoch', 'genre', 'kind']:
+ lst = self.book_tags.get(t.category, [])
+ lst.append(t)
+ self.book_tags[t.category] = lst
+ if t.category in ['theme', 'theme_pl']:
+ self.part_tags.append(t)
+
+ def tag_filter(self, tags, field='tags'):
+ """
+ Given a lsit of tags and an optional field (but they are normally in tags field)
+ returns a filter accepting only books with specific tags.
+ """
+ q = BooleanQuery()
+
+ for tag in tags:
+ toks = self.search.get_tokens(tag.name, field=field)
+ tag_phrase = PhraseQuery()
+ for tok in toks:
+ tag_phrase.add(Term(field, tok))
+ q.add(BooleanClause(tag_phrase, BooleanClause.Occur.MUST))
+
+ return QueryWrapperFilter(q)
+
+ def book_filter(self):
+ """
+ Filters using book tags (all tag kinds except a theme)
+ """
+ tags = reduce(lambda a, b: a + b, self.book_tags.values(), [])
+ if tags:
+ return self.tag_filter(tags)
+ else:
+ return None
+
+ def part_filter(self):
+ """
+ This filter can be used to look for book parts.
+ It filters on book id and/or themes.
+ """
+ fs = []
+ if self.part_tags:
+ fs.append(self.tag_filter(self.part_tags, field='themes'))
+
+ if self._books != []:
+ bf = BooleanFilter()
+ for b in self._books:
+ id_filter = NumericRangeFilter.newIntRange('book_id', b.id, b.id, True, True)
+ bf.add(FilterClause(id_filter, BooleanClause.Occur.SHOULD))
+ fs.append(bf)
+
+ return Search.chain_filters(fs)
+
+ def should_search_for_book(self):
+ return self._books == []
+
+ def just_search_in(self, all):
+ """Holds logic to figure out which indexes should be search, when we have some hinst already"""
+ some = []
+ for field in all:
+ if field == 'authors' and 'author' in self.book_tags:
+ continue
+ if field == 'title' and self._books != []:
+ continue
+ if (field == 'themes' or field == 'themes_pl') and self.part_tags:
+ continue
+ some.append(field)
+ return some
+
+
+class Search(IndexStore):
+ """
+ Search facilities.
+ """
+ def __init__(self, default_field="content"):
+ IndexStore.__init__(self)
+ self.analyzer = WLAnalyzer() # PolishAnalyzer(Version.LUCENE_34)
+ # self.analyzer = WLAnalyzer()
+ self.searcher = IndexSearcher(self.store, True)
+ self.parser = QueryParser(Version.LUCENE_34, default_field,
+ self.analyzer)
+
+ self.parent_filter = TermsFilter()
+ self.parent_filter.addTerm(Term("is_book", "true"))
+
+ def query(self, query):
+ """Parse query in default Lucene Syntax. (for humans)
+ """
+ return self.parser.parse(query)
+
+ def simple_search(self, query, max_results=50):
+ """Runs a query for books using lucene syntax. (for humans)
+ Returns (books, total_hits)
+ """
+
+ tops = self.searcher.search(self.query(query), max_results)
+ bks = []
+ for found in tops.scoreDocs:
+ doc = self.searcher.doc(found.doc)
+ bks.append(catalogue.models.Book.objects.get(id=doc.get("book_id")))
+ return (bks, tops.totalHits)
+
+ def get_tokens(self, searched, field='content'):
+ """returns tokens analyzed by a proper (for a field) analyzer
+ argument can be: StringReader, string/unicode, or tokens. In the last case
+ they will just be returned (so we can reuse tokens, if we don't change the analyzer)
+ """
+ if isinstance(searched, str) or isinstance(searched, unicode):
+ searched = StringReader(searched)
+ elif isinstance(searched, list):
+ return searched
+
+ searched.reset()
+ tokens = self.analyzer.reusableTokenStream(field, searched)
+ toks = []
+ while tokens.incrementToken():
+ cta = tokens.getAttribute(CharTermAttribute.class_)
+ toks.append(cta.toString())
+ return toks
+
+ def fuzziness(self, fuzzy):
+ """Helper method to sanitize fuzziness"""
+ if not fuzzy:
+ return None
+ if isinstance(fuzzy, float) and fuzzy > 0.0 and fuzzy <= 1.0:
+ return fuzzy
+ else:
+ return 0.5
+
+ def make_phrase(self, tokens, field='content', slop=2, fuzzy=False):
+ """
+ Return a PhraseQuery with a series of tokens.
+ """
+ if fuzzy:
+ phrase = MultiPhraseQuery()
+ for t in tokens:
+ term = Term(field, t)
+ fuzzterm = FuzzyTermEnum(self.searcher.getIndexReader(), term, self.fuzziness(fuzzy))
+ fuzzterms = []
+
+ while True:
+ # print("fuzz %s" % unicode(fuzzterm.term()).encode('utf-8'))
+ ft = fuzzterm.term()
+ if ft:
+ fuzzterms.append(ft)
+ if not fuzzterm.next(): break
+ if fuzzterms:
+ phrase.add(JArray('object')(fuzzterms, Term))
+ else:
+ phrase.add(term)
+ else:
+ phrase = PhraseQuery()
+ phrase.setSlop(slop)
+ for t in tokens:
+ term = Term(field, t)
+ phrase.add(term)
+ return phrase
+
+ def make_term_query(self, tokens, field='content', modal=BooleanClause.Occur.SHOULD, fuzzy=False):
+ """
+ Returns term queries joined by boolean query.
+ modal - applies to boolean query
+ fuzzy - should the query by fuzzy.
+ """
+ q = BooleanQuery()
+ for t in tokens:
+ term = Term(field, t)
+ if fuzzy:
+ term = FuzzyQuery(term, self.fuzziness(fuzzy))
+ else:
+ term = TermQuery(term)
+ q.add(BooleanClause(term, modal))
+ return q
+
+ # def content_query(self, query):
+ # return BlockJoinQuery(query, self.parent_filter,
+ # BlockJoinQuery.ScoreMode.Total)
+
+ def search_perfect_book(self, searched, max_results=20, fuzzy=False, hint=None):
+ """
+ Search for perfect book matches. Just see if the query matches with some author or title,
+ taking hints into account.
+ """
+ fields_to_search = ['authors', 'title']
+ only_in = None
+ if hint:
+ if not hint.should_search_for_book():
+ return []
+ fields_to_search = hint.just_search_in(fields_to_search)
+ only_in = hint.book_filter()
+
+ qrys = [self.make_phrase(self.get_tokens(searched, field=fld), field=fld, fuzzy=fuzzy) for fld in fields_to_search]
+
+ books = []
+ for q in qrys:
+ top = self.searcher.search(q,
+ self.chain_filters([only_in, self.term_filter(Term('is_book', 'true'))]),
+ max_results)
+ for found in top.scoreDocs:
+ books.append(SearchResult(self.searcher, found))
+ return books
+
+ def search_book(self, searched, max_results=20, fuzzy=False, hint=None):
+ fields_to_search = ['tags', 'authors', 'title']
+
+ only_in = None
+ if hint:
+ if not hint.should_search_for_book():
+ return []
+ fields_to_search = hint.just_search_in(fields_to_search)
+ only_in = hint.book_filter()
+
+ tokens = self.get_tokens(searched, field='SIMPLE')
+
+ q = BooleanQuery()
+
+ for fld in fields_to_search:
+ q.add(BooleanClause(self.make_term_query(tokens, field=fld,
+ fuzzy=fuzzy), BooleanClause.Occur.SHOULD))
+
+ books = []
+ top = self.searcher.search(q,
+ self.chain_filters([only_in, self.term_filter(Term('is_book', 'true'))]),
+ max_results)
+ for found in top.scoreDocs:
+ books.append(SearchResult(self.searcher, found))
+
+ return books
+
+ def search_perfect_parts(self, searched, max_results=20, fuzzy=False, hint=None):
+ """
+ Search for book parts which containt a phrase perfectly matching (with a slop of 2, default for make_phrase())
+ some part/fragment of the book.
+ """
+ qrys = [self.make_phrase(self.get_tokens(searched), field=fld, fuzzy=fuzzy) for fld in ['content']]
+
+ flt = None
+ if hint:
+ flt = hint.part_filter()
+
+ books = []
+ for q in qrys:
+ top = self.searcher.search(q,
+ self.chain_filters([self.term_filter(Term('is_book', 'true'), inverse=True),
+ flt]),
+ max_results)
+ for found in top.scoreDocs:
+ books.append(SearchResult(self.searcher, found, snippets=self.get_snippets(found, q)))
+
+ return books
+
+ def search_everywhere(self, searched, max_results=20, fuzzy=False, hint=None):
+ """
+ Tries to use search terms to match different fields of book (or its parts).
+ E.g. one word can be an author survey, another be a part of the title, and the rest
+ are some words from third chapter.
+ """
+ books = []
+ only_in = None
+
+ if hint:
+ only_in = hint.part_filter()
+
+ # content only query : themes x content
+ q = BooleanQuery()
+
+ tokens_pl = self.get_tokens(searched, field='content')
+ tokens = self.get_tokens(searched, field='SIMPLE')
+
+ # only search in themes when we do not already filter by themes
+ if hint is None or hint.just_search_in(['themes']) != []:
+ q.add(BooleanClause(self.make_term_query(tokens_pl, field='themes_pl',
+ fuzzy=fuzzy), BooleanClause.Occur.MUST))
+
+ q.add(BooleanClause(self.make_term_query(tokens_pl, field='content',
+ fuzzy=fuzzy), BooleanClause.Occur.SHOULD))
+
+ topDocs = self.searcher.search(q, only_in, max_results)
+ for found in topDocs.scoreDocs:
+ books.append(SearchResult(self.searcher, found))
+ print "* %s theme x content: %s" % (searched, books[-1]._hits)
+
+ # query themes/content x author/title/tags
+ q = BooleanQuery()
+ in_content = BooleanQuery()
+ in_meta = BooleanQuery()
+
+ for fld in ['themes_pl', 'content']:
+ in_content.add(BooleanClause(self.make_term_query(tokens_pl, field=fld, fuzzy=False), BooleanClause.Occur.SHOULD))
+
+ for fld in ['tags', 'authors', 'title']:
+ in_meta.add(BooleanClause(self.make_term_query(tokens, field=fld, fuzzy=False), BooleanClause.Occur.SHOULD))
+
+ q.add(BooleanClause(in_content, BooleanClause.Occur.MUST))
+ q.add(BooleanClause(in_meta, BooleanClause.Occur.SHOULD))
+
+ topDocs = self.searcher.search(q, only_in, max_results)
+ for found in topDocs.scoreDocs:
+ books.append(SearchResult(self.searcher, found))
+ print "* %s scatter search: %s" % (searched, books[-1]._hits)
+
+ return books
+
+ # def multisearch(self, query, max_results=50):
+ # """
+ # Search strategy:
+ # - (phrase) OR -> content
+ # -> title
+ # -> authors
+ # - (keywords) -> authors
+ # -> motyw
+ # -> tags
+ # -> content
+ # """
+ # queryreader = StringReader(query)
+ # tokens = self.get_tokens(queryreader)
+
+ # top_level = BooleanQuery()
+ # Should = BooleanClause.Occur.SHOULD
+
+ # phrase_level = BooleanQuery()
+ # phrase_level.setBoost(1.3)
+
+ # p_content = self.make_phrase(tokens, joined=True)
+ # p_title = self.make_phrase(tokens, 'title')
+ # p_author = self.make_phrase(tokens, 'author')
+
+ # phrase_level.add(BooleanClause(p_content, Should))
+ # phrase_level.add(BooleanClause(p_title, Should))
+ # phrase_level.add(BooleanClause(p_author, Should))
+
+ # kw_level = BooleanQuery()
+
+ # kw_level.add(self.make_term_query(tokens, 'author'), Should)
+ # j_themes = self.make_term_query(tokens, 'themes', joined=True)
+ # kw_level.add(j_themes, Should)
+ # kw_level.add(self.make_term_query(tokens, 'tags'), Should)
+ # j_con = self.make_term_query(tokens, joined=True)
+ # kw_level.add(j_con, Should)
+
+ # top_level.add(BooleanClause(phrase_level, Should))
+ # top_level.add(BooleanClause(kw_level, Should))
+
+ # return None
+
+ def get_snippets(self, scoreDoc, query, field='content'):
+ """
+ Returns a snippet for found scoreDoc.
+ """
+ htmlFormatter = SimpleHTMLFormatter()
+ highlighter = Highlighter(htmlFormatter, QueryScorer(query))
+
+ stored = self.searcher.doc(scoreDoc.doc)
+
+ # locate content.
+ snippets = Snippets(stored.get('book_id')).open()
+ try:
+ text = snippets.get((int(stored.get('snippets_position')),
+ int(stored.get('snippets_length'))))
+ finally:
+ snippets.close()
+
+ tokenStream = TokenSources.getAnyTokenStream(self.searcher.getIndexReader(), scoreDoc.doc, field, self.analyzer)
+ # highlighter.getBestTextFragments(tokenStream, text, False, 10)
+ snip = highlighter.getBestFragments(tokenStream, text, 3, "...")
+
+ return snip
+
+ @staticmethod
+ def enum_to_array(enum):
+ """
+ Converts a lucene TermEnum to array of Terms, suitable for
+ addition to queries
+ """
+ terms = []
+
+ while True:
+ t = enum.term()
+ if t:
+ terms.append(t)
+ if not enum.next(): break
+
+ if terms:
+ return JArray('object')(terms, Term)
+
+ def search_tags(self, query, filter=None, max_results=40):
+ """
+ Search for Tag objects using query.
+ """
+ tops = self.searcher.search(query, filter, max_results)
+
+ tags = []
+ for found in tops.scoreDocs:
+ doc = self.searcher.doc(found.doc)
+ tag = catalogue.models.Tag.objects.get(id=doc.get("tag_id"))
+ tags.append(tag)
+ print "%s (%d) -> %f" % (tag, tag.id, found.score)
+
+ return tags
+
+ def search_books(self, query, filter=None, max_results=10):
+ """
+ Searches for Book objects using query
+ """
+ bks = []
+ tops = self.searcher.search(query, filter, max_results)
+ for found in tops.scoreDocs:
+ doc = self.searcher.doc(found.doc)
+ bks.append(catalogue.models.Book.objects.get(id=doc.get("book_id")))
+ return bks
+
+ def create_prefix_phrase(self, toks, field):
+ q = MultiPhraseQuery()
+ for i in range(len(toks)):
+ t = Term(field, toks[i])
+ if i == len(toks) - 1:
+ pterms = Search.enum_to_array(PrefixTermEnum(self.searcher.getIndexReader(), t))
+ if pterms:
+ q.add(pterms)
+ else:
+ q.add(t)
+ else:
+ q.add(t)
+ return q
+
+ @staticmethod
+ def term_filter(term, inverse=False):
+ only_term = TermsFilter()
+ only_term.addTerm(term)
+
+ if inverse:
+ neg = BooleanFilter()
+ neg.add(FilterClause(only_term, BooleanClause.Occur.MUST_NOT))
+ only_term = neg
+
+ return only_term
+
+ def hint_tags(self, string, max_results=50):
+ """
+ Return auto-complete hints for tags
+ using prefix search.
+ """
+ toks = self.get_tokens(string, field='SIMPLE')
+ top = BooleanQuery()
+
+ for field in ['tag_name', 'tag_name_pl']:
+ q = self.create_prefix_phrase(toks, field)
+ top.add(BooleanClause(q, BooleanClause.Occur.SHOULD))
+
+ no_book_cat = self.term_filter(Term("tag_category", "book"), inverse=True)
+
+ return self.search_tags(top, no_book_cat, max_results=max_results)
+
+ def hint_books(self, string, max_results=50):
+ """
+ Returns auto-complete hints for book titles
+ Because we do not index 'pseudo' title-tags.
+ Prefix search.
+ """
+ toks = self.get_tokens(string, field='SIMPLE')
+
+ q = self.create_prefix_phrase(toks, 'title')
+
+ return self.search_books(q, self.term_filter(Term("is_book", "true")), max_results=max_results)
+
+ @staticmethod
+ def chain_filters(filters, op=ChainedFilter.AND):
+ """
+ Chains a filter list together
+ """
+ filters = filter(lambda x: x is not None, filters)
+ if not filters:
+ return None
+ chf = ChainedFilter(JArray('object')(filters, Filter), op)
+ return chf
+
+ def filtered_categories(self, tags):
+ """
+ Return a list of tag categories, present in tags list.
+ """
+ cats = {}
+ for t in tags:
+ cats[t.category] = True
+ return cats.keys()
+
+ def hint(self):
+ return Hint(self)
--- /dev/null
+
+from django.core.management.base import BaseCommand
+from search import IndexChecker
+
+class Command(BaseCommand):
+ help = 'Check Lucene search index'
+ args = ''
+
+ def handle(self, *args, **opts):
+ checker = IndexChecker()
+ status = checker.check()
+ if status.clean:
+ print "No problems found."
+ else:
+ if status.missingSegments:
+ print "Unable to locate."
+ print "Number of bad segments: %d / %d (max segment name is %d)" % \
+ (status.numBadSegments, status.numSegments, status.maxSegmentName)
+ print "Total lost documents (due to bad segments) %d" % status.totLoseDocCount
+ if not status.validCounter:
+ print "Segment counter is not valid."
+
--- /dev/null
+
+from django.core.management.base import BaseCommand
+from search import Index
+
+class Command(BaseCommand):
+ help = 'Optimize Lucene search index'
+ args = ''
+
+ def handle(self, *args, **opts):
+ index = Index()
+ index.open()
+ try:
+ index.optimize()
+ finally:
+ index.close()
--- /dev/null
+from django.core.management.base import BaseCommand
+
+class Command(BaseCommand):
+ help = 'Reindex everything.'
+ args = ''
+
+ def handle(self, *args, **opts):
+ from catalogue.models import Book
+ import search
+ idx = search.ReusableIndex()
+ idx.open()
+
+ if args:
+ books = []
+ for a in args:
+ books += Book.objects.filter(slug=a).all()
+ else:
+ books = Book.objects.all()
+
+ for b in books:
+ print b.title
+ idx.index_book(b, None)
+ print 'Reindexing tags.'
+ idx.index_tags()
+ idx.close()
--- /dev/null
+from search.tests.index import *
--- /dev/null
+<?xml version='1.0' encoding='utf-8'?>
+<utwor>
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<rdf:Description rdf:about="http://wiki.wolnepodreczniki.pl/index.php?title=Lektury:S%C4%99p-Szarzy%C5%84ski/Rytmy/Fraszka_do_Anusie">
+<dc:creator xml:lang="pl">Sęp Szarzyński, Mikołaj</dc:creator>
+<dc:title xml:lang="pl">Fraszka do Anusie</dc:title>
+<dc:contributor.editor xml:lang="pl">Sekuła, Aleksandra</dc:contributor.editor>
+<dc:contributor.technical_editor xml:lang="pl">Sutkowska, Olga</dc:contributor.technical_editor>
+<dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+<dc:subject.period xml:lang="pl">Barok</dc:subject.period>
+<dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+<dc:subject.genre xml:lang="pl">Fraszka</dc:subject.genre>
+<dc:description xml:lang="pl">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description>
+<dc:identifier.url xml:lang="pl">http://wolnelektury.pl/katalog/lektura/fraszka-do-anusie</dc:identifier.url>
+<dc:source.URL xml:lang="pl">http://www.polona.pl/Content/8759</dc:source.URL>
+<dc:source xml:lang="pl">Szarzyński Sęp, Mikołaj (ca 1550-1581), Rytmy abo Wiersze polskie w wyborze, E. Wende, Warszawa, 1914</dc:source>
+<dc:rights xml:lang="pl">Domena publiczna - Mikołaj Sęp Szarzyński zm. 1581</dc:rights>
+<dc:date.pd xml:lang="pl">1581</dc:date.pd>
+<dc:format xml:lang="pl">xml</dc:format>
+<dc:type xml:lang="pl">text</dc:type>
+<dc:type xml:lang="en">text</dc:type>
+<dc:date xml:lang="pl">2008-12-29</dc:date>
+<dc:audience xml:lang="pl">L</dc:audience>
+<dc:audience xml:lang="pl">L</dc:audience>
+<dc:language xml:lang="pl">pol</dc:language>
+</rdf:Description>
+</rdf:RDF>
+ <liryka_l>
+
+<autor_utworu>Mikołaj Sęp Szarzyński</autor_utworu>
+
+<nazwa_utworu>Fraszka do Anusie</nazwa_utworu>
+
+
+
+<strofa><begin id="b1230084410751"/><motyw id="m1230084410751">Kochanek, Łzy, Miłość, Oko, Serce, Wzrok</motyw>Jeśli oczu hamować swoich nie umiały/
+Leśnych krynic boginie, aby nie płakały,/
+Gdy baczyły<pe><slowo_obce>baczyły</slowo_obce> --- tu: zobaczyły, patrzyły na.</pe> przy studni Narcyza pięknego,/
+A on umarł prze miłość oblicza swojego;/
+Jeśli nieśmiertelnym stanom żałość rozkazuje,/
+Gdy niebaczna fortuna co niesłusznie psuje:</strofa>
+
+<strofa>Jakoż ja mam hamować, by na lice moje/
+Z oczu smutnych żałośne nie płynęły zdroje?/
+Jako serce powściągać, aby nie wzdychało/
+I od ciężkiej żałości omdlewać nie miało?<end id="e1230084410751"/></strofa>
+
+</liryka_l>
+</utwor>
--- /dev/null
+<?xml version='1.0' encoding='utf-8'?>
+<utwor>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
+<rdf:Description rdf:about="">
+<dc:creator xml:lang="pl">Kochanowski, Jan</dc:creator>
+<dc:title xml:lang="pl">Fraszki</dc:title>
+<dc:relation.hasPart xml:lang="pl">http://wolnelektury.pl/katalog/lektura/fraszka-do-anusie</dc:relation.hasPart>
+
+<dc:publisher xml:lang="pl">Fundacja Nowoczesna Polska</dc:publisher>
+<dc:subject.period xml:lang="pl">Renesans</dc:subject.period>
+<dc:subject.type xml:lang="pl">Liryka</dc:subject.type>
+<dc:subject.genre xml:lang="pl">Fraszka</dc:subject.genre>
+
+<dc:description xml:lang="pl"></dc:description>
+<dc:identifier.url xml:lang="pl">http://wolnelektury.pl/lektura/fraszki</dc:identifier.url>
+<dc:source xml:lang="pl"></dc:source>
+<dc:rights xml:lang="pl">Domena publiczna - Jan Kochanowski zm. 1584</dc:rights>
+<dc:date.pd xml:lang="pl">1584</dc:date.pd>
+<dc:format xml:lang="pl">xml</dc:format>
+<dc:type xml:lang="pl">text</dc:type>
+
+<dc:type xml:lang="en">text</dc:type>
+<dc:date xml:lang="pl">2008-11-12</dc:date>
+<dc:language xml:lang="pl">pol</dc:language>
+</rdf:Description>
+</rdf:RDF>
+</utwor>
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from __future__ import with_statement
+
+from django.conf import settings
+from search import Index, Search, IndexStore, JVM, SearchResult
+from catalogue import models
+from catalogue.test_utils import WLTestCase
+from lucene import PolishAnalyzer, Version
+#from nose.tools import raises
+from os import path
+
+
+class BookSearchTests(WLTestCase):
+ def setUp(self):
+ JVM.attachCurrentThread()
+ WLTestCase.setUp(self)
+ settings.SEARCH_INDEX = path.join(settings.MEDIA_ROOT, 'search')
+
+ txt = path.join(path.dirname(__file__), 'files/fraszka-do-anusie.xml')
+ self.book = models.Book.from_xml_file(txt)
+
+ index = Index()
+ index.open()
+ try:
+ index.index_book(self.book)
+ except:
+ index.close()
+
+ self.search = Search()
+
+ def test_search_perfect_book_author(self):
+ books = self.search.search_perfect_book("sęp szarzyński")
+ assert len(books) == 1
+ assert books[0].book_id == self.book.id
+
+ def test_search_perfect_book_title(self):
+ books = self.search.search_perfect_book("fraszka anusie")
+ assert len(books) == 1
+ assert books[0].book_id == self.book.id
+
+ def test_search_perfect_parts(self):
+ books = self.search.search_perfect_parts("Jakoż hamować")
+ assert len(books) == 2
+ for b in books:
+ b.book_id == self.book.id
+ a = SearchResult.aggregate(books)
+ # just one fragment hit.
+ assert len(filter(lambda x: x[1], a[0].hits)) == 1
+ print a[0].process_hits()
+
+ def test_search_perfect_author_title(self):
+ books = self.search.search_perfect_book("szarzyński anusie")
+ assert books == []
+
+ books = self.search.search_book("szarzyński anusie")
+ assert len(books) == 1
+
+ books = self.search.search_book("szarzyński fraszka")
+ assert len(books) == 1
+
+ def test_search_everywhere(self):
+ books = self.search.search_everywhere("szarzyński kochanek")
+ print 'szarzyński kochanek %s' % [b.hits for b in books]
+
+ books = self.search.search_everywhere("szarzyński narcyz")
+ print 'szarzyński narcyz %s' % [b.hits for b in books]
+
+ books = self.search.search_everywhere("anusie narcyz")
+ print 'anusie narcyz %s' % [b.hits for b in books]
+
+ # theme content cross
+ books = self.search.search_everywhere("wzrok boginie")
+ print 'wzrok boginie %s' % [b.hits for b in books]
+
+ books = self.search.search_everywhere("anusie płynęły zdroje")
+ print 'anusie płynęły zdroje %s' % [b.hits for b in books]
--- /dev/null
+# -*- coding: utf-8 -*-
+# 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.urls.defaults import *
+
+urlpatterns = patterns('search.views',
+ url(r'^$', 'main', name='search'),
+ url(r'^hint/$', 'hint'),
+)
+
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from django.conf import settings
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext
+from django.contrib.auth.decorators import login_required
+from django.views.decorators import cache
+from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponsePermanentRedirect
+from django.utils.translation import ugettext as _
+
+from catalogue.utils import get_random_hash
+from catalogue.models import Book, Tag, Fragment
+from catalogue.fields import dumps
+from catalogue.views import JSONResponse
+from search import Search, JVM, SearchResult
+from lucene import StringReader
+from suggest.forms import PublishingSuggestForm
+
+import enchant
+
+dictionary = enchant.Dict('pl_PL')
+
+
+def match_word_re(word):
+ if 'sqlite' in settings.DATABASES['default']['ENGINE']:
+ return r"\b%s\b" % word
+ elif 'mysql' in settings.DATABASES['default']['ENGINE']:
+ return "[[:<:]]%s[[:>:]]" % word
+
+
+def did_you_mean(query, tokens):
+ change = {}
+ for t in tokens:
+ print("%s ok? %s, sug: %s" % (t, dictionary.check(t), dictionary.suggest(t)))
+ authors = Tag.objects.filter(category='author', name__iregex=match_word_re(t))
+ if len(authors) > 0:
+ continue
+
+ if not dictionary.check(t):
+ try:
+ change[t] = dictionary.suggest(t)[0]
+ except IndexError:
+ pass
+
+ if change == {}:
+ return None
+
+ for frm, to in change.items():
+ query = query.replace(frm, to)
+
+ return query
+
+
+def hint(request):
+ prefix = request.GET.get('term', '')
+ if len(prefix) < 2:
+ return JSONResponse([])
+ JVM.attachCurrentThread()
+ s = Search()
+
+ hint = s.hint()
+ try:
+ tags = request.GET.get('tags', '')
+ hint.tags(Tag.get_tag_list(tags))
+ except:
+ pass
+
+ # tagi beda ograniczac tutaj
+ # ale tagi moga byc na ksiazce i na fragmentach
+ # jezeli tagi dot tylko ksiazki, to wazne zeby te nowe byly w tej samej ksiazce
+ # jesli zas dotycza themes, to wazne, zeby byly w tym samym fragmencie.
+
+ tags = s.hint_tags(prefix)
+ books = s.hint_books(prefix)
+
+ # TODO DODAC TU HINTY
+
+ return JSONResponse(
+ [{'label': t.name,
+ 'category': _(t.category),
+ 'id': t.id,
+ 'url': t.get_absolute_url()}
+ for t in tags] + \
+ [{'label': b.title,
+ 'category': _('book'),
+ 'id': b.id,
+ 'url': b.get_absolute_url()}
+ for b in books])
+
+
+def main(request):
+ results = {}
+ JVM.attachCurrentThread() # where to put this?
+ srch = Search()
+
+ results = None
+ query = None
+ fuzzy = False
+
+ if 'q' in request.GET:
+ tags = request.GET.get('tags', '')
+ query = request.GET['q']
+ book_id = request.GET.get('book', None)
+ book = None
+ if book_id is not None:
+ book = get_object_or_404(Book, id=book_id)
+
+ hint = srch.hint()
+ try:
+ tag_list = Tag.get_tag_list(tags)
+ except:
+ tag_list = []
+
+ if len(query) < 2:
+ return render_to_response('catalogue/search_too_short.html', {'tags': tag_list, 'prefix': query},
+ context_instance=RequestContext(request))
+
+ hint.tags(tag_list)
+ if book:
+ hint.books(book)
+
+ toks = StringReader(query)
+ fuzzy = 'fuzzy' in request.GET
+ if fuzzy:
+ fuzzy = 0.7
+
+ results = SearchResult.aggregate(srch.search_perfect_book(toks, fuzzy=fuzzy, hint=hint),
+ srch.search_book(toks, fuzzy=fuzzy, hint=hint),
+ srch.search_perfect_parts(toks, fuzzy=fuzzy, hint=hint),
+ srch.search_everywhere(toks, fuzzy=fuzzy, hint=hint))
+
+ for r in results:
+ r.process_hits()
+
+ results.sort(reverse=True)
+
+ for r in results:
+ print "-----"
+ for h in r.hits:
+ print "- %s" % h
+
+ # Did you mean?
+ suggestion = did_you_mean(query, srch.get_tokens(toks, field="SIMPLE"))
+
+ if len(results) == 1:
+ if len(results[0].hits) == 0:
+ return HttpResponseRedirect(results[0].book.get_absolute_url())
+ elif len(results[0].hits) == 1 and results[0].hits[0] is not None:
+ frag = Fragment.objects.get(anchor=results[0].hits[0])
+ return HttpResponseRedirect(frag.get_absolute_url())
+ elif len(results) == 0:
+ form = PublishingSuggestForm(initial={"books": query + ", "})
+ return render_to_response('catalogue/search_no_hits.html',
+ {'tags': tag_list,
+ 'prefix': query,
+ "form": form,
+ 'did_you_mean': suggestion},
+ context_instance=RequestContext(request))
+
+ return render_to_response('catalogue/search_multiple_hits.html',
+ {'tags': tag_list,
+ 'prefix': query,
+ 'results': results,
+ 'did_you_mean': suggestion},
+ context_instance=RequestContext(request))
from django.template.loader import render_to_string
from PIL import Image
-from sorl.thumbnail.fields import ImageWithThumbnailsField
from sponsors.fields import JSONField
from django.core.files.base import ContentFile
-THUMB_WIDTH=120
-THUMB_HEIGHT=120
+THUMB_WIDTH = 120
+THUMB_HEIGHT = 120
+
class Sponsor(models.Model):
name = models.CharField(_('name'), max_length=120)
_description = models.CharField(_('description'), blank=True, max_length=255)
- logo = ImageWithThumbnailsField(
- _('logo'),
- upload_to='sponsorzy/sponsor/logo',
- thumbnail={
- 'size': (THUMB_WIDTH, THUMB_HEIGHT),
- 'extension': 'png',
- 'options': ['pad', 'detail'],
- })
+ logo = models.ImageField(_('logo'), upload_to='sponsorzy/sponsor/logo')
url = models.URLField(_('url'), blank=True, verify_exists=False)
def __unicode__(self):
for column in self.get_sponsors_value():
sponsor_ids.extend(column['sponsors'])
sponsors = Sponsor.objects.in_bulk(sponsor_ids)
- sprite = Image.new('RGBA', (THUMB_WIDTH, len(sponsors)*THUMB_HEIGHT))
+ sprite = Image.new('RGBA', (THUMB_WIDTH, len(sponsors) * THUMB_HEIGHT))
for i, sponsor_id in enumerate(sponsor_ids):
- simg = Image.open(sponsors[sponsor_id].logo.thumbnail.dest)
- sprite.paste(simg, (0, i*THUMB_HEIGHT))
+ simg = Image.open(sponsors[sponsor_id].logo.path)
+ if simg.size[0] > THUMB_WIDTH or simg.size[1] > THUMB_HEIGHT:
+ size = (
+ min(THUMB_WIDTH,
+ simg.size[0] * THUMB_HEIGHT / simg.size[1]),
+ min(THUMB_HEIGHT,
+ simg.size[1] * THUMB_WIDTH / simg.size[0])
+ )
+ simg = simg.resize(size, Image.ANTIALIAS)
+ sprite.paste(simg, (
+ (THUMB_WIDTH - simg.size[0]) / 2,
+ i * THUMB_HEIGHT + (THUMB_HEIGHT - simg.size[1]) / 2,
+ ))
imgstr = StringIO()
sprite.save(imgstr, 'png')
+++ /dev/null
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from PIL import Image, ImageFilter, ImageChops
-
-
-def add_padding(image, requested_size, opts):
- if 'pad' in opts:
- padded_image = Image.new('RGBA', requested_size, '#fff')
- width, height = image.size
- requested_width, requested_height = requested_size
- print 'whatever'
- padded_image.paste(image, (0, (requested_height - height) / 2))
- return padded_image
- return image
-
-add_padding.valid_options = ('pad',)
background-color: #EEE;
cursor: default;
}
+
+.sponsors-sponsor img {
+ max-width: 120px;
+ max-height: 120px;
+}
def render(self, name, value, attrs=None):
output = [super(SponsorPageWidget, self).render(name, value, attrs)]
- sponsors = [(unicode(obj), obj.pk, obj.logo.thumbnail) for obj in models.Sponsor.objects.all()]
+ sponsors = [(unicode(obj), obj.pk, obj.logo.url) for obj in models.Sponsor.objects.all()]
sponsors_js = ', '.join('{name: "%s", id: %d, image: "%s"}' % sponsor for sponsor in sponsors)
output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
# TODO: "id_" is hard-coded here. This should instead use the correct
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
-
-from suggest.models import PublishingSuggestion
+from suggest.models import PublishingSuggestion, Suggestion
class SuggestForm(forms.Form):
contact = forms.CharField(label=_('Contact'), max_length=120, required=False)
description = forms.CharField(label=_('Description'), widget=forms.Textarea, required=True)
+ def save(self, request):
+ contact = self.cleaned_data['contact']
+ description = self.cleaned_data['description']
+
+ suggestion = Suggestion(contact=contact,
+ description=description, ip=request.META['REMOTE_ADDR'])
+ if request.user.is_authenticated():
+ suggestion.user = request.user
+ suggestion.save()
+
+ mail_managers(u'Nowa sugestia na stronie WolneLektury.pl', u'''\
+Zgłoszono nową sugestię w serwisie WolneLektury.pl.
+http://%(site)s%(url)s
+
+Użytkownik: %(user)s
+Kontakt: %(contact)s
+
+%(description)s''' % {
+ 'site': Site.objects.get_current().domain,
+ 'url': reverse('admin:suggest_suggestion_change', args=[suggestion.id]),
+ 'user': str(request.user) if request.user.is_authenticated() else '',
+ 'contact': contact,
+ 'description': description,
+ }, fail_silently=True)
+
+ if email_re.match(contact):
+ send_mail(u'[WolneLektury] ' + _(u'Thank you for your suggestion.'),
+ _(u"""\
+Thank you for your comment on WolneLektury.pl.
+The suggestion has been referred to the project coordinator.""") +
+u"""
+
+--
+""" + _(u'''Message sent automatically. Please do not reply.'''),
+ 'no-reply@wolnelektury.pl', [contact], fail_silently=True)
+
class PublishingSuggestForm(forms.Form):
contact = forms.CharField(label=_('Contact'), max_length=120, required=False)
{% load i18n %}
-<h2>{% trans "Didn't find a book? Make a suggestion." %}</h2>
+<h1>{% trans "Didn't find a book? Make a suggestion." %}</h1>
+
<form id='suggest-publishing-form' action="{% url suggest_publishing %}" method="post" accept-charset="utf-8" class="cuteform">
+{% csrf_token %}
<ol>
- <li><span class="error">{{ pubsuggest_form.contact.errors }}</span><label for="id_contact">{{ pubsuggest_form.contact.label }}</label> {{ pubsuggest_form.contact }}</li>
+ <li><span class="error">{{ form.contact.errors }}</span><label for="id_contact">{{ form.contact.label }}</label> {{ form.contact }}</li>
<li>{% trans "I'd like to find in WolneLektury.pl these…" %}</li>
- <li><span class="error">{{ pubsuggest_form.books.errors }}</span><label for="id_books">{{ pubsuggest_form.books.label }}:</label> {{ pubsuggest_form.books }}</li>
+ <li><span class="error">{{ form.books.errors }}</span><label for="id_books">{{ form.books.label }}:</label> {{ form.books }}</li>
- <li><span class="error">{{ pubsuggest_form.audiobooks.errors }}</span><label for="id_audiobooks">{{ pubsuggest_form.audiobooks.label }}:</label> {{ pubsuggest_form.audiobooks }}</li>
+ <li><span class="error">{{ form.audiobooks.errors }}</span><label for="id_audiobooks">{{ form.audiobooks.label }}:</label> {{ form.audiobooks }}</li>
<li><input type="submit" value="{% trans "Send report" %}"/></li>
</ol>
+++ /dev/null
-{% extends "base.html" %}
-{% load i18n %}
-
-{% block title %}Sugestia do planu wydawniczego w WolneLektury.pl{% endblock %}
-
-{% block metadescription %}Sugestia do planu wydawniczego.{% endblock %}
-
-{% block bodyid %}suggest-publishing{% endblock %}
-
-{% block body %}
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
-
- <div id="books-list">
- </div>
-
- <div class="column-right block-form">
- {% include "publishing_suggest.html" %}
- {% if response_data.message %}
- <p>{{ response_data.message }}</p>
- {% endif %}
- </div>
-{% endblock %}
+++ /dev/null
-{% load i18n %}
-<h2>{% trans "Report a bug or suggestion" %}</h2>
-<form id='suggest-form' action="{% url suggest.views.report %}" method="post" accept-charset="utf-8" class="cuteform">
-<ol>
- <li><label for="id_contact">{{ form.contact.label }}</label> {{ form.contact }}</li>
- <li><label for="id_description">{{ form.description.label }}</label> {{ form.description }}</li>
- <li><input type="submit" value="{% trans "Send report" %}"/></li>
-</ol>
-</form>
\ No newline at end of file
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
from django.conf.urls.defaults import *
-from django.views.generic.simple import direct_to_template
-from suggest.forms import SuggestForm, PublishingSuggestForm
-from suggest.views import PublishingSuggestionFormView
+from suggest import views
urlpatterns = patterns('',
- url(r'^$', 'django.views.generic.simple.direct_to_template',
- {'template': 'suggest.html', 'extra_context': {'form': SuggestForm }}, name='suggest'),
- url(r'^wyslij/$', 'suggest.views.report', name='report'),
-
- #url(r'^plan/$', 'suggest.views.publishing', name='suggest_publishing'),
- url(r'^plan/$', PublishingSuggestionFormView(), name='suggest_publishing'),
- #url(r'^plan_block/$', 'django.views.generic.simple.direct_to_template',
- # {'template': 'publishing_suggest.html',
- # 'extra_context': {'pubsuggest_form': PublishingSuggestForm }},
- # name='suggest_publishing'),
- #url(r'^plan/wyslij/$', 'suggest.views.publishing_commit', name='suggest_publishing_commit'),
+ url(r'^$', views.SuggestionFormView(), name='suggest'),
+ url(r'^plan/$', views.PublishingSuggestionFormView(), name='suggest_publishing'),
)
# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-from django.core.mail import send_mail, mail_managers
-from django.core.urlresolvers import reverse
-from django.core.validators import email_re
-from django.http import HttpResponse, HttpResponseRedirect
-from django.utils.translation import ugettext as _
-from django.views.decorators import cache
-from django.views.decorators.http import require_POST
-from django.contrib.sites.models import Site
-from django.shortcuts import render_to_response
-from django.template import RequestContext
+from django.utils.translation import ugettext_lazy as _
-from catalogue.forms import SearchForm
+from ajaxable.utils import AjaxableFormView
from suggest import forms
from suggest.models import Suggestion, PublishingSuggestion
-# FIXME - shouldn't be in catalogue
-from catalogue.views import LazyEncoder
-
-
-class AjaxableFormView(object):
- formClass = None
- template = None
- ajax_template = None
- formname = None
-
- def __call__(self, request):
- """
- A view displaying a form, or JSON if `ajax' GET param is set.
- """
- ajax = request.GET.get('ajax', False)
- if request.method == "POST":
- form = self.formClass(request.POST)
- if form.is_valid():
- form.save(request)
- response_data = {'success': True, 'message': _('Report was sent successfully.')}
- else:
- response_data = {'success': False, 'errors': form.errors}
- if ajax:
- return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
- else:
- form = self.formClass()
- response_data = None
-
- template = self.ajax_template if ajax else self.template
- return render_to_response(template, {
- self.formname: form,
- "form": SearchForm(),
- "response_data": response_data,
- },
- context_instance=RequestContext(request))
-
-
class PublishingSuggestionFormView(AjaxableFormView):
- formClass = forms.PublishingSuggestForm
- ajax_template = "publishing_suggest.html"
- template = "publishing_suggest_full.html"
- formname = "pubsuggest_form"
-
-
-@require_POST
-@cache.never_cache
-def report(request):
- suggest_form = forms.SuggestForm(request.POST)
- if suggest_form.is_valid():
- contact = suggest_form.cleaned_data['contact']
- description = suggest_form.cleaned_data['description']
-
- suggestion = Suggestion(contact=contact,
- description=description, ip=request.META['REMOTE_ADDR'])
- if request.user.is_authenticated():
- suggestion.user = request.user
- suggestion.save()
-
- mail_managers(u'Nowa sugestia na stronie WolneLektury.pl', u'''\
-Zgłoszono nową sugestię w serwisie WolneLektury.pl.
-http://%(site)s%(url)s
-
-Użytkownik: %(user)s
-Kontakt: %(contact)s
-
-%(description)s''' % {
- 'site': Site.objects.get_current().domain,
- 'url': reverse('admin:suggest_suggestion_change', args=[suggestion.id]),
- 'user': str(request.user) if request.user.is_authenticated() else '',
- 'contact': contact,
- 'description': description,
- }, fail_silently=True)
-
- if email_re.match(contact):
- send_mail(u'[WolneLektury] ' + _(u'Thank you for your suggestion.'),
- _(u"""\
-Thank you for your comment on WolneLektury.pl.
-The suggestion has been referred to the project coordinator.""") +
-u"""
+ form_class = forms.PublishingSuggestForm
+ title = _('Report a bug or suggestion')
+ template = "publishing_suggest.html"
+ success_message = _('Report was sent successfully.')
---
-""" + _(u'''Message sent automatically. Please do not reply.'''),
- 'no-reply@wolnelektury.pl', [contact], fail_silently=True)
- response_data = {'success': True, 'message': _('Report was sent successfully.')}
- else:
- response_data = {'success': False, 'errors': suggest_form.errors}
- return HttpResponse(LazyEncoder(ensure_ascii=False).encode(response_data))
+class SuggestionFormView(AjaxableFormView):
+ form_class = forms.SuggestForm
+ title = _('Report a bug or suggestion')
+ submit = _('Send report')
+ success_message = _('Report was sent successfully.')
-Subproject commit 84ec0eba63d0933b3f22a7884c46be6b796ee165
+Subproject commit e394602de9243608d1e99a3de448a75646f1a77f
# PIL
PIL>=1.1.6
mutagen>=1.17
-sorl-thumbnail>=3.2,<10
+sorl-thumbnail>=11.09,<12
# home-brewed & dependencies
lxml>=2.2.2
# celery tasks
django-celery
django-kombu
+
+# spell checking
+pyenchant
ROOT=$(git rev-parse --show-toplevel)
find $ROOT -name '*.py' | xargs etags -o ${ROOT}/TAGS
-find $ROOT/../librarian -name '*.py' | xargs etags -a -o ${ROOT}/TAGS
if [ -n "$VIRTUAL_ENV" ]; then
find ${VIRTUAL_ENV}/lib -name '*.py' |xargs etags -a -o ${ROOT}/TAGS
else
echo "No Virtual env enabled, will not add it to TAGS"
-fi
\ No newline at end of file
+fi
+
+find $ROOT/wolnelektury/static/css -name '*.css' |xargs etags -a -o ${ROOT}/TAGS
+find $ROOT/wolnelektury/static/js -name '*.js' |xargs etags -a -o ${ROOT}/TAGS
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.core.management import setup_environ
-from wolnelektury import settings
-import sys
-
-setup_environ(settings)
-
-from catalogue.models import Tag
-
-
-MAIN_PAGE_THEMES = [
- u'Obywatel',
- u'Car',
- u'Błoto',
- u'Krew',
- u'Danse macabre',
- u'Obcy',
- u'Matka',
- u'Gotycyzm',
-]
-
-
-for tag in Tag.objects.all():
- if tag.category in ('epoch', 'genre', 'author', 'kind'):
- tag.main_page = True
- elif tag.category == 'theme' and tag.name in MAIN_PAGE_THEMES:
- tag.main_page = True
- else:
- tag.main_page = False
-
- tag.save()
- sys.stderr.write('.')
-
-
msgstr ""
"Project-Id-Version: WolneLektury\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-01-10 13:04+0100\n"
-"PO-Revision-Date: 2012-01-10 13:04+0100\n"
+"POT-Creation-Date: 2011-10-11 15:45+0200\n"
+"PO-Revision-Date: 2011-10-11 15:46+0100\n"
"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: pl\n"
#: templates/base.html.py:120
#: templates/base.html:126
#: templates/base.html.py:132
-#: templates/catalogue/book_detail.html:211
+#: templates/catalogue/book_detail.html:208
#: templates/catalogue/book_fragments.html:33
#: templates/catalogue/differentiate_tags.html:23
#: templates/catalogue/search_multiple_hits.html:29
#: templates/catalogue/search_too_short.html:19
-#: templates/catalogue/tagged_object_list.html:143
+#: templates/catalogue/tagged_object_list.html:142
msgid "Close"
msgstr "Zamknij"
#: templates/base.html:122
#: templates/base.html.py:128
#: templates/base.html:134
-#: templates/catalogue/book_detail.html:213
+#: templates/catalogue/book_detail.html:210
#: templates/catalogue/book_fragments.html:35
#: templates/catalogue/differentiate_tags.html:25
#: templates/catalogue/search_multiple_hits.html:31
#: templates/catalogue/search_too_short.html:21
-#: templates/catalogue/tagged_object_list.html:145
+#: templates/catalogue/tagged_object_list.html:144
msgid "Loading"
msgstr "Ładowanie"
#: templates/catalogue/book_list.html:13
#: templates/catalogue/main_page.html:31
#: templates/catalogue/search_form.html:3
-#: templates/catalogue/tagged_object_list.html:45
+#: templates/catalogue/tagged_object_list.html:44
#: templates/info/base.html:12
#: templates/lesmianator/lesmianator.html:14
#: templates/lessons/document_list.html:34
#: templates/catalogue/book_detail.html:53
#: templates/catalogue/book_detail.html:56
#: templates/catalogue/book_detail.html:59
-#: templates/catalogue/book_detail.html:62
#: templates/catalogue/tagged_object_list.html:37
#: templates/catalogue/tagged_object_list.html:38
#: templates/catalogue/tagged_object_list.html:39
#: templates/catalogue/tagged_object_list.html:40
-#: templates/catalogue/tagged_object_list.html:41
msgid "for reading"
msgstr "do czytania"
msgstr "Pobierz plik EPUB"
#: templates/catalogue/book_detail.html:53
-#: templates/catalogue/book_detail.html:56
#: templates/catalogue/tagged_object_list.html:38
-#: templates/catalogue/tagged_object_list.html:39
msgid "on mobile devices"
msgstr "na urządzeniach mobilnych"
#: templates/catalogue/book_detail.html:56
-msgid "Download MOBI"
-msgstr "Pobierz plik MOBI"
-
-#: templates/catalogue/book_detail.html:59
msgid "Download TXT"
msgstr "Pobierz plik TXT"
-#: templates/catalogue/book_detail.html:59
-#: templates/catalogue/tagged_object_list.html:41
+#: templates/catalogue/book_detail.html:56
+#: templates/catalogue/tagged_object_list.html:40
msgid "on small displays, for example mobile phones"
msgstr "na małych ekranach, np. na komórce"
-#: templates/catalogue/book_detail.html:62
+#: templates/catalogue/book_detail.html:59
msgid "Download ODT"
msgstr "Pobierz plik ODT"
-#: templates/catalogue/book_detail.html:62
-#: templates/catalogue/tagged_object_list.html:40
+#: templates/catalogue/book_detail.html:59
+#: templates/catalogue/tagged_object_list.html:39
msgid "and editing using"
msgstr "i edytowania przy pomocy"
-#: templates/catalogue/book_detail.html:67
+#: templates/catalogue/book_detail.html:64
msgid "Audiobooks"
msgstr "Audiobooki"
-#: templates/catalogue/book_detail.html:81
+#: templates/catalogue/book_detail.html:78
msgid "Artist"
msgstr "Czyta"
-#: templates/catalogue/book_detail.html:82
+#: templates/catalogue/book_detail.html:79
msgid "Director"
msgstr "Reżyseruje"
-#: templates/catalogue/book_detail.html:110
+#: templates/catalogue/book_detail.html:107
msgid "Audiobooks were prepared as a part of the projects:"
msgstr "Audiobooki przygotowane w ramach projektów:"
-#: templates/catalogue/book_detail.html:115
+#: templates/catalogue/book_detail.html:112
#, python-format
msgid "%(cs)s, funded by %(fb)s"
msgstr "%(cs)s, finansowanego przez %(fb)s"
-#: templates/catalogue/book_detail.html:127
+#: templates/catalogue/book_detail.html:124
#, python-format
msgid "Audiobooks were prepared as a part of the %(cs)s project funded by %(fb)s."
msgstr "Audiobooki przygotowane w ramach projektu %(cs)s finansowanego przez %(fb)s."
-#: templates/catalogue/book_detail.html:129
+#: templates/catalogue/book_detail.html:126
#, python-format
msgid "Audiobooks were prepared as a part of the %(cs)s project."
msgstr "Audiobooki przygotowane w ramach projektu %(cs)s."
-#: templates/catalogue/book_detail.html:155
+#: templates/catalogue/book_detail.html:152
msgid "Details"
msgstr "O utworze"
-#: templates/catalogue/book_detail.html:158
+#: templates/catalogue/book_detail.html:155
msgid "Author"
msgstr "Autor"
-#: templates/catalogue/book_detail.html:164
+#: templates/catalogue/book_detail.html:161
msgid "Epoch"
msgstr "Epoka"
-#: templates/catalogue/book_detail.html:170
+#: templates/catalogue/book_detail.html:167
msgid "Kind"
msgstr "Rodzaj"
-#: templates/catalogue/book_detail.html:176
+#: templates/catalogue/book_detail.html:173
msgid "Genre"
msgstr "Gatunek"
-#: templates/catalogue/book_detail.html:182
+#: templates/catalogue/book_detail.html:179
msgid "Other resources"
msgstr "W innych miejscach"
-#: templates/catalogue/book_detail.html:185
+#: templates/catalogue/book_detail.html:182
msgid "Source of the book"
msgstr "Źródło lektury"
-#: templates/catalogue/book_detail.html:188
+#: templates/catalogue/book_detail.html:185
msgid "Book on the Editor's Platform"
msgstr "Utwór na Platformie Redakcyjnej"
-#: templates/catalogue/book_detail.html:191
+#: templates/catalogue/book_detail.html:188
msgid "Book description on Lektury.Gazeta.pl"
msgstr "Opis lektury w Lektury.Gazeta.pl"
-#: templates/catalogue/book_detail.html:194
+#: templates/catalogue/book_detail.html:191
msgid "Book description on Wikipedia"
msgstr "Opis lektury w Wikipedii"
-#: templates/catalogue/book_detail.html:197
+#: templates/catalogue/book_detail.html:194
msgid "View XML source"
msgstr "Źródłowy plik XML"
-#: templates/catalogue/book_detail.html:201
+#: templates/catalogue/book_detail.html:198
msgid "Work's themes "
msgstr "Motywy w utworze"
msgstr "Spis treści"
#: templates/catalogue/book_text.html:22
-#: templates/catalogue/tagged_object_list.html:134
+#: templates/catalogue/tagged_object_list.html:133
msgid "Themes"
msgstr "Motywy"
msgid "Infobox"
msgstr "Informacje"
-#: templates/catalogue/collection.html:6
-msgid "in WolneLektury.pl"
-msgstr "w WolneLektury.pl"
-
#: templates/catalogue/daisy_list.html:6
msgid "Listing of all DAISY files on WolneLektury.pl"
msgstr "Spis wszystkich plików DAISY w WolneLektury.pl"
msgstr "Zobacz całą kategorię"
#: templates/catalogue/folded_tag_list.html:13
-#: templates/catalogue/main_page.html:103
-#: templates/catalogue/main_page.html:108
-#: templates/catalogue/main_page.html:147
-#: templates/catalogue/main_page.html:342
+#: templates/catalogue/main_page.html:111
+#: templates/catalogue/main_page.html:116
+#: templates/catalogue/main_page.html:155
+#: templates/catalogue/main_page.html:350
msgid "See more"
msgstr "Zobacz więcej"
#: templates/catalogue/folded_tag_list.html:22
-#: templates/catalogue/main_page.html:310
+#: templates/catalogue/main_page.html:318
msgid "Hide"
msgstr "Zwiń"
msgstr "Półki zawierające fragment"
#: templates/catalogue/fragment_sets.html:4
-#: templates/catalogue/main_page.html:76
+#: templates/catalogue/main_page.html:85
msgid "You do not own any shelves. You can create one below, if you want to."
msgstr "Nie posiadasz żadnych półek. Jeśli chcesz, możesz utworzyć nową półkę poniżej."
msgid "Browse books by categories"
msgstr "Przeglądaj lektury według wybranych kategorii"
-#: templates/catalogue/main_page.html:59
+#: templates/catalogue/main_page.html:69
msgid "Books for every school level"
msgstr "Lektury na każdy poziom edukacji"
-#: templates/catalogue/main_page.html:61
+#: templates/catalogue/main_page.html:71
msgid "primary school"
msgstr "szkoła podstawowa"
-#: templates/catalogue/main_page.html:62
+#: templates/catalogue/main_page.html:72
msgid "gymnasium"
msgstr "gimnazjum"
-#: templates/catalogue/main_page.html:63
+#: templates/catalogue/main_page.html:73
msgid "high school"
msgstr "szkoła średnia"
-#: templates/catalogue/main_page.html:67
+#: templates/catalogue/main_page.html:76
#: templates/catalogue/user_shelves.html:2
msgid "Your shelves with books"
msgstr "Twoje półki z lekturami"
-#: templates/catalogue/main_page.html:72
+#: templates/catalogue/main_page.html:81
msgid "delete"
msgstr "usuń"
-#: templates/catalogue/main_page.html:81
+#: templates/catalogue/main_page.html:90
#: templates/catalogue/user_shelves.html:15
msgid "Create shelf"
msgstr "Utwórz półkę"
-#: templates/catalogue/main_page.html:86
+#: templates/catalogue/main_page.html:94
msgid "Create your own book set. You can share it with friends by sending them link to your shelf."
msgstr "Stwórz własny zestaw lektur. Możesz się nim później podzielić z innymi, przesyłając im link do Twojej półki."
-#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:95
msgid "You need to "
msgstr "Aby zarządzać swoimi półkami, musisz się"
-#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:95
msgid "sign in"
msgstr "zalogować"
-#: templates/catalogue/main_page.html:87
+#: templates/catalogue/main_page.html:95
msgid "to manage your shelves."
msgstr "."
-#: templates/catalogue/main_page.html:93
+#: templates/catalogue/main_page.html:101
msgid "Twórzże się!"
msgstr ""
-#: templates/catalogue/main_page.html:95
#: templates/catalogue/main_page.html:103
+#: templates/catalogue/main_page.html:111
msgid "Wolne Lektury Widget"
msgstr "Widżet Wolne Lektury"
-#: templates/catalogue/main_page.html:96
+#: templates/catalogue/main_page.html:104
msgid "Place our widget - search engine for Wolne Lektury which gives access to free books and audiobooks - on your homepage! Just copy the HTML code below onto your page:"
msgstr "Umieść widżet – wyszukiwarkę Wolnych Lektur umożliwiającą dostęp do darmowych lektur i audiobooków – na swojej stronie WWW! Po prostu skopiuj poniższy kod HTML na swoją stronę:"
-#: templates/catalogue/main_page.html:97
+#: templates/catalogue/main_page.html:105
msgid "Insert this element in place where you want display the widget"
msgstr "Umieść ten element w miejscu gdzie chcesz wyświetlić widżet"
-#: templates/catalogue/main_page.html:100
+#: templates/catalogue/main_page.html:108
msgid "Place this element just before closing body tag: </body>"
msgstr "Umieść ten element tuż przed zamknięciem taga body: </body>"
-#: templates/catalogue/main_page.html:106
-#: templates/catalogue/main_page.html:108
+#: templates/catalogue/main_page.html:114
+#: templates/catalogue/main_page.html:116
#: templates/lessons/document_list.html:32
msgid "Hand-outs for teachers"
msgstr "Materiały pomocnicze dla nauczycieli"
-#: templates/catalogue/main_page.html:107
+#: templates/catalogue/main_page.html:115
msgid "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching."
msgstr "Scenariusze lekcji i inne pomysły na wykorzytanie serwisu WolneLektury.pl podczas nauczania."
-#: templates/catalogue/main_page.html:114
-#: templates/catalogue/tagged_object_list.html:113
+#: templates/catalogue/main_page.html:122
+#: templates/catalogue/tagged_object_list.html:112
msgid "Authors"
msgstr "Autorzy"
-#: templates/catalogue/main_page.html:118
-#: templates/catalogue/tagged_object_list.html:117
+#: templates/catalogue/main_page.html:126
+#: templates/catalogue/tagged_object_list.html:116
msgid "Kinds"
msgstr "Rodzaje"
-#: templates/catalogue/main_page.html:122
-#: templates/catalogue/tagged_object_list.html:121
+#: templates/catalogue/main_page.html:130
+#: templates/catalogue/tagged_object_list.html:120
msgid "Genres"
msgstr "Gatunki"
-#: templates/catalogue/main_page.html:126
-#: templates/catalogue/tagged_object_list.html:125
+#: templates/catalogue/main_page.html:134
+#: templates/catalogue/tagged_object_list.html:124
msgid "Epochs"
msgstr "Epoki"
-#: templates/catalogue/main_page.html:132
-#: templates/catalogue/main_page.html:147
+#: templates/catalogue/main_page.html:140
+#: templates/catalogue/main_page.html:155
msgid "Themes and topics"
msgstr "Motywy i tematy"
-#: templates/catalogue/main_page.html:135
+#: templates/catalogue/main_page.html:143
msgid "Themes groups"
msgstr "Rodziny motywów"
-#: templates/catalogue/main_page.html:320
+#: templates/catalogue/main_page.html:328
msgid "News"
msgstr "Aktualności"
-#: templates/catalogue/main_page.html:324
+#: templates/catalogue/main_page.html:332
msgid "See our blog"
msgstr "Zobacz nasz blog"
-#: templates/catalogue/main_page.html:327
-#: templates/catalogue/main_page.html:333
+#: templates/catalogue/main_page.html:335
+#: templates/catalogue/main_page.html:341
msgid "You can help us!"
msgstr "Możesz nam pomóc!"
-#: templates/catalogue/main_page.html:329
+#: templates/catalogue/main_page.html:337
msgid "Become a volunteer – an editor, developer or translator."
msgstr "Zostań naszym redaktorem, programistą lub tłumaczem – wolontariuszem."
-#: templates/catalogue/main_page.html:330
+#: templates/catalogue/main_page.html:338
msgid "Gain new skills and experience."
msgstr "Zdobądź nowe umiejętności i doświadczenie."
-#: templates/catalogue/main_page.html:331
+#: templates/catalogue/main_page.html:339
msgid "Join an open project of creating an innovative online library."
msgstr "Weź udział w otwartym projekcie i twórz innowacyjną bibliotekę internetową."
-#: templates/catalogue/main_page.html:336
-#: templates/catalogue/main_page.html:342
+#: templates/catalogue/main_page.html:344
+#: templates/catalogue/main_page.html:350
msgid "About us"
msgstr "O projekcie"
-#: templates/catalogue/main_page.html:338
+#: templates/catalogue/main_page.html:346
msgid ""
"\n"
"\t\t\tInternet library with school readings “Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.\n"
"\n"
"Biblioteka internetowa z lekturami szkolnymi „Wolne Lektury” (<a href=\"http://wolnelektury.pl\">www.wolnelektury.pl</a>) to projekt realizowany przez fundację Nowoczesna Polska. Działa od 2007 roku i udostępnia w swoich zbiorach lektury szkolne, które są zalecane do użytku przez Ministerstwo Edukacji Narodowej i które trafiły już do domeny publicznej."
-#: templates/catalogue/main_page.html:351
+#: templates/catalogue/main_page.html:359
msgid ""
"\n"
"Portions of this page are modifications based on work created and <a href=\"http://code.google.com/policies.html\">shared by Google</a> and used\n"
msgstr "Wyszukiwanie w WolneLektury.pl"
#: templates/catalogue/search_no_hits.html:14
-#: templates/catalogue/tagged_object_list.html:103
+#: templates/catalogue/tagged_object_list.html:101
msgid "Sorry! Search cirteria did not match any resources."
msgstr "Przepraszamy! Brak wyników spełniających kryteria podane w zapytaniu."
msgid "Choose books' formats which you want to download:"
msgstr "Wybierz formaty książek, które chcesz pobrać:"
+#: templates/catalogue/tagged_object_list.html:41
#: templates/catalogue/tagged_object_list.html:42
-#: templates/catalogue/tagged_object_list.html:43
msgid "for listening"
msgstr "do słuchania"
-#: templates/catalogue/tagged_object_list.html:42
+#: templates/catalogue/tagged_object_list.html:41
msgid "on favourite MP3 player"
msgstr "w ulubionym odtwarzaczu MP3"
-#: templates/catalogue/tagged_object_list.html:43
+#: templates/catalogue/tagged_object_list.html:42
msgid "open format"
msgstr "otwarty format"
-#: templates/catalogue/tagged_object_list.html:43
+#: templates/catalogue/tagged_object_list.html:42
msgid "Xiph.org Foundation"
msgstr "fundacji Xiph.Org"
-#: templates/catalogue/tagged_object_list.html:45
+#: templates/catalogue/tagged_object_list.html:44
#: templates/lessons/ajax_document_detail.html:3
msgid "Download"
msgstr "Pobierz"
-#: templates/catalogue/tagged_object_list.html:45
+#: templates/catalogue/tagged_object_list.html:44
msgid "Updating list of books' formats on the shelf"
msgstr "Uaktualnianie listy formatów książek na półce."
-#: templates/catalogue/tagged_object_list.html:45
+#: templates/catalogue/tagged_object_list.html:44
msgid "cancel"
msgstr "anuluj"
-#: templates/catalogue/tagged_object_list.html:50
+#: templates/catalogue/tagged_object_list.html:49
msgid "Share this shelf"
msgstr "Podziel się tą półką"
-#: templates/catalogue/tagged_object_list.html:52
+#: templates/catalogue/tagged_object_list.html:51
msgid "Copy this link and share it with other people to let them see your shelf."
msgstr "Skopiuj ten link i przekaż go osobom, z którymi chcesz się podzielić tą półką."
-#: templates/catalogue/tagged_object_list.html:62
+#: templates/catalogue/tagged_object_list.html:61
#: templates/pdcounter/author_detail.html:27
msgid "Read work's study of this author on Lektury.Gazeta.pl"
msgstr "Przeczytaj omówienia utworów autora w serwisie Lektury.Gazeta.pl"
-#: templates/catalogue/tagged_object_list.html:64
+#: templates/catalogue/tagged_object_list.html:63
#, python-format
msgid "Read study of epoch %(last_tag)s on Lektury.Gazeta.pl"
msgstr "Przeczytaj omówienia z epoki %(last_tag)s w serwisie Lektury.Gazeta.pl"
-#: templates/catalogue/tagged_object_list.html:66
+#: templates/catalogue/tagged_object_list.html:65
#, python-format
msgid "Read study of kind %(last_tag)s on Lektury.Gazeta.pl"
msgstr "Przeczytaj omówienia z rodzaju %(last_tag)s w serwisie Lektury.Gazeta.pl"
-#: templates/catalogue/tagged_object_list.html:68
+#: templates/catalogue/tagged_object_list.html:67
#, python-format
msgid "Read study of genre %(last_tag)s on Lektury.Gazeta.pl"
msgstr "Przeczytaj omówienia z gatunku %(last_tag)s w serwisie Lektury.Gazeta.pl"
-#: templates/catalogue/tagged_object_list.html:70
+#: templates/catalogue/tagged_object_list.html:69
msgid "Read related study on Lektury.Gazeta.pl"
msgstr "Przeczytaj powiązane omówienia w serwisie Lektury.Gazeta.pl"
-#: templates/catalogue/tagged_object_list.html:78
+#: templates/catalogue/tagged_object_list.html:77
#: templates/pdcounter/author_detail.html:32
msgid "Read article about this author on Wikipedia"
msgstr "Przeczytaj artykuł o autorze w Wikipedii"
-#: templates/catalogue/tagged_object_list.html:80
+#: templates/catalogue/tagged_object_list.html:79
#, python-format
msgid "Read article about epoch %(last_tag)s on Wikipedia"
msgstr "Przeczytaj artykuł o epoce %(last_tag)s w Wikipedii"
-#: templates/catalogue/tagged_object_list.html:82
+#: templates/catalogue/tagged_object_list.html:81
#, python-format
msgid "Read article about kind %(last_tag)s on Wikipedia"
msgstr "Przeczytaj artykuł o rodzaju %(last_tag)s w Wikipedii"
-#: templates/catalogue/tagged_object_list.html:84
+#: templates/catalogue/tagged_object_list.html:83
#, python-format
msgid "Read article about genre %(last_tag)s on Wikipedia"
msgstr "Przeczytaj artykuł o gatunku %(last_tag)s w Wikipedii"
-#: templates/catalogue/tagged_object_list.html:86
+#: templates/catalogue/tagged_object_list.html:85
msgid "Read related article on Wikipedia"
msgstr "Przeczytaj powiązany artykuł w Wikipedii"
-#: templates/catalogue/tagged_object_list.html:96
+#: templates/catalogue/tagged_object_list.html:95
msgid "Delete"
msgstr "Usuń"
#~ "to profesjonalne nagrania tekstów literackich z naszego zbioru dostępne "
#~ "na wolnej licencji w formatach MP3, Ogg Vorbis oraz w systemie DAISY."
+#~ msgid "Download MP3"
+#~ msgstr "Pobierz plik MP3"
+
#~ msgid "Download Ogg Vorbis"
#~ msgstr "Pobierz plik Ogg Vorbis"
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = path.join(PROJECT_DIR, '../media/')
STATIC_ROOT = path.join(PROJECT_DIR, 'static/')
+SEARCH_INDEX = path.join(MEDIA_ROOT, 'search/')
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
'django.core.context_processors.media',
'django.core.context_processors.request',
'wolnelektury.context_processors.extra_settings',
+ 'search.context_processors.search_form',
)
MIDDLEWARE_CLASSES = [
path.join(PROJECT_DIR, 'templates'),
]
-LOGIN_URL = '/uzytkownicy/login/'
+LOGIN_URL = '/uzytkownicy/zaloguj/'
LOGIN_REDIRECT_URL = '/'
'modeltranslation',
# our
+ 'ajaxable',
'api',
'catalogue',
'chunks',
'sponsors',
'stats',
'suggest',
+ 'picture',
+ 'search',
]
CACHES = {
# CSS and JavaScript file groups
COMPRESS_CSS = {
'all': {
- 'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/jquery.countdown.css', 'css/master.plain.css', 'css/sponsors.css', 'css/facelist_2-0.css',),
+ #'source_filenames': ('css/master.css', 'css/jquery.autocomplete.css', 'css/master.plain.css', 'css/facelist_2-0.css',),
+ 'source_filenames': [
+ 'css/jquery.countdown.css',
+
+ 'css/base.css',
+ 'css/header.css',
+ 'css/main_page.css',
+ 'css/dialogs.css',
+ 'css/picture_box.css',
+ 'css/book_box.css',
+ 'css/catalogue.css',
+ 'css/sponsors.css',
+
+ 'css/ui-lightness/jquery-ui-1.8.16.custom.css',
+ ],
'output_filename': 'css/all.min?.css',
},
'book': {
'source_filenames': ('css/master.book.css',),
'output_filename': 'css/book.min?.css',
},
+ 'player': {
+ 'source_filenames': [
+ 'jplayer/jplayer.blue.monday.css',
+ ],
+ 'output_filename': 'css/player.min?.css',
+ },
'simple': {
'source_filenames': ('css/simple.css',),
'output_filename': 'css/simple.min?.css',
}
COMPRESS_JS = {
- 'jquery': {
- 'source_filenames': ('js/jquery.js',),
- 'output_filename': 'js/jquery.min.js',
- },
- 'all': {
- 'source_filenames': ('js/jquery.autocomplete.js', 'js/jquery.form.js',
+ 'base': {
+ 'source_filenames': (
+ 'js/jquery.cycle.min.js',
+ 'js/jquery.jqmodal.js',
+ 'js/jquery.form.js',
'js/jquery.countdown.js', 'js/jquery.countdown-pl.js',
'js/jquery.countdown-de.js', 'js/jquery.countdown-uk.js',
'js/jquery.countdown-es.js', 'js/jquery.countdown-lt.js',
'js/jquery.countdown-ru.js', 'js/jquery.countdown-fr.js',
- 'js/jquery.cycle.min.js',
- 'js/jquery.jqmodal.js', 'js/jquery.labelify.js', 'js/catalogue.js',
+
+ 'js/jquery-ui-1.8.16.custom.min.js',
+
+ 'js/locale.js',
+ 'js/dialogs.js',
+ 'js/sponsors.js',
+ 'js/base.js',
+ 'js/pdcounter.js',
+
+ 'js/search.js',
+
+ 'js/jquery.labelify.js',
),
- 'output_filename': 'js/all?.min.js',
+ 'output_filename': 'js/base?.min.js',
+ },
+ 'player': {
+ 'source_filenames': [
+ 'jplayer/jquery.jplayer.min.js',
+ 'jplayer/jplayer.playlist.min.js',
+ 'js/player.js',
+ ],
+ 'output_filename': 'js/player.min?.js',
},
'book': {
'source_filenames': ('js/jquery.eventdelegation.js', 'js/jquery.scrollto.js', 'js/jquery.highlightfade.js', 'js/book.js',),
NO_BUILD_EPUB = False
NO_BUILD_TXT = False
NO_BUILD_PDF = False
-NO_BUILD_MOBI = False
+NO_BUILD_MOBI = True
+NO_SEARCH_INDEX = False
ALL_EPUB_ZIP = 'wolnelektury_pl_epub'
ALL_PDF_ZIP = 'wolnelektury_pl_pdf'
ALL_MOBI_ZIP = 'wolnelektury_pl_mobi'
+CATALOGUE_DEFAULT_LANGUAGE = 'pol'
+PUBLISH_PLAN_FEED = 'http://redakcja.wolnelektury.pl/documents/track/editor-proofreading/'
+
PAGINATION_INVALID_PAGE_RAISES_404 = True
import djcelery
BROKER_VHOST = "/"
+
# Load localsettings, if they exist
try:
from localsettings import *
--- /dev/null
+/* Logo font */
+@font-face {
+ /* IE version */
+ font-family: WL-Logo;
+ src: url(/static/fonts/WL.eot);
+}
+@font-face {
+ font-family: WL-Nav;
+ src: url(/static/fonts/WL-Nav.ttf) format("truetype");
+}
+
+
+html {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ margin: 0;
+ background: #f7f7f7;
+ font-size: .625em;
+ font-family: Georgia;
+ /*line-height: 1.4em;*/
+}
+
+
+a {
+ color: #1199a2; /* #01adba; */
+ text-decoration: none;
+}
+
+h1 {
+ font-size: 3.5em;
+ font-weight: normal;
+ margin-top: .4em
+}
+
+.left-column {
+ width: 47em;
+ float: left;
+}
+.right-column {
+ float:right;
+ width: 47em;
+}
+.normal-text {
+ font-size: 1.3em;
+ line-height: 1.3em;
+}
+
+h2 {
+ margin: 0;
+ font-size: 1em;
+ font-weight: normal;
+}
+
+
+.mono {
+ font-family: "Andale Mono", "Lucida Sans Typewriter", "Courier New";
+ font-weight: bold;
+}
+
+.accent1 {
+ color: #191919;
+}
+
+.accent2 {
+ color: #242424;
+}
+
+.accent3 {
+ color: #575c63;
+}
+
+
+.accent4 {
+ color: #707b7a;
+}
+
+.contrast {
+ #1199a2;
+}
+
+/* #281d1c */
+
+.clearboth {
+ clear: both;
+}
+
+#header-content, div#main-content, div#half-header-content, #footer-content {
+ width: 97.5em;
+ margin: auto;
+}
+
+
+.page-desc {
+ margin-left: 1.5em;
+}
+
+.inline-tag-lists p span:first-child {
+ color: #281d1c;
+}
+
+.inline-tag-lists {
+ font-size: 1.1em;
+}
+
+#themes-list-toggle:after {
+ padding-left: 1em;
+ content: "↓";
+ font-family: WL-Nav;
+ vertical-align: middle;
+}
+#themes-list-wrapper {
+ position: relative;
+ font-size: 1.1em;
+}
+#themes-list {
+ position: absolute;
+ display: none;
+ border: 1px solid #ddd;
+ padding: 1em;
+ background: #fff;
+ -moz-box-shadow: 2px 2px 2px #ddd;
+ -webkit-box-shadow: 2px 2px 2px #ddd;
+ box-shadow: 2px 2px 2px #ddd;
+ z-index: 500;
+}
+#themes-list ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ font-size: 1.1em;
+ -moz-column-width: 12em;
+ width: 48em;
+}
+
+
+a.cite {
+ display: block;
+ color: black;
+ background: white;
+ padding: 3em 2em .1em 8em;
+}
+.cite-body {
+ font-size: 1.8em;
+ line-height: 1.3em;
+}
+.cite p {
+ color: #444;
+ font-size: 1.1em;
+ margin-top: 1.6em;
+}
+
+.see-also {
+ margin-left: 8em;
+ float: left;
+ width: 14.3em;
+}
+.download {
+ margin-left: 2em;
+ float: left;
+}
+
+.see-also, .download {
+ margin-top: 2em;
+ margin-bottom: 2em;
+}
+.see-also h2, .download h2 {
+ font-size: 1.1em;
+}
+.see-also ul, .download ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ font-size: 1.1em;
+}
+
+
+#footer {
+ color: #777;
+ eborder-top: 1px solid #ddd;
+ margin-top: 5em;
+ padding-top:3em;
+ background: #fff;
+}
--- /dev/null
+.book-wide-box, .book-mini-box, .book-box {
+ display: inline-block;
+ margin: 0;
+ vertical-align: top;
+}
+
+
+.book-box {
+ width: 48.75em;
+}
+
+.book-mini-box {
+ width: 16.15em;
+}
+
+.book-wide-box {
+ width: 98.5em;
+ margin-left: -0.1em;
+}
+
+.book-mini-box a, .book-box-inner {
+ display: block;
+ color: black;
+ border: 1px solid #ddd;
+ height: 20em;
+ padding: .8em 1em;
+ margin: .1em;
+ background: #fff;
+ -moz-box-shadow: 2px 2px 2px #ddd;
+ -webkit-box-shadow: 2px 2px 2px #ddd;
+ box-shadow: 2px 2px 2px #ddd;
+}
+
+.book-mini-box a {
+ height: 27.1em;
+ margin: .1em;
+ overflow: hidden;
+}
+.book-box-inner {
+ height: 19.75em;
+ margin: .5em;
+}
+
+.book-wide-box .book-box-inner {
+ height: 24.4em;
+}
+
+.book-mini-box img, .book-box img, .book-wide-box img {
+ width: 13.9em;
+ height: 19.3em;
+}
+.book-mini-box img {
+ margin-bottom: 1.8em;
+}
+.book-box img, .book-wide-box img {
+ float: left;
+ margin-right: 1.5em;
+}
+
+.book-mini-box .desc {
+ margin-left:0em;
+}
+.book-mini-box .author {
+ font-size: 1.1em;
+ color: #707b7a;
+ display: block;
+}
+.book-mini-box .title {
+ font-size: 1.4em;
+ color: #242424;
+}
+
+
+.book-box-body {
+ height: 17em;
+ overflow: hidden;
+}
+
+.book-wide-box .book-box-body {
+ height: 21.8em;
+}
+
+.book-box-head {
+ min-height: 7em;
+ margin-top: 1.4em;
+ margin-bottom: 1em;
+}
+.book-box-head .author {
+ font-size: 1.1em;
+}
+.book-box-head .title {
+ font-size: 2.4em;
+ margin-top: .3em;
+}
+.book-box-body .tags {
+ font-size: 1.1em;
+}
+.book-box-tag {
+ margin-right: .5em;
+ margin-left: .4em;
+}
+.book-box-download {
+ position: relative;
+}
+
+.book-box-download a {
+ position: relative;
+ z-index: 1;
+}
+
+.book-box-formats {
+ display: none;
+ position: absolute;
+
+ width: 16.363em;
+ border: 1px solid #ddd;
+ padding: 3.454em 1.727em .818em 1.727em;
+ background: #fff;
+ -moz-box-shadow: 2px 2px 2px #ddd;
+ -webkit-box-shadow: 2px 2px 2px #ddd;
+ box-shadow: 2px 2px 2px #ddd;
+
+ z-index: 0;
+ top: -1.454em;
+ left: -1.727em;
+}
+.book-box-formats span {
+ display: block;
+}
+
+
+.book-box-download:hover .book-box-formats span:first-child {
+ margin-top: 1.454em;
+}
+
+.book-box-download:hover .book-box-formats {
+ display: block;
+}
+
+.book-box-tools {
+ font-size: 1.1em;
+}
+
+.book-wide-box .book-box-tools {
+ margin-left: 14em;
+}
+
+.book-box-tools a.downarrow:before {
+ content: "\2609";
+ font-family: WL-Nav;
+ font-size: 2.25em;
+ margin-right: .15em;
+ vertical-align: middle;
+}
+
+.book-box-audiobook a:before {
+ content: "\266B";
+ font-family: WL-Nav;
+ font-size: 2.25em;
+ margin-right: .15em;
+ vertical-align: middle;
+}
+
+ul.book-box-tools {
+ margin: 0;
+ padding: 0;
+}
+
+.book-box-tools li {
+ display: inline-block;
+}
+
+.book-box-read {
+ width: 11.5em;
+}
+.book-box-download {
+ width: 8.5em;
+}
+.book-box-audiobook {
+ width: 7em;
+}
+
+.book-wide-box .right-column {
+ float: right;
+ width: 41.5em;
+}
+
+.book-wide-box blockquote.cite-body {
+ /* @ 18pt */
+ width: 100%; /*23.055em;*/
+ height: 7.222em;
+ background-color: #f7f7f7;
+ margin: 0;
+ position: relative;
+ top: -0.444em;
+ right: -0.555em;
+ vertical-align: center;
+}
+
+.book-wide-box blockquote div {
+ padding: 0.888em;
+}
+
+ul.inline-items, ul.inline-items li {
+ margin: 0;
+ padding: 0;
+}
+
+ul.inline-items li {
+ display: inline-block;
+}
+
+.book-wide-box #other-tools {
+ float: left;
+ width: 14.5em;
+ margin: 6em 0 0 1.5em;
+
+}
+
+.book-wide-box #other-download {
+ float: left;
+ width: 22.5em;
+ margin: 6em 1.5em 0em 1.5em
+}
+
--- /dev/null
+.work-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.work-item {
+ margin: 0;
+ padding: 0;
+}
+
+.books .work-item {
+ display: inline-block;
+}
+
+
+#tagged-object-list .left-column, #tagged-object-list .right-column {
+ width: 48em;
+}
+
+
+/* listing of all books */
+#book-list {
+ padding-left: 50px;
+}
+#book-list-nav {
+ position: absolute;
+ right: 50px;
+ width: 200px;
+ border-left: 1px #cfcfcf solid;
+ padding: 10px;
+ font-size: 1.2em;
+}
+
+#book-list-nav ul {
+ list-style-type: none;
+ margin: 5px;
+ padding: 0;
+}
+
+.book-list-show-index {
+ display: none;
+ margin: 0;
+ padding: 0;
+}
+
+
+#book-a-list #book-list ol {
+ padding-left: 1em;
+ margin: 0.3em 0 1.2em 0;
+ list-style: none;
+}
+
+#book-a-list #book-list h2 a {
+ color: black;
+}
+
+#book-list-up {
+ position: fixed;
+ bottom: 50px;
+ right: 50px;
+ border-left: 1px #cfcfcf solid;
+ padding: 10px;
+ background-color: white;
+}
+
+
+
+fragment
\ No newline at end of file
--- /dev/null
+.cuteform {
+ font-size: 1.1em;
+}
+.cuteform ol, .cuteform ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ font-style: 1.1em;
+}
+
+.cuteform ol li, .cuteform ul li {
+ margin-top: 0.7em;
+}
+
+.cuteform label {
+ display: block;
+}
+
+.cuteform span.help-text {
+ display: block;
+ font-size: 0.8em;
+ color: #999;
+}
+
+.cuteform .error {
+ color: #BF3024;
+ display: block;
+}
+.cuteform .errorlist {
+ color: #BF3024;
+}
+
+
+.jqmOverlay { background-color: #000; }
+
+
+.dialog-window {
+ position: absolute;
+ display: none;
+ background-color: transparent;
+ margin-top: -0.5em;
+ margin-left: 1em;
+}
+
+.dialog-window div.header {
+ font-size: 1.1em;
+ width: 4em;
+ background-color: #FFF;
+ border-right: 0.3em solid #DDD;
+ padding: 0.5em 1em 0.5em 1em;
+ right: 0;
+ left: auto;
+ float: right;
+ text-align: center;
+}
+
+
+.dialog-window div.target {
+ background-color: #FFF;
+ color: black;
+ border-right: 0.3em solid #DDD;
+ border-bottom: 0.3em solid #DDD;
+ padding: 1em;
+ clear: both;
+}
+
+.dialog-window h1 {
+ font-size: 1.2em;
+}
+
+.dialog-window textarea, .dialog-window input {
+ width: 100%;
+}
+
+#login-window {
+ width: 26em;
+}
+#register-window {
+ width: 26em;
+}
+
+#suggest-window {
+ width: 26em;
+}
+
+#suggest-window textarea {
+ height: 6em;
+}
+
+#suggest-publishing-window {
+ width: 29em;
+}
+
+#suggest-publishing-window textarea {
+ height: 3em;
+}
+
+#custom-pdf-window {
+ width: 24em;
+}
+
+#custom-pdf-window label {
+ display: inline;
+}
--- /dev/null
+/* Logo font */
+@font-face {
+ /* IE version */
+ font-family: WL-Logo;
+ src: url(/static/fonts/WL.eot);
+}
+@font-face {
+ font-family: WL-Logo;
+ src: url(/static/fonts/WL.ttf) format("truetype");
+}
+
+
+#header {
+ height: 3em;
+ padding-top: 1.9em;
+ padding-bottom: 0;
+ color: #989898;
+ background: #191919;
+}
+
+#half-header {
+ padding-bottom: 0;
+ background: url('/static/img/bg-header.png');
+ background-position: center;
+ background-size: 100%;
+}
+
+#half-header-content {
+ background: #191919;
+}
+
+
+#user-info {
+ float: right;
+ margin: 0;
+}
+
+#logo {
+ position: absolute;
+ top: 1.9em;
+ margin-left: 1.5em;
+}
+
+#logo a {
+ font-family: WL-Logo;
+ font-size: 2.05em;
+ color:#f7f7f7;
+}
+
+#tagline {
+ display: inline-block;
+ margin-left: 25.5em;
+}
+#tagline span {
+ font-size: 1.1em;
+}
+
+#search-area {
+ margin: 0;
+ background: #444;
+ margin-left: 24em;
+ width: 73.5em;
+}
+
+#search-field {
+ display: inline-block;
+ width: 63.1em;
+ padding-left: .5em;
+ padding-right: 0;
+ padding-top: 0.6em;
+ padding-bottom: 0;
+}
+
+#search {
+ font-size: 1.3em;
+ padding: 0;
+ /*height: 3.3em;
+ width: 62.6em;
+ padding-left: .5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ border: none;
+ border-radius: .5em;
+ -webkit-box-shadow:0 0 .5em #444 inset;
+ -moz-box-shadow:0 0 .5em #444 inset;
+ box-shadow: 0 0 .5em #444 inset;*/
+ height: 2.54em;
+ width: 47.47em;
+ padding-left: 1em;
+ -webkit-border-radius: .38em;
+ -moz-border-radius: .38em;
+ border: none;
+ border-radius: .38em;
+ -webkit-box-shadow:0 0 .38em #444 inset;
+ -moz-box-shadow:0 0 .38em #444 inset;
+ box-shadow: 0 0 .5em #444 inset;
+
+ font-family: Georgia;
+ background-color: #fff;
+ color: #000;
+}
+#search.blur {
+ font-family: Georgia;
+ font-style: italic;
+ color: #888;
+}
+
+#search-button {
+ display: inline-block;
+ background: #02adb7;
+ padding: 0;
+ margin: 0;
+ width: 9.4em;
+ float: right;
+}
+#search-button button {
+ font-size: 1em;
+ height: 4.5em;
+ border: none;
+ background: #02adb7;
+ color: white;
+ width: 100%;
+ padding: 0;
+}
+
+#search-button button span {
+ font-size: 1.1em;
+ position:relative;
+}
+
+
+#nav-line {
+ background-color: #e2e2e2;
+ height: 4.9em;
+}
+
+ul#catalogue {
+ list-style: none;
+ padding: 0;
+ margin: 0 0 0 .6em;
+}
+ul#catalogue li {
+ background-color: #e2e2e2;
+ float: left;
+}
+ul#catalogue a {
+ display: block;
+ padding-left: 1.4em;
+ padding-right: 1.4em;
+ /* must match grid-line */
+ height: 3.1em;
+ padding-top: 1.8em;
+}
+ul#catalogue span {
+ font-size: 1.1em;
+}
+
+
+#lang-button {
+ color: #aaa;
+}
+#lang-button:after {
+ padding-left: 1em;
+ content: "↓";
+ font-family: WL-Nav;
+ vertical-align: middle;
+}
+#lang-menu {
+ position: relative;
+ float: right;
+ display: block;
+ padding-left: 2.5em;
+ padding-right: 2em;
+ /* must match grid-line */
+ height: 3em;
+ padding-top: 1.9em;
+ background: #f7f7f7;
+}
+
+#lang-menu-items button {
+ display: none;
+ background: #f7f7f7;
+ color: #777;
+ cursor: pointer;
+ width: 100%;
+ border: solid #ddd;
+ border-width: 0 0 1px 0;
+ padding: .5em 0;
+ margin: 0;
+}
+
+#lang-menu:hover button {
+ display: block;
+}
+
+#lang-menu:hover #lang-menu-items {
+ position: absolute;
+ width: 100%;
+ padding: 0;
+ left: 0;
+ /* must match grid-line height */
+ top: 3.9em;
+}
+
+#lang-menu .active {
+ color: #000;
+}
--- /dev/null
+#big-cite {
+ background-color: white;
+ padding: 10.75em 10em 8.5em 18.2em;
+ margin: 0;
+}
+
+#big-cite a {
+ color: black;
+ display: block;
+}
+
+#big-cite h2 {
+ margin: 0;
+ font-size: 1.1em;
+ color: #575c63;
+}
+
+
+#big-cite-text {
+ margin: .05em;
+ font-size: 2.8em;
+ line-height: 1.2em;
+ color: #191919;
+}
+
+
+#big-cite-source {
+ color: #00a1ac;
+ margin: 0;
+ font-size: 1.1em;
+ margin: 1.1em 0.2em;
+}
+
+
+#promo-box {
+ float: right;
+ width: 32em;
+ margin-top: -5.1em;
+}
+#promo-box-header {
+ padding-top: 2em;
+ height: 3.1em;
+ padding-bottom: 0;
+ padding-left: 2.5em;
+ padding-right: 2.5em;
+ background: #191919;
+ color: white;
+}
+#promo-box-header h2 {
+ font-size: 1.1em;
+ padding-top: .1em;
+}
+#promo-box-body {
+ border-bottom: 2px solid #efefef;
+ padding: 2em 2.8em;
+ height: 30em;
+ background: #efefef;
+}
+#promo-box-title {
+ color: #02ADB7;
+ height: 2.75em;
+ margin: 0;
+}
+#promo-box-title span {
+ font-size: 1.1em;
+}
+#promo-box-body p {
+ margin-top: 0;
+}
+#promo-box-content {
+ font-size: 1.2em;
+ line-height: 1.55em;
+ color: #989898;
+}
+
+.main-last {
+ padding-top: 1.9em;
+ height: 3.2em;
+ padding-left: 1.9em;
+}
+.main-last span {
+ font-size: 1.1em;
+}
+
+
+.infopages-box {
+ width: 20.6em;
+ display: inline-block;
+ margin: .5em 0 0 0;
+ padding: 0 1.7em;
+ vertical-align: top;
+ color: #989898;
+}
+.infopages-box h2 {
+ color: #02ADB7;
+ height: 2.8em;
+ padding-top: 2.5em;
+}
+.infopages-box h2 span {
+ font-size: 1.1em;
+}
+.infopages-box a {
+ color: black;
+}
+
+.infopages-box ol, .infopages-box ul {
+ font-size: 1.1em;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ line-height: 1.45em;
+}
+
+.social-links {
+ margin-top: 1em;
+}
\ No newline at end of file
padding: 0 10px 0 10px;
}
+#formats .wrap div.download .custom-pdf {
+ text-align: left;
+}
+
+
#czytamysluchajac {
margin-top: 2.5em;
}
/* report */
.stats td {
vertical-align: top;
-}
\ No newline at end of file
+}
+
+/* ============ */
+/* = Pictures = */
+/* ============ */
+
+
+#picture-list .picture .title {
+ font-weight: bold;
+}
+
+#picture-list .picture {
+ background-color: white;
+ padding: 0.8em;
+ margin: 0.8em;
+ border: black 1px solid;
+ width: 600px;
+}
+
--- /dev/null
+.picture-mini-box, .picture-box {
+ display: inline-block;
+ margin: 0;
+ vertical-align: top;
+}
+
+
+.picture-box {
+ width: 37.5em;
+}
+
+.picture-mini-box {
+ width: 12.5em;
+}
+
+.picture-mini-box a, .picture-box-inner {
+ display: block;
+ color: black;
+ border: 1px solid #ddd;
+ height: 20em;
+ padding: .75em;
+ margin: .1em;
+ background: #fff;
+ -moz-box-shadow: 2px 2px 2px #ddd;
+ -webkit-box-shadow: 2px 2px 2px #ddd;
+ box-shadow: 2px 2px 2px #ddd;
+ overflow: hidden;
+}
+
+.picture-mini-box a {
+ height: 20em;
+ margin: .1em;
+}
+.picture-box-inner {
+ height: 14.4em;
+ margin: .5em;
+}
+
+.picture-mini-box img, .picture-box img {
+ width: 10.8em;
+ height: 14.4em;
+}
+.picture-mini-box img {
+ margin-bottom: .3em;
+}
+.picture-box img {
+ float: left;
+ margin-right: 1.5em;
+}
+
+.picture-mini-box .author {
+ color: #777;
+}
+
+
+.picture-box-body {
+ height: 13em;
+ overflow: hidden;
+}
+.picture-box-head {
+ min-height: 7em;
+}
+.picture-box-tag {
+ font-size: .8em;
+ margin-right: .5em;
+}
+.picture-box-download {
+ position: relative;
+}
+.picture-box-formats {
+ display: none;
+ top: -2em;
+ position: absolute;
+ height: 2em;
+ width: 100em;
+}
+.picture-box-formats a {
+ margin-right: 1em;
+}
+.picture-box-download:hover .picture-box-formats {
+ display: block;
+}
+
+.picture-box-tools a:before {
+ content: "⇩";
+ font-family: WL-Nav;
+ font-size: 2em;
+ margin-right: .25em;
+ vertical-align: middle;
+}
.sponsors-page {
+ background: white;
margin-top: 6px;
}
width: 150px;
}
+.sponsor-logos {
+ height: 130px;
+}
+
.sponsors-page img {
float: left;
}
--- /dev/null
+/*
+ * jQuery UI CSS Framework 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*
+ * jQuery UI CSS Framework 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
+.ui-widget-content a { color: #333333; }
+.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
+.ui-widget-header a { color: #ffffff; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
+.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
+ * jQuery UI Autocomplete 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete { position: absolute; cursor: default; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.16
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+ float: left;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
--- /dev/null
+/*\r
+ * Skin for jPlayer Plugin (jQuery JavaScript Library)\r
+ * http://www.happyworm.com/jquery/jplayer\r
+ *\r
+ * Skin Name: Blue Monday\r
+ *\r
+ * Copyright (c) 2010-2011 Happyworm Ltd\r
+ * Dual licensed under the MIT and GPL licenses.\r
+ * - http://www.opensource.org/licenses/mit-license.php\r
+ * - http://www.gnu.org/copyleft/gpl.html\r
+ *\r
+ * Author: Silvia Benvenuti\r
+ * Skin Version: 4.0 (jPlayer 2.1.0)\r
+ * Date: 1st September 2011\r
+ */\r
+\r
+div.jp-audio,\r
+div.jp-video {\r
+\r
+ /* Edit the font-size to counteract inherited font sizing.\r
+ * Eg. 1.25em = 1 / 0.8em\r
+ */\r
+\r
+ font-size:1.25em; /* 1.25em for testing in site pages */ /* No parent CSS that can effect the size in the demos ZIP */\r
+\r
+ font-family:Verdana, Arial, sans-serif;\r
+ line-height:1.6;\r
+ color: #666;\r
+ border:1px solid #009be3;\r
+ background-color:#eee;\r
+ position:relative;\r
+}\r
+div.jp-audio {\r
+ width:420px;\r
+}\r
+div.jp-video-270p {\r
+ width:480px;\r
+}\r
+div.jp-video-360p {\r
+ width:640px;\r
+}\r
+div.jp-video-full {\r
+ /* Rules for IE6 (full-screen) */\r
+ width:480px;\r
+ height:270px;\r
+ /* Rules for IE7 (full-screen) - Otherwise the relative container causes other page items that are not position:static (default) to appear over the video/gui. */\r
+ position:static !important; position:relative\r
+}\r
+\r
+div.jp-video-full div.jp-jplayer {\r
+ top: 0;\r
+ left: 0;\r
+ position: fixed !important; position: relative; /* Rules for IE6 (full-screen) */\r
+ overflow: hidden;\r
+ z-index:1000;\r
+}\r
+\r
+div.jp-video-full div.jp-gui {\r
+ position: fixed !important; position: static; /* Rules for IE6 (full-screen) */\r
+ top: 0;\r
+ left: 0;\r
+ width:100%;\r
+ height:100%;\r
+ z-index:1000;\r
+}\r
+\r
+div.jp-video-full div.jp-interface {\r
+ position: absolute !important; position: relative; /* Rules for IE6 (full-screen) */\r
+ bottom: 0;\r
+ left: 0;\r
+ z-index:1000;\r
+}\r
+\r
+div.jp-interface {\r
+ position: relative;\r
+ background-color:#eee;\r
+ width:100%;\r
+}\r
+\r
+div.jp-audio div.jp-type-single div.jp-interface {\r
+ height:80px;\r
+}\r
+div.jp-audio div.jp-type-playlist div.jp-interface {\r
+ height:80px;\r
+}\r
+\r
+div.jp-video div.jp-interface {\r
+ border-top:1px solid #009be3;\r
+}\r
+\r
+/* @group CONTROLS */\r
+\r
+div.jp-controls-holder {\r
+ clear: both;\r
+ width:440px;\r
+ margin:0 auto;\r
+ position: relative;\r
+ overflow:hidden;\r
+ top:-8px; /* This negative value depends on the size of the text in jp-currentTime and jp-duration */\r
+}\r
+\r
+div.jp-interface ul.jp-controls {\r
+ list-style-type:none;\r
+ margin:0;\r
+ padding: 0;
+ overflow:hidden;
+}
+
+div.jp-audio ul.jp-controls {
+ width: 380px;\r
+ padding:20px 20px 0 20px;\r
+}
+
+div.jp-video div.jp-type-single ul.jp-controls {
+ width: 78px;\r
+ margin-left: 200px;\r
+}
+
+div.jp-video div.jp-type-playlist ul.jp-controls {
+ width: 134px;\r
+ margin-left: 172px;\r
+}
+div.jp-video ul.jp-controls,\r
+div.jp-interface ul.jp-controls li {\r
+ display:inline;
+ float: left;
+}\r
+\r
+div.jp-interface ul.jp-controls a {\r
+ display:block;\r
+ overflow:hidden;\r
+ text-indent:-9999px;\r
+}\r
+a.jp-play,\r
+a.jp-pause {\r
+ width:40px;\r
+ height:40px;\r
+}\r
+\r
+a.jp-play {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 0 no-repeat;\r
+}\r
+a.jp-play:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -41px 0 no-repeat;\r
+}\r
+a.jp-pause {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -42px no-repeat;\r
+ display: none;\r
+}\r
+a.jp-pause:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -41px -42px no-repeat;\r
+}\r
+
+a.jp-stop, a.jp-previous, a.jp-next {\r
+ width:28px;\r
+ height:28px;
+ margin-top:6px;\r
+}\r
+
+a.jp-stop {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -83px no-repeat;\r
+ margin-left:10px;
+}
+\r
+a.jp-stop:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -29px -83px no-repeat;\r
+}
+\r
+a.jp-previous {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -112px no-repeat;\r
+}\r
+a.jp-previous:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -29px -112px no-repeat;\r
+}
+
+a.jp-next {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -141px no-repeat;\r
+}\r
+a.jp-next:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -29px -141px no-repeat;\r
+}\r
+\r
+/* @end */\r
+\r
+/* @group progress bar */\r
+\r
+div.jp-progress {\r
+ overflow:hidden;\r
+ background-color: #ddd;\r
+}\r
+div.jp-audio div.jp-progress {\r
+ position: absolute;\r
+ top:32px;\r
+ height:15px;\r
+}\r
+div.jp-audio div.jp-type-single div.jp-progress {\r
+ left:110px;\r
+ width:186px;\r
+}\r
+div.jp-audio div.jp-type-playlist div.jp-progress {\r
+ left:166px;\r
+ width:130px;\r
+}\r
+div.jp-video div.jp-progress {\r
+ top:0px;\r
+ left:0px;\r
+ width:100%;\r
+ height:10px;\r
+}\r
+div.jp-seek-bar {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -202px repeat-x;\r
+ width:0px;\r
+ height:100%;\r
+ cursor: pointer;\r
+}\r
+div.jp-play-bar {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -218px repeat-x ;\r
+ width:0px;\r
+ height:100%;\r
+}\r
+\r
+/* The seeking class is added/removed inside jPlayer */\r
+div.jp-seeking-bg {\r
+ background: url("/static/jplayer/jplayer.blue.monday.seeking.gif");\r
+}\r
+\r
+/* @end */\r
+\r
+/* @group volume controls */\r
+\r
+\r
+a.jp-mute,\r
+a.jp-unmute,\r
+a.jp-volume-max {\r
+ width:18px;\r
+ height:15px;
+ margin-top:12px;
+}
+
+div.jp-audio div.jp-type-single a.jp-mute,\r
+div.jp-audio div.jp-type-single a.jp-unmute {
+ margin-left: 210px;
+}
+
+div.jp-audio div.jp-type-playlist a.jp-mute,\r
+div.jp-audio div.jp-type-playlist a.jp-unmute {
+ margin-left: 154px;\r
+}
+\r
+div.jp-audio a.jp-volume-max {\r
+ margin-left: 56px; \r
+}\r
+\r
+div.jp-video a.jp-mute,\r
+div.jp-video a.jp-unmute,\r
+div.jp-video a.jp-volume-max {\r
+ position: absolute;\r
+ top:12px;\r
+ margin-top:0;\r
+}\r
+\r
+div.jp-video a.jp-mute,\r
+div.jp-video a.jp-unmute {
+ left: 50px;\r
+}
+\r\r
+div.jp-video a.jp-volume-max {\r
+ left: 134px;\r
+}\r
+\r
+a.jp-mute {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -170px no-repeat;\r
+}\r
+a.jp-mute:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -19px -170px no-repeat;\r
+}\r
+a.jp-unmute {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -60px -170px no-repeat;\r
+ display: none;\r
+}\r
+a.jp-unmute:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -79px -170px no-repeat;\r
+}
+\ra.jp-volume-max {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -186px no-repeat;\r
+}\r
+a.jp-volume-max:hover {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -19px -186px no-repeat;\r
+}\r
+
+div.jp-volume-bar {\r
+ position: absolute;\r
+ overflow:hidden;\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -250px repeat-x;\r
+ width:46px;\r
+ height:5px;\r
+ cursor: pointer;\r
+}\r
+div.jp-audio div.jp-volume-bar {\r
+ top:37px;\r
+ left:330px;\r
+}\r
+div.jp-video div.jp-volume-bar {\r
+ top:17px;\r
+ left:72px;\r
+}\r
+div.jp-volume-bar-value {\r
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -256px repeat-x;\r
+ width:0px;\r
+ height:5px;\r
+}\r
+\r
+/* @end */\r
+\r
+/* @group current time and duration */\r
+\r
+div.jp-audio div.jp-time-holder {\r
+ position:absolute;\r
+ top:50px;\r
+}\r
+div.jp-audio div.jp-type-single div.jp-time-holder {\r
+ left:110px;\r
+ width:186px;\r
+}\r
+div.jp-audio div.jp-type-playlist div.jp-time-holder {\r
+ left:166px;\r
+ width:130px;\r
+}\r
+\r
+div.jp-current-time,\r
+div.jp-duration {\r
+ width:60px;\r
+ font-size:.64em;\r
+ font-style:oblique;
+}\r
+div.jp-current-time {\r
+ float: left;\r
+ display:inline;\r
+}\r
+div.jp-duration {\r
+ float: right;\r
+ display:inline;\r
+ text-align: right;\r
+}\r
+\r
+div.jp-video div.jp-current-time {\r
+ margin-left:20px;\r
+}\r
+div.jp-video div.jp-duration {\r
+ margin-right:20px;\r
+}\r
+\r
+/* @end */\r
+\r
+/* @group playlist */\r
+\r
+div.jp-title {\r
+ font-weight:bold;\r
+ text-align:center;\r
+}\r
+\r
+div.jp-title,\r
+div.jp-playlist {\r
+ width:100%;\r
+ background-color:#ccc;\r
+ border-top:1px solid #009be3;\r
+}\r
+div.jp-type-single div.jp-title,\r
+div.jp-type-playlist div.jp-title,\r
+div.jp-type-single div.jp-playlist {\r
+ border-top:none;\r
+}\r
+div.jp-title ul,\r
+div.jp-playlist ul {\r
+ list-style-type:none;\r
+ margin:0;\r
+ padding:0 20px;\r
+ font-size:.72em;\r
+}\r
+\r
+div.jp-title li {\r
+ padding:5px 0;\r
+ font-weight:bold;\r
+}\r
+div.jp-playlist li {\r
+ padding:5px 0 4px 20px;\r
+ border-bottom:1px solid #eee;\r
+}\r
+\r
+div.jp-playlist li div {\r
+ display:inline;\r
+}\r
+\r
+/* Note that the first-child (IE6) and last-child (IE6/7/8) selectors do not work on IE */\r
+\r
+div.jp-type-playlist div.jp-playlist li:last-child {\r
+ padding:5px 0 5px 20px;\r
+ border-bottom:none;\r
+}\r
+div.jp-type-playlist div.jp-playlist li.jp-playlist-current {\r
+ list-style-type:square;\r
+ list-style-position:inside;\r
+ padding-left:7px;\r
+}\r
+div.jp-type-playlist div.jp-playlist a {\r
+ color: #333;\r
+ text-decoration: none;\r
+}\r
+div.jp-type-playlist div.jp-playlist a:hover {\r
+ color:#0d88c1;\r
+}\r
+div.jp-type-playlist div.jp-playlist a.jp-playlist-current {\r
+ color:#0d88c1;\r
+}\r
+\r
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove {\r
+ float:right;\r
+ display:inline;\r
+ text-align:right;\r
+ margin-right:10px;\r
+ font-weight:bold;\r
+ color:#666;\r
+}\r
+div.jp-type-playlist div.jp-playlist a.jp-playlist-item-remove:hover {\r
+ color:#0d88c1;\r
+}\r
+div.jp-type-playlist div.jp-playlist span.jp-free-media {\r
+ float:right;\r
+ display:inline;\r
+ text-align:right;\r
+ margin-right:10px;\r
+}\r
+div.jp-type-playlist div.jp-playlist span.jp-free-media a{\r
+ color:#666;\r
+}\r
+div.jp-type-playlist div.jp-playlist span.jp-free-media a:hover{\r
+ color:#0d88c1;\r
+}\r
+span.jp-artist {\r
+ font-size:.8em;\r
+ color:#666;\r
+}\r
+\r
+/* @end */\r
+\r
+div.jp-video-play {\r
+ position:absolute;\r
+ top:0;\r
+ left:0;\r
+ width:100%;\r
+ cursor:pointer;\r
+ background-color:rgba(0,0,0,0); /* Makes IE9 work with the active area over the whole video area. IE6/7/8 only have the button as active area. */\r
+}\r
+div.jp-video-270p div.jp-video-play {\r
+ height:270px;\r
+}\r
+div.jp-video-360p div.jp-video-play {\r
+ height:360px;\r
+}\r
+div.jp-video-full div.jp-video-play {\r
+ height:100%;\r
+ z-index:1000;\r
+}\r
+a.jp-video-play-icon {\r
+ position:relative;\r
+ display:block;\r
+ width: 112px;\r
+ height: 100px;\r
+\r
+ margin-left:-56px;\r
+ margin-top:-50px;\r
+ left:50%;\r
+ top:50%;\r
+\r
+ background: url("/static/jplayer/jplayer.blue.monday.video.play.png") 0 0 no-repeat;\r
+ text-indent:-9999px;\r
+}\r
+div.jp-video-play:hover a.jp-video-play-icon {\r
+ background: url("/static/jplayer/jplayer.blue.monday.video.play.png") 0 -100px no-repeat;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+div.jp-jplayer audio,\r
+div.jp-jplayer {\r
+ width:0px;\r
+ height:0px;\r
+}\r
+\r
+div.jp-jplayer {\r
+ background-color: #000000;\r
+}
+
+
+
+
+
+/* @group TOGGLES */
+\r
+/* The audio toggles are nested inside jp-time-holder */\r
+
+ul.jp-toggles {
+ list-style-type:none;
+ padding:0;
+ margin:0 auto;\r
+ overflow:hidden;
+}
+
+div.jp-audio .jp-type-single ul.jp-toggles {
+ width:25px;
+}
+div.jp-audio .jp-type-playlist ul.jp-toggles {\r
+ width:55px;\r
+ margin: 0;\r
+ position: absolute;\r
+ left: 325px;\r
+ top: 50px;\r
+}\r
+
+div.jp-video ul.jp-toggles {
+ margin-top:10px;\r
+ width:100px;\r
+}
+
+ul.jp-toggles li {
+ display:block;
+ float:right;
+}
+
+ul.jp-toggles li a {
+ display:block;
+ width:25px;
+ height:18px;
+ text-indent:-9999px;\r
+ line-height:100%; /* need this for IE6 */
+}
+
+a.jp-full-screen {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -310px no-repeat;
+ margin-left: 20px;
+}
+
+a.jp-full-screen:hover {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -30px -310px no-repeat;
+}
+
+a.jp-restore-screen {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -60px -310px no-repeat;
+ margin-left: 20px;\r
+}
+
+a.jp-restore-screen:hover {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -90px -310px no-repeat;
+}
+
+a.jp-repeat {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -290px no-repeat;
+}
+
+a.jp-repeat:hover {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -30px -290px no-repeat;
+}
+
+a.jp-repeat-off {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -60px -290px no-repeat;
+}
+
+a.jp-repeat-off:hover {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -90px -290px no-repeat;
+}
+
+a.jp-shuffle {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") 0 -270px no-repeat;
+ margin-left: 5px;
+}
+
+a.jp-shuffle:hover {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -30px -270px no-repeat;
+}
+
+a.jp-shuffle-off {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -60px -270px no-repeat;
+ margin-left: 5px;\r
+}
+
+a.jp-shuffle-off:hover {
+ background: url("/static/jplayer/jplayer.blue.monday.jpg") -90px -270px no-repeat;
+}
+
+
+/* @end */\r
+\r
+/* @group NO SOLUTION error feedback */\r
+\r
+.jp-no-solution {\r
+ position:absolute;\r
+ width:390px;\r
+ margin-left:-202px;\r
+ left:50%;\r
+ top: 10px;\r
+\r
+ padding:5px;\r
+ font-size:.8em;\r
+ background-color:#eee;\r
+ border:2px solid #009be3;\r
+ color:#000;\r
+ display:none;\r
+}\r
+\r
+.jp-no-solution a {\r
+ color:#000;\r
+}\r
+\r
+.jp-no-solution span {\r
+ font-size:1em;\r
+ display:block;\r
+ text-align:center;\r
+ font-weight:bold;\r
+}\r
+\r
+/* @end */\r
--- /dev/null
+/*
+ * Playlist Object for the jPlayer Plugin
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2011 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Mark J Panaghiston
+ * Version: 2.1.0 (jPlayer 2.1.0)
+ * Date: 1st September 2011
+ */
+
+(function(b,f){jPlayerPlaylist=function(a,c,d){var e=this;this.current=0;this.removing=this.shuffled=this.loop=!1;this.cssSelector=b.extend({},this._cssSelector,a);this.options=b.extend(!0,{},this._options,d);this.playlist=[];this.original=[];this._initPlaylist(c);this.cssSelector.title=this.cssSelector.cssSelectorAncestor+" .jp-title";this.cssSelector.playlist=this.cssSelector.cssSelectorAncestor+" .jp-playlist";this.cssSelector.next=this.cssSelector.cssSelectorAncestor+" .jp-next";this.cssSelector.previous=
+this.cssSelector.cssSelectorAncestor+" .jp-previous";this.cssSelector.shuffle=this.cssSelector.cssSelectorAncestor+" .jp-shuffle";this.cssSelector.shuffleOff=this.cssSelector.cssSelectorAncestor+" .jp-shuffle-off";this.options.cssSelectorAncestor=this.cssSelector.cssSelectorAncestor;this.options.repeat=function(a){e.loop=a.jPlayer.options.loop};b(this.cssSelector.jPlayer).bind(b.jPlayer.event.ready,function(){e._init()});b(this.cssSelector.jPlayer).bind(b.jPlayer.event.ended,function(){e.next()});
+b(this.cssSelector.jPlayer).bind(b.jPlayer.event.play,function(){b(this).jPlayer("pauseOthers")});b(this.cssSelector.jPlayer).bind(b.jPlayer.event.resize,function(a){a.jPlayer.options.fullScreen?b(e.cssSelector.title).show():b(e.cssSelector.title).hide()});b(this.cssSelector.previous).click(function(){e.previous();b(this).blur();return!1});b(this.cssSelector.next).click(function(){e.next();b(this).blur();return!1});b(this.cssSelector.shuffle).click(function(){e.shuffle(!0);return!1});b(this.cssSelector.shuffleOff).click(function(){e.shuffle(!1);
+return!1}).hide();this.options.fullScreen||b(this.cssSelector.title).hide();b(this.cssSelector.playlist+" ul").empty();this._createItemHandlers();b(this.cssSelector.jPlayer).jPlayer(this.options)};jPlayerPlaylist.prototype={_cssSelector:{jPlayer:"#jquery_jplayer_1",cssSelectorAncestor:"#jp_container_1"},_options:{playlistOptions:{autoPlay:!1,loopOnPrevious:!1,shuffleOnLoop:!0,enableRemoveControls:!1,displayTime:"slow",addTime:"fast",removeTime:"fast",shuffleTime:"slow",itemClass:"jp-playlist-item",
+freeGroupClass:"jp-free-media",freeItemClass:"jp-playlist-item-free",removeItemClass:"jp-playlist-item-remove"}},option:function(a,b){if(b===f)return this.options.playlistOptions[a];this.options.playlistOptions[a]=b;switch(a){case "enableRemoveControls":this._updateControls();break;case "itemClass":case "freeGroupClass":case "freeItemClass":case "removeItemClass":this._refresh(!0),this._createItemHandlers()}return this},_init:function(){var a=this;this._refresh(function(){a.options.playlistOptions.autoPlay?
+a.play(a.current):a.select(a.current)})},_initPlaylist:function(a){this.current=0;this.removing=this.shuffled=!1;this.original=b.extend(!0,[],a);this._originalPlaylist()},_originalPlaylist:function(){var a=this;this.playlist=[];b.each(this.original,function(b){a.playlist[b]=a.original[b]})},_refresh:function(a){var c=this;if(a&&!b.isFunction(a))b(this.cssSelector.playlist+" ul").empty(),b.each(this.playlist,function(a){b(c.cssSelector.playlist+" ul").append(c._createListItem(c.playlist[a]))}),this._updateControls();
+else{var d=b(this.cssSelector.playlist+" ul").children().length?this.options.playlistOptions.displayTime:0;b(this.cssSelector.playlist+" ul").slideUp(d,function(){var d=b(this);b(this).empty();b.each(c.playlist,function(a){d.append(c._createListItem(c.playlist[a]))});c._updateControls();b.isFunction(a)&&a();c.playlist.length?b(this).slideDown(c.options.playlistOptions.displayTime):b(this).show()})}},_createListItem:function(a){var c=this,d="<li><div>";d+="<a href='javascript:;' class='"+this.options.playlistOptions.removeItemClass+
+"'>×</a>";if(a.free){var e=!0;d+="<span class='"+this.options.playlistOptions.freeGroupClass+"'>(";b.each(a,function(a,f){b.jPlayer.prototype.format[a]&&(e?e=!1:d+=" | ",d+="<a class='"+c.options.playlistOptions.freeItemClass+"' href='"+f+"' tabindex='1'>"+a+"</a>")});d+=")</span>"}d+="<a href='javascript:;' class='"+this.options.playlistOptions.itemClass+"' tabindex='1'>"+a.title+(a.artist?" <span class='jp-artist'>by "+a.artist+"</span>":"")+"</a>";d+="</div></li>";return d},_createItemHandlers:function(){var a=
+this;b(this.cssSelector.playlist+" a."+this.options.playlistOptions.itemClass).die("click").live("click",function(){var c=b(this).parent().parent().index();a.current!==c?a.play(c):b(a.cssSelector.jPlayer).jPlayer("play");b(this).blur();return!1});b(a.cssSelector.playlist+" a."+this.options.playlistOptions.freeItemClass).die("click").live("click",function(){b(this).parent().parent().find("."+a.options.playlistOptions.itemClass).click();b(this).blur();return!1});b(a.cssSelector.playlist+" a."+this.options.playlistOptions.removeItemClass).die("click").live("click",
+function(){var c=b(this).parent().parent().index();a.remove(c);b(this).blur();return!1})},_updateControls:function(){this.options.playlistOptions.enableRemoveControls?b(this.cssSelector.playlist+" ."+this.options.playlistOptions.removeItemClass).show():b(this.cssSelector.playlist+" ."+this.options.playlistOptions.removeItemClass).hide();this.shuffled?(b(this.cssSelector.shuffleOff).show(),b(this.cssSelector.shuffle).hide()):(b(this.cssSelector.shuffleOff).hide(),b(this.cssSelector.shuffle).show())},
+_highlight:function(a){this.playlist.length&&a!==f&&(b(this.cssSelector.playlist+" .jp-playlist-current").removeClass("jp-playlist-current"),b(this.cssSelector.playlist+" li:nth-child("+(a+1)+")").addClass("jp-playlist-current").find(".jp-playlist-item").addClass("jp-playlist-current"),b(this.cssSelector.title+" li").html(this.playlist[a].title+(this.playlist[a].artist?" <span class='jp-artist'>by "+this.playlist[a].artist+"</span>":"")))},setPlaylist:function(a){this._initPlaylist(a);this._init()},
+add:function(a,c){b(this.cssSelector.playlist+" ul").append(this._createListItem(a)).find("li:last-child").hide().slideDown(this.options.playlistOptions.addTime);this._updateControls();this.original.push(a);this.playlist.push(a);c?this.play(this.playlist.length-1):this.original.length===1&&this.select(0)},remove:function(a){var c=this;if(a===f)return this._initPlaylist([]),this._refresh(function(){b(c.cssSelector.jPlayer).jPlayer("clearMedia")}),!0;else if(this.removing)return!1;else{a=a<0?c.original.length+
+a:a;if(0<=a&&a<this.playlist.length)this.removing=!0,b(this.cssSelector.playlist+" li:nth-child("+(a+1)+")").slideUp(this.options.playlistOptions.removeTime,function(){b(this).remove();if(c.shuffled){var d=c.playlist[a];b.each(c.original,function(a){if(c.original[a]===d)return c.original.splice(a,1),!1})}else c.original.splice(a,1);c.playlist.splice(a,1);c.original.length?a===c.current?(c.current=a<c.original.length?c.current:c.original.length-1,c.select(c.current)):a<c.current&&c.current--:(b(c.cssSelector.jPlayer).jPlayer("clearMedia"),
+c.current=0,c.shuffled=!1,c._updateControls());c.removing=!1});return!0}},select:function(a){a=a<0?this.original.length+a:a;0<=a&&a<this.playlist.length?(this.current=a,this._highlight(a),b(this.cssSelector.jPlayer).jPlayer("setMedia",this.playlist[this.current])):this.current=0},play:function(a){a=a<0?this.original.length+a:a;0<=a&&a<this.playlist.length?this.playlist.length&&(this.select(a),b(this.cssSelector.jPlayer).jPlayer("play")):a===f&&b(this.cssSelector.jPlayer).jPlayer("play")},pause:function(){b(this.cssSelector.jPlayer).jPlayer("pause")},
+next:function(){var a=this.current+1<this.playlist.length?this.current+1:0;this.loop?a===0&&this.shuffled&&this.options.playlistOptions.shuffleOnLoop&&this.playlist.length>1?this.shuffle(!0,!0):this.play(a):a>0&&this.play(a)},previous:function(){var a=this.current-1>=0?this.current-1:this.playlist.length-1;(this.loop&&this.options.playlistOptions.loopOnPrevious||a<this.playlist.length-1)&&this.play(a)},shuffle:function(a,c){var d=this;a===f&&(a=!this.shuffled);(a||a!==this.shuffled)&&b(this.cssSelector.playlist+
+" ul").slideUp(this.options.playlistOptions.shuffleTime,function(){(d.shuffled=a)?d.playlist.sort(function(){return 0.5-Math.random()}):d._originalPlaylist();d._refresh(!0);c||!b(d.cssSelector.jPlayer).data("jPlayer").status.paused?d.play(0):d.select(0);b(this).slideDown(d.options.playlistOptions.shuffleTime)})}}})(jQuery);
\ No newline at end of file
--- /dev/null
+/*
+ * jPlayer Plugin for jQuery JavaScript Library
+ * http://www.jplayer.org
+ *
+ * Copyright (c) 2009 - 2011 Happyworm Ltd
+ * Dual licensed under the MIT and GPL licenses.
+ * - http://www.opensource.org/licenses/mit-license.php
+ * - http://www.gnu.org/copyleft/gpl.html
+ *
+ * Author: Mark J Panaghiston
+ * Version: 2.1.0
+ * Date: 1st September 2011
+ */
+
+(function(b,f){b.fn.jPlayer=function(a){var c=typeof a==="string",d=Array.prototype.slice.call(arguments,1),e=this,a=!c&&d.length?b.extend.apply(null,[!0,a].concat(d)):a;if(c&&a.charAt(0)==="_")return e;c?this.each(function(){var c=b.data(this,"jPlayer"),h=c&&b.isFunction(c[a])?c[a].apply(c,d):c;if(h!==c&&h!==f)return e=h,!1}):this.each(function(){var c=b.data(this,"jPlayer");c?c.option(a||{}):b.data(this,"jPlayer",new b.jPlayer(a,this))});return e};b.jPlayer=function(a,c){if(arguments.length){this.element=
+b(c);this.options=b.extend(!0,{},this.options,a);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()});this._init()}};b.jPlayer.emulateMethods="load play pause";b.jPlayer.emulateStatus="src readyState networkState currentTime duration paused ended playbackRate";b.jPlayer.emulateOptions="muted volume";b.jPlayer.reservedEvent="ready flashreset resize repeat error warning";b.jPlayer.event={ready:"jPlayer_ready",flashreset:"jPlayer_flashreset",resize:"jPlayer_resize",repeat:"jPlayer_repeat",
+click:"jPlayer_click",error:"jPlayer_error",warning:"jPlayer_warning",loadstart:"jPlayer_loadstart",progress:"jPlayer_progress",suspend:"jPlayer_suspend",abort:"jPlayer_abort",emptied:"jPlayer_emptied",stalled:"jPlayer_stalled",play:"jPlayer_play",pause:"jPlayer_pause",loadedmetadata:"jPlayer_loadedmetadata",loadeddata:"jPlayer_loadeddata",waiting:"jPlayer_waiting",playing:"jPlayer_playing",canplay:"jPlayer_canplay",canplaythrough:"jPlayer_canplaythrough",seeking:"jPlayer_seeking",seeked:"jPlayer_seeked",
+timeupdate:"jPlayer_timeupdate",ended:"jPlayer_ended",ratechange:"jPlayer_ratechange",durationchange:"jPlayer_durationchange",volumechange:"jPlayer_volumechange"};b.jPlayer.htmlEvent="loadstart,abort,emptied,stalled,loadedmetadata,loadeddata,canplay,canplaythrough,ratechange".split(",");b.jPlayer.pause=function(){b.each(b.jPlayer.prototype.instances,function(a,b){b.data("jPlayer").status.srcSet&&b.jPlayer("pause")})};b.jPlayer.timeFormat={showHour:!1,showMin:!0,showSec:!0,padHour:!1,padMin:!0,padSec:!0,
+sepHour:":",sepMin:":",sepSec:""};b.jPlayer.convertTime=function(a){var c=new Date(a*1E3),d=c.getUTCHours(),a=c.getUTCMinutes(),c=c.getUTCSeconds(),d=b.jPlayer.timeFormat.padHour&&d<10?"0"+d:d,a=b.jPlayer.timeFormat.padMin&&a<10?"0"+a:a,c=b.jPlayer.timeFormat.padSec&&c<10?"0"+c:c;return(b.jPlayer.timeFormat.showHour?d+b.jPlayer.timeFormat.sepHour:"")+(b.jPlayer.timeFormat.showMin?a+b.jPlayer.timeFormat.sepMin:"")+(b.jPlayer.timeFormat.showSec?c+b.jPlayer.timeFormat.sepSec:"")};b.jPlayer.uaBrowser=
+function(a){var a=a.toLowerCase(),b=/(opera)(?:.*version)?[ \/]([\w.]+)/,d=/(msie) ([\w.]+)/,e=/(mozilla)(?:.*? rv:([\w.]+))?/,a=/(webkit)[ \/]([\w.]+)/.exec(a)||b.exec(a)||d.exec(a)||a.indexOf("compatible")<0&&e.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}};b.jPlayer.uaPlatform=function(a){var b=a.toLowerCase(),d=/(android)/,e=/(mobile)/,a=/(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/.exec(b)||[],b=/(ipad|playbook)/.exec(b)||!e.exec(b)&&d.exec(b)||[];a[1]&&(a[1]=a[1].replace(/\s/g,
+"_"));return{platform:a[1]||"",tablet:b[1]||""}};b.jPlayer.browser={};b.jPlayer.platform={};var i=b.jPlayer.uaBrowser(navigator.userAgent);if(i.browser)b.jPlayer.browser[i.browser]=!0,b.jPlayer.browser.version=i.version;i=b.jPlayer.uaPlatform(navigator.userAgent);if(i.platform)b.jPlayer.platform[i.platform]=!0,b.jPlayer.platform.mobile=!i.tablet,b.jPlayer.platform.tablet=!!i.tablet;b.jPlayer.prototype={count:0,version:{script:"2.1.0",needFlash:"2.1.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",
+supplied:"mp3",preload:"metadata",volume:0.8,muted:!1,wmode:"opaque",backgroundColor:"#000000",cssSelectorAncestor:"#jp_container_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",volumeMax:".jp-volume-max",currentTime:".jp-current-time",duration:".jp-duration",fullScreen:".jp-full-screen",restoreScreen:".jp-restore-screen",
+repeat:".jp-repeat",repeatOff:".jp-repeat-off",gui:".jp-gui",noSolution:".jp-no-solution"},fullScreen:!1,autohide:{restored:!1,full:!0,fadeIn:200,fadeOut:600,hold:1E3},loop:!1,repeat:function(a){a.jPlayer.options.loop?b(this).unbind(".jPlayerRepeat").bind(b.jPlayer.event.ended+".jPlayer.jPlayerRepeat",function(){b(this).jPlayer("play")}):b(this).unbind(".jPlayerRepeat")},nativeVideoControls:{},noFullScreen:{msie:/msie [0-6]/,ipad:/ipad.*?os [0-4]/,iphone:/iphone/,ipod:/ipod/,android_pad:/android [0-3](?!.*?mobile)/,
+android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,webos:/webos/},noVolume:{ipad:/ipad/,iphone:/iphone/,ipod:/ipod/,android_pad:/android(?!.*?mobile)/,android_phone:/android.*?mobile/,blackberry:/blackberry/,windows_ce:/windows ce/,webos:/webos/,playbook:/playbook/},verticalVolume:!1,idPrefix:"jp",noConflict:"jQuery",emulateHtml:!1,errorAlerts:!1,warningAlerts:!1},optionsAudio:{size:{width:"0px",height:"0px",cssClass:""},sizeFull:{width:"0px",height:"0px",cssClass:""}},
+optionsVideo:{size:{width:"480px",height:"270px",cssClass:"jp-video-270p"},sizeFull:{width:"100%",height:"100%",cssClass:"jp-video-full"}},instances:{},status:{src:"",media:{},paused:!0,format:{},formatType:"",waitForPlay:!0,waitForLoad:!0,srcSet:!1,video:!1,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0,readyState:0,networkState:0,playbackRate:1,ended:0},internal:{ready:!1},solution:{html:!0,flash:!0},format:{mp3:{codec:'audio/mpeg; codecs="mp3"',flashCanPlay:!0,
+media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:!0,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis"',flashCanPlay:!1,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:!1,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:!1,media:"audio"},fla:{codec:"audio/x-flv",flashCanPlay:!0,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:!0,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',flashCanPlay:!1,
+media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:!1,media:"video"},flv:{codec:"video/x-flv",flashCanPlay:!0,media:"video"}},_init:function(){var a=this;this.element.empty();this.status=b.extend({},this.status);this.internal=b.extend({},this.internal);this.internal.domNode=this.element.get(0);this.formats=[];this.solutions=[];this.require={};this.htmlElement={};this.html={};this.html.audio={};this.html.video={};this.flash={};this.css={};this.css.cs={};this.css.jq={};this.ancestorJq=
+[];this.options.volume=this._limitValue(this.options.volume,0,1);b.each(this.options.supplied.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.format[e]){var f=!1;b.each(a.formats,function(a,b){if(e===b)return f=!0,!1});f||a.formats.push(e)}});b.each(this.options.solution.toLowerCase().split(","),function(c,d){var e=d.replace(/^\s+|\s+$/g,"");if(a.solution[e]){var f=!1;b.each(a.solutions,function(a,b){if(e===b)return f=!0,!1});f||a.solutions.push(e)}});this.internal.instance=
+"jp_"+this.count;this.instances[this.internal.instance]=this.element;this.element.attr("id")||this.element.attr("id",this.options.idPrefix+"_jplayer_"+this.count);this.internal.self=b.extend({},{id:this.element.attr("id"),jq:this.element});this.internal.audio=b.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:f});this.internal.video=b.extend({},{id:this.options.idPrefix+"_video_"+this.count,jq:f});this.internal.flash=b.extend({},{id:this.options.idPrefix+"_flash_"+this.count,jq:f,swf:this.options.swfPath+
+(this.options.swfPath.toLowerCase().slice(-4)!==".swf"?(this.options.swfPath&&this.options.swfPath.slice(-1)!=="/"?"/":"")+"Jplayer.swf":"")});this.internal.poster=b.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:f});b.each(b.jPlayer.event,function(b,c){a.options[b]!==f&&(a.element.bind(c+".jPlayer",a.options[b]),a.options[b]=f)});this.require.audio=!1;this.require.video=!1;b.each(this.formats,function(b,c){a.require[a.format[c].media]=!0});this.options=this.require.video?b.extend(!0,
+{},this.optionsVideo,this.options):b.extend(!0,{},this.optionsAudio,this.options);this._setSize();this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullScreen=this._uaBlocklist(this.options.noFullScreen);this.status.noVolume=this._uaBlocklist(this.options.noVolume);this._restrictNativeVideoControls();this.htmlElement.poster=document.createElement("img");this.htmlElement.poster.id=this.internal.poster.id;this.htmlElement.poster.onload=function(){(!a.status.video||
+a.status.waitForPlay)&&a.internal.poster.jq.show()};this.element.append(this.htmlElement.poster);this.internal.poster.jq=b("#"+this.internal.poster.id);this.internal.poster.jq.css({width:this.status.width,height:this.status.height});this.internal.poster.jq.hide();this.internal.poster.jq.bind("click.jPlayer",function(){a._trigger(b.jPlayer.event.click)});this.html.audio.available=!1;if(this.require.audio)this.htmlElement.audio=document.createElement("audio"),this.htmlElement.audio.id=this.internal.audio.id,
+this.html.audio.available=!!this.htmlElement.audio.canPlayType&&this._testCanPlayType(this.htmlElement.audio);this.html.video.available=!1;if(this.require.video)this.htmlElement.video=document.createElement("video"),this.htmlElement.video.id=this.internal.video.id,this.html.video.available=!!this.htmlElement.video.canPlayType&&this._testCanPlayType(this.htmlElement.video);this.flash.available=this._checkForFlash(10);this.html.canPlay={};this.flash.canPlay={};b.each(this.formats,function(b,c){a.html.canPlay[c]=
+a.html[a.format[c].media].available&&""!==a.htmlElement[a.format[c].media].canPlayType(a.format[c].codec);a.flash.canPlay[c]=a.format[c].flashCanPlay&&a.flash.available});this.html.desired=!1;this.flash.desired=!1;b.each(this.solutions,function(c,d){if(c===0)a[d].desired=!0;else{var e=!1,f=!1;b.each(a.formats,function(b,c){a[a.solutions[0]].canPlay[c]&&(a.format[c].media==="video"?f=!0:e=!0)});a[d].desired=a.require.audio&&!e||a.require.video&&!f}});this.html.support={};this.flash.support={};b.each(this.formats,
+function(b,c){a.html.support[c]=a.html.canPlay[c]&&a.html.desired;a.flash.support[c]=a.flash.canPlay[c]&&a.flash.desired});this.html.used=!1;this.flash.used=!1;b.each(this.solutions,function(c,d){b.each(a.formats,function(b,c){if(a[d].support[c])return a[d].used=!0,!1})});this._resetActive();this._resetGate();this._cssSelectorAncestor(this.options.cssSelectorAncestor);!this.html.used&&!this.flash.used?(this._error({type:b.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+
+this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SOLUTION,hint:b.jPlayer.errorHint.NO_SOLUTION}),this.css.jq.noSolution.length&&this.css.jq.noSolution.show()):this.css.jq.noSolution.length&&this.css.jq.noSolution.hide();if(this.flash.used){var c,d="jQuery="+encodeURI(this.options.noConflict)+"&id="+encodeURI(this.internal.self.id)+"&vol="+this.options.volume+"&muted="+this.options.muted;if(b.browser.msie&&Number(b.browser.version)<=8){d=['<param name="movie" value="'+this.internal.flash.swf+
+'" />','<param name="FlashVars" value="'+d+'" />','<param name="allowScriptAccess" value="always" />','<param name="bgcolor" value="'+this.options.backgroundColor+'" />','<param name="wmode" value="'+this.options.wmode+'" />'];c=document.createElement('<object id="'+this.internal.flash.id+'" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0"></object>');for(var e=0;e<d.length;e++)c.appendChild(document.createElement(d[e]))}else e=function(a,b,c){var d=document.createElement("param");
+d.setAttribute("name",b);d.setAttribute("value",c);a.appendChild(d)},c=document.createElement("object"),c.setAttribute("id",this.internal.flash.id),c.setAttribute("data",this.internal.flash.swf),c.setAttribute("type","application/x-shockwave-flash"),c.setAttribute("width","1"),c.setAttribute("height","1"),e(c,"flashvars",d),e(c,"allowscriptaccess","always"),e(c,"bgcolor",this.options.backgroundColor),e(c,"wmode",this.options.wmode);this.element.append(c);this.internal.flash.jq=b(c)}if(this.html.used){if(this.html.audio.available)this._addHtmlEventListeners(this.htmlElement.audio,
+this.html.audio),this.element.append(this.htmlElement.audio),this.internal.audio.jq=b("#"+this.internal.audio.id);if(this.html.video.available)this._addHtmlEventListeners(this.htmlElement.video,this.html.video),this.element.append(this.htmlElement.video),this.internal.video.jq=b("#"+this.internal.video.id),this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):this.internal.video.jq.css({width:"0px",height:"0px"}),this.internal.video.jq.bind("click.jPlayer",
+function(){a._trigger(b.jPlayer.event.click)})}this.options.emulateHtml&&this._emulateHtmlBridge();this.html.used&&!this.flash.used&&setTimeout(function(){a.internal.ready=!0;a.version.flash="n/a";a._trigger(b.jPlayer.event.repeat);a._trigger(b.jPlayer.event.ready)},100);this._updateNativeVideoControls();this._updateInterface();this._updateButtons(!1);this._updateAutohide();this._updateVolume(this.options.volume);this._updateMute(this.options.muted);this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();
+b.jPlayer.prototype.count++},destroy:function(){this.clearMedia();this._removeUiClass();this.css.jq.currentTime.length&&this.css.jq.currentTime.text("");this.css.jq.duration.length&&this.css.jq.duration.text("");b.each(this.css.jq,function(a,b){b.length&&b.unbind(".jPlayer")});this.internal.poster.jq.unbind(".jPlayer");this.internal.video.jq&&this.internal.video.jq.unbind(".jPlayer");this.options.emulateHtml&&this._destroyHtmlBridge();this.element.removeData("jPlayer");this.element.unbind(".jPlayer");
+this.element.empty();delete this.instances[this.internal.instance]},enable:function(){},disable:function(){},_testCanPlayType:function(a){try{return a.canPlayType(this.format.mp3.codec),!0}catch(b){return!1}},_uaBlocklist:function(a){var c=navigator.userAgent.toLowerCase(),d=!1;b.each(a,function(a,b){if(b&&b.test(c))return d=!0,!1});return d},_restrictNativeVideoControls:function(){if(this.require.audio&&this.status.nativeVideoControls)this.status.nativeVideoControls=!1,this.status.noFullScreen=!0},
+_updateNativeVideoControls:function(){if(this.html.video.available&&this.html.used)this.htmlElement.video.controls=this.status.nativeVideoControls,this._updateAutohide(),this.status.nativeVideoControls&&this.require.video?(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height})):this.status.waitForPlay&&this.status.video&&(this.internal.poster.jq.show(),this.internal.video.jq.css({width:"0px",height:"0px"}))},_addHtmlEventListeners:function(a,
+c){var d=this;a.preload=this.options.preload;a.muted=this.options.muted;a.volume=this.options.volume;a.addEventListener("progress",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.progress))},!1);a.addEventListener("timeupdate",function(){c.gate&&(d._getHtmlStatus(a),d._updateInterface(),d._trigger(b.jPlayer.event.timeupdate))},!1);a.addEventListener("durationchange",function(){if(c.gate)d.status.duration=this.duration,d._getHtmlStatus(a),d._updateInterface(),
+d._trigger(b.jPlayer.event.durationchange)},!1);a.addEventListener("play",function(){c.gate&&(d._updateButtons(!0),d._html_checkWaitForPlay(),d._trigger(b.jPlayer.event.play))},!1);a.addEventListener("playing",function(){c.gate&&(d._updateButtons(!0),d._seeked(),d._trigger(b.jPlayer.event.playing))},!1);a.addEventListener("pause",function(){c.gate&&(d._updateButtons(!1),d._trigger(b.jPlayer.event.pause))},!1);a.addEventListener("waiting",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.waiting))},
+!1);a.addEventListener("seeking",function(){c.gate&&(d._seeking(),d._trigger(b.jPlayer.event.seeking))},!1);a.addEventListener("seeked",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.seeked))},!1);a.addEventListener("volumechange",function(){if(c.gate)d.options.volume=a.volume,d.options.muted=a.muted,d._updateMute(),d._updateVolume(),d._trigger(b.jPlayer.event.volumechange)},!1);a.addEventListener("suspend",function(){c.gate&&(d._seeked(),d._trigger(b.jPlayer.event.suspend))},!1);a.addEventListener("ended",
+function(){if(c.gate){if(!b.jPlayer.browser.webkit)d.htmlElement.media.currentTime=0;d.htmlElement.media.pause();d._updateButtons(!1);d._getHtmlStatus(a,!0);d._updateInterface();d._trigger(b.jPlayer.event.ended)}},!1);a.addEventListener("error",function(){if(c.gate&&(d._updateButtons(!1),d._seeked(),d.status.srcSet))clearTimeout(d.internal.htmlDlyCmdId),d.status.waitForLoad=!0,d.status.waitForPlay=!0,d.status.video&&!d.status.nativeVideoControls&&d.internal.video.jq.css({width:"0px",height:"0px"}),
+d._validString(d.status.media.poster)&&!d.status.nativeVideoControls&&d.internal.poster.jq.show(),d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show(),d._error({type:b.jPlayer.error.URL,context:d.status.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL})},!1);b.each(b.jPlayer.htmlEvent,function(e,g){a.addEventListener(this,function(){c.gate&&d._trigger(b.jPlayer.event[g])},!1)})},_getHtmlStatus:function(a,b){var d=0,e=0,g=0,f=0;if(a.duration)this.status.duration=a.duration;d=a.currentTime;
+e=this.status.duration>0?100*d/this.status.duration:0;typeof a.seekable==="object"&&a.seekable.length>0?(g=this.status.duration>0?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100,f=100*a.currentTime/a.seekable.end(a.seekable.length-1)):(g=100,f=e);b&&(e=f=d=0);this.status.seekPercent=g;this.status.currentPercentRelative=f;this.status.currentPercentAbsolute=e;this.status.currentTime=d;this.status.readyState=a.readyState;this.status.networkState=a.networkState;this.status.playbackRate=
+a.playbackRate;this.status.ended=a.ended},_resetStatus:function(){this.status=b.extend({},this.status,b.jPlayer.prototype.status)},_trigger:function(a,c,d){a=b.Event(a);a.jPlayer={};a.jPlayer.version=b.extend({},this.version);a.jPlayer.options=b.extend(!0,{},this.options);a.jPlayer.status=b.extend(!0,{},this.status);a.jPlayer.html=b.extend(!0,{},this.html);a.jPlayer.flash=b.extend(!0,{},this.flash);if(c)a.jPlayer.error=b.extend({},c);if(d)a.jPlayer.warning=b.extend({},d);this.element.trigger(a)},
+jPlayerFlashEvent:function(a,c){if(a===b.jPlayer.event.ready)if(this.internal.ready){if(this.flash.gate){if(this.status.srcSet){var d=this.status.currentTime,e=this.status.paused;this.setMedia(this.status.media);d>0&&(e?this.pause(d):this.play(d))}this._trigger(b.jPlayer.event.flashreset)}}else this.internal.ready=!0,this.internal.flash.jq.css({width:"0px",height:"0px"}),this.version.flash=c.version,this.version.needFlash!==this.version.flash&&this._error({type:b.jPlayer.error.VERSION,context:this.version.flash,
+message:b.jPlayer.errorMsg.VERSION+this.version.flash,hint:b.jPlayer.errorHint.VERSION}),this._trigger(b.jPlayer.event.repeat),this._trigger(a);if(this.flash.gate)switch(a){case b.jPlayer.event.progress:this._getFlashStatus(c);this._updateInterface();this._trigger(a);break;case b.jPlayer.event.timeupdate:this._getFlashStatus(c);this._updateInterface();this._trigger(a);break;case b.jPlayer.event.play:this._seeked();this._updateButtons(!0);this._trigger(a);break;case b.jPlayer.event.pause:this._updateButtons(!1);
+this._trigger(a);break;case b.jPlayer.event.ended:this._updateButtons(!1);this._trigger(a);break;case b.jPlayer.event.click:this._trigger(a);break;case b.jPlayer.event.error:this.status.waitForLoad=!0;this.status.waitForPlay=!0;this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"});this._validString(this.status.media.poster)&&this.internal.poster.jq.show();this.css.jq.videoPlay.length&&this.status.video&&this.css.jq.videoPlay.show();this.status.video?this._flash_setVideo(this.status.media):
+this._flash_setAudio(this.status.media);this._updateButtons(!1);this._error({type:b.jPlayer.error.URL,context:c.src,message:b.jPlayer.errorMsg.URL,hint:b.jPlayer.errorHint.URL});break;case b.jPlayer.event.seeking:this._seeking();this._trigger(a);break;case b.jPlayer.event.seeked:this._seeked();this._trigger(a);break;case b.jPlayer.event.ready:break;default:this._trigger(a)}return!1},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent;this.status.currentPercentRelative=a.currentPercentRelative;
+this.status.currentPercentAbsolute=a.currentPercentAbsolute;this.status.currentTime=a.currentTime;this.status.duration=a.duration;this.status.readyState=4;this.status.networkState=0;this.status.playbackRate=1;this.status.ended=!1},_updateButtons:function(a){if(a!==f)this.status.paused=!a,this.css.jq.play.length&&this.css.jq.pause.length&&(a?(this.css.jq.play.hide(),this.css.jq.pause.show()):(this.css.jq.play.show(),this.css.jq.pause.hide()));this.css.jq.restoreScreen.length&&this.css.jq.fullScreen.length&&
+(this.status.noFullScreen?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.hide()):this.options.fullScreen?(this.css.jq.fullScreen.hide(),this.css.jq.restoreScreen.show()):(this.css.jq.fullScreen.show(),this.css.jq.restoreScreen.hide()));this.css.jq.repeat.length&&this.css.jq.repeatOff.length&&(this.options.loop?(this.css.jq.repeat.hide(),this.css.jq.repeatOff.show()):(this.css.jq.repeat.show(),this.css.jq.repeatOff.hide()))},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+
+"%");this.css.jq.playBar.length&&this.css.jq.playBar.width(this.status.currentPercentRelative+"%");this.css.jq.currentTime.length&&this.css.jq.currentTime.text(b.jPlayer.convertTime(this.status.currentTime));this.css.jq.duration.length&&this.css.jq.duration.text(b.jPlayer.convertTime(this.status.duration))},_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg")},
+_resetGate:function(){this.html.audio.gate=!1;this.html.video.gate=!1;this.flash.gate=!1},_resetActive:function(){this.html.active=!1;this.flash.active=!1},setMedia:function(a){var c=this,d=!1,e=this.status.media.poster!==a.poster;this._resetMedia();this._resetGate();this._resetActive();b.each(this.formats,function(e,f){var i=c.format[f].media==="video";b.each(c.solutions,function(b,e){if(c[e].support[f]&&c._validString(a[f])){var g=e==="html";i?(g?(c.html.video.gate=!0,c._html_setVideo(a),c.html.active=
+!0):(c.flash.gate=!0,c._flash_setVideo(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.show(),c.status.video=!0):(g?(c.html.audio.gate=!0,c._html_setAudio(a),c.html.active=!0):(c.flash.gate=!0,c._flash_setAudio(a),c.flash.active=!0),c.css.jq.videoPlay.length&&c.css.jq.videoPlay.hide(),c.status.video=!1);d=!0;return!1}});if(d)return!1});if(d){if((!this.status.nativeVideoControls||!this.html.video.gate)&&this._validString(a.poster))e?this.htmlElement.poster.src=a.poster:this.internal.poster.jq.show();
+this.status.srcSet=!0;this.status.media=b.extend({},a);this._updateButtons(!1);this._updateInterface()}else this._error({type:b.jPlayer.error.NO_SUPPORT,context:"{supplied:'"+this.options.supplied+"'}",message:b.jPlayer.errorMsg.NO_SUPPORT,hint:b.jPlayer.errorHint.NO_SUPPORT})},_resetMedia:function(){this._resetStatus();this._updateButtons(!1);this._updateInterface();this._seeked();this.internal.poster.jq.hide();clearTimeout(this.internal.htmlDlyCmdId);this.html.active?this._html_resetMedia():this.flash.active&&
+this._flash_resetMedia()},clearMedia:function(){this._resetMedia();this.html.active?this._html_clearMedia():this.flash.active&&this._flash_clearMedia();this._resetGate();this._resetActive()},load:function(){this.status.srcSet?this.html.active?this._html_load():this.flash.active&&this._flash_load():this._urlNotSetError("load")},play:function(a){a=typeof a==="number"?a:NaN;this.status.srcSet?this.html.active?this._html_play(a):this.flash.active&&this._flash_play(a):this._urlNotSetError("play")},videoPlay:function(){this.play()},
+pause:function(a){a=typeof a==="number"?a:NaN;this.status.srcSet?this.html.active?this._html_pause(a):this.flash.active&&this._flash_pause(a):this._urlNotSetError("pause")},pauseOthers:function(){var a=this;b.each(this.instances,function(b,d){a.element!==d&&d.data("jPlayer").status.srcSet&&d.jPlayer("pause")})},stop:function(){this.status.srcSet?this.html.active?this._html_pause(0):this.flash.active&&this._flash_pause(0):this._urlNotSetError("stop")},playHead:function(a){a=this._limitValue(a,0,100);
+this.status.srcSet?this.html.active?this._html_playHead(a):this.flash.active&&this._flash_playHead(a):this._urlNotSetError("playHead")},_muted:function(a){this.options.muted=a;this.html.used&&this._html_mute(a);this.flash.used&&this._flash_mute(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateMute(a),this._updateVolume(this.options.volume),this._trigger(b.jPlayer.event.volumechange))},mute:function(a){a=a===f?!0:!!a;this._muted(a)},unmute:function(a){a=a===f?!0:!!a;this._muted(!a)},_updateMute:function(a){if(a===
+f)a=this.options.muted;this.css.jq.mute.length&&this.css.jq.unmute.length&&(this.status.noVolume?(this.css.jq.mute.hide(),this.css.jq.unmute.hide()):a?(this.css.jq.mute.hide(),this.css.jq.unmute.show()):(this.css.jq.mute.show(),this.css.jq.unmute.hide()))},volume:function(a){a=this._limitValue(a,0,1);this.options.volume=a;this.html.used&&this._html_volume(a);this.flash.used&&this._flash_volume(a);!this.html.video.gate&&!this.html.audio.gate&&(this._updateVolume(a),this._trigger(b.jPlayer.event.volumechange))},
+volumeBar:function(a){if(this.css.jq.volumeBar.length){var b=this.css.jq.volumeBar.offset(),d=a.pageX-b.left,e=this.css.jq.volumeBar.width(),a=this.css.jq.volumeBar.height()-a.pageY+b.top,b=this.css.jq.volumeBar.height();this.options.verticalVolume?this.volume(a/b):this.volume(d/e)}this.options.muted&&this._muted(!1)},volumeBarValue:function(a){this.volumeBar(a)},_updateVolume:function(a){if(a===f)a=this.options.volume;a=this.options.muted?0:a;this.status.noVolume?(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.hide(),
+this.css.jq.volumeBarValue.length&&this.css.jq.volumeBarValue.hide(),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.hide()):(this.css.jq.volumeBar.length&&this.css.jq.volumeBar.show(),this.css.jq.volumeBarValue.length&&(this.css.jq.volumeBarValue.show(),this.css.jq.volumeBarValue[this.options.verticalVolume?"height":"width"](a*100+"%")),this.css.jq.volumeMax.length&&this.css.jq.volumeMax.show())},volumeMax:function(){this.volume(1);this.options.muted&&this._muted(!1)},_cssSelectorAncestor:function(a){var c=
+this;this.options.cssSelectorAncestor=a;this._removeUiClass();this.ancestorJq=a?b(a):[];a&&this.ancestorJq.length!==1&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.ancestorJq.length+" found for cssSelectorAncestor.",hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT});this._addUiClass();b.each(this.options.cssSelector,function(a,b){c._cssSelector(a,b)})},_cssSelector:function(a,c){var d=this;typeof c==="string"?b.jPlayer.prototype.options.cssSelector[a]?
+(this.css.jq[a]&&this.css.jq[a].length&&this.css.jq[a].unbind(".jPlayer"),this.options.cssSelector[a]=c,this.css.cs[a]=this.options.cssSelectorAncestor+" "+c,this.css.jq[a]=c?b(this.css.cs[a]):[],this.css.jq[a].length&&this.css.jq[a].bind("click.jPlayer",function(c){d[a](c);b(this).blur();return!1}),c&&this.css.jq[a].length!==1&&this._warning({type:b.jPlayer.warning.CSS_SELECTOR_COUNT,context:this.css.cs[a],message:b.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.css.jq[a].length+" found for "+a+" method.",
+hint:b.jPlayer.warningHint.CSS_SELECTOR_COUNT})):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_METHOD,context:a,message:b.jPlayer.warningMsg.CSS_SELECTOR_METHOD,hint:b.jPlayer.warningHint.CSS_SELECTOR_METHOD}):this._warning({type:b.jPlayer.warning.CSS_SELECTOR_STRING,context:c,message:b.jPlayer.warningMsg.CSS_SELECTOR_STRING,hint:b.jPlayer.warningHint.CSS_SELECTOR_STRING})},seekBar:function(a){if(this.css.jq.seekBar){var b=this.css.jq.seekBar.offset(),a=a.pageX-b.left,b=this.css.jq.seekBar.width();
+this.playHead(100*a/b)}},playBar:function(a){this.seekBar(a)},repeat:function(){this._loop(!0)},repeatOff:function(){this._loop(!1)},_loop:function(a){if(this.options.loop!==a)this.options.loop=a,this._updateButtons(),this._trigger(b.jPlayer.event.repeat)},currentTime:function(){},duration:function(){},gui:function(){},noSolution:function(){},option:function(a,c){var d=a;if(arguments.length===0)return b.extend(!0,{},this.options);if(typeof a==="string"){var e=a.split(".");if(c===f){for(var d=b.extend(!0,
+{},this.options),g=0;g<e.length;g++)if(d[e[g]]!==f)d=d[e[g]];else return this._warning({type:b.jPlayer.warning.OPTION_KEY,context:a,message:b.jPlayer.warningMsg.OPTION_KEY,hint:b.jPlayer.warningHint.OPTION_KEY}),f;return d}for(var g=d={},h=0;h<e.length;h++)h<e.length-1?(g[e[h]]={},g=g[e[h]]):g[e[h]]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(a,b){c._setOption(a,b)});return this},_setOption:function(a,c){var d=this;switch(a){case "volume":this.volume(c);
+break;case "muted":this._muted(c);break;case "cssSelectorAncestor":this._cssSelectorAncestor(c);break;case "cssSelector":b.each(c,function(a,b){d._cssSelector(a,b)});break;case "fullScreen":this.options[a]!==c&&(this._removeUiClass(),this.options[a]=c,this._refreshSize());break;case "size":!this.options.fullScreen&&this.options[a].cssClass!==c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "sizeFull":this.options.fullScreen&&this.options[a].cssClass!==
+c.cssClass&&this._removeUiClass();this.options[a]=b.extend({},this.options[a],c);this._refreshSize();break;case "autohide":this.options[a]=b.extend({},this.options[a],c);this._updateAutohide();break;case "loop":this._loop(c);break;case "nativeVideoControls":this.options[a]=b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this._restrictNativeVideoControls();this._updateNativeVideoControls();break;case "noFullScreen":this.options[a]=
+b.extend({},this.options[a],c);this.status.nativeVideoControls=this._uaBlocklist(this.options.nativeVideoControls);this.status.noFullScreen=this._uaBlocklist(this.options.noFullScreen);this._restrictNativeVideoControls();this._updateButtons();break;case "noVolume":this.options[a]=b.extend({},this.options[a],c);this.status.noVolume=this._uaBlocklist(this.options.noVolume);this._updateVolume();this._updateMute();break;case "emulateHtml":this.options[a]!==c&&((this.options[a]=c)?this._emulateHtmlBridge():
+this._destroyHtmlBridge())}return this},_refreshSize:function(){this._setSize();this._addUiClass();this._updateSize();this._updateButtons();this._updateAutohide();this._trigger(b.jPlayer.event.resize)},_setSize:function(){this.options.fullScreen?(this.status.width=this.options.sizeFull.width,this.status.height=this.options.sizeFull.height,this.status.cssClass=this.options.sizeFull.cssClass):(this.status.width=this.options.size.width,this.status.height=this.options.size.height,this.status.cssClass=
+this.options.size.cssClass);this.element.css({width:this.status.width,height:this.status.height})},_addUiClass:function(){this.ancestorJq.length&&this.ancestorJq.addClass(this.status.cssClass)},_removeUiClass:function(){this.ancestorJq.length&&this.ancestorJq.removeClass(this.status.cssClass)},_updateSize:function(){this.internal.poster.jq.css({width:this.status.width,height:this.status.height});!this.status.waitForPlay&&this.html.active&&this.status.video||this.html.video.available&&this.html.used&&
+this.status.nativeVideoControls?this.internal.video.jq.css({width:this.status.width,height:this.status.height}):!this.status.waitForPlay&&this.flash.active&&this.status.video&&this.internal.flash.jq.css({width:this.status.width,height:this.status.height})},_updateAutohide:function(){var a=this,b=function(){a.css.jq.gui.fadeIn(a.options.autohide.fadeIn,function(){clearTimeout(a.internal.autohideId);a.internal.autohideId=setTimeout(function(){a.css.jq.gui.fadeOut(a.options.autohide.fadeOut)},a.options.autohide.hold)})};
+this.css.jq.gui.length&&(this.css.jq.gui.stop(!0,!0),clearTimeout(this.internal.autohideId),this.element.unbind(".jPlayerAutohide"),this.css.jq.gui.unbind(".jPlayerAutohide"),this.status.nativeVideoControls?this.css.jq.gui.hide():this.options.fullScreen&&this.options.autohide.full||!this.options.fullScreen&&this.options.autohide.restored?(this.element.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.bind("mousemove.jPlayer.jPlayerAutohide",b),this.css.jq.gui.hide()):this.css.jq.gui.show())},
+fullScreen:function(){this._setOption("fullScreen",!0)},restoreScreen:function(){this._setOption("fullScreen",!1)},_html_initMedia:function(){this.htmlElement.media.src=this.status.src;this.options.preload!=="none"&&this._html_load();this._trigger(b.jPlayer.event.timeupdate)},_html_setAudio:function(a){var c=this;b.each(this.formats,function(b,e){if(c.html.support[e]&&a[e])return c.status.src=a[e],c.status.format[e]=!0,c.status.formatType=e,!1});this.htmlElement.media=this.htmlElement.audio;this._html_initMedia()},
+_html_setVideo:function(a){var c=this;b.each(this.formats,function(b,e){if(c.html.support[e]&&a[e])return c.status.src=a[e],c.status.format[e]=!0,c.status.formatType=e,!1});if(this.status.nativeVideoControls)this.htmlElement.video.poster=this._validString(a.poster)?a.poster:"";this.htmlElement.media=this.htmlElement.video;this._html_initMedia()},_html_resetMedia:function(){this.htmlElement.media&&(this.htmlElement.media.id===this.internal.video.id&&!this.status.nativeVideoControls&&this.internal.video.jq.css({width:"0px",
+height:"0px"}),this.htmlElement.media.pause())},_html_clearMedia:function(){if(this.htmlElement.media)this.htmlElement.media.src="",this.htmlElement.media.load()},_html_load:function(){if(this.status.waitForLoad)this.status.waitForLoad=!1,this.htmlElement.media.load();clearTimeout(this.internal.htmlDlyCmdId)},_html_play:function(a){var b=this;this._html_load();this.htmlElement.media.play();if(!isNaN(a))try{this.htmlElement.media.currentTime=a}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.play(a)},
+100);return}this._html_checkWaitForPlay()},_html_pause:function(a){var b=this;a>0?this._html_load():clearTimeout(this.internal.htmlDlyCmdId);this.htmlElement.media.pause();if(!isNaN(a))try{this.htmlElement.media.currentTime=a}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.pause(a)},100);return}a>0&&this._html_checkWaitForPlay()},_html_playHead:function(a){var b=this;this._html_load();try{if(typeof this.htmlElement.media.seekable==="object"&&this.htmlElement.media.seekable.length>0)this.htmlElement.media.currentTime=
+a*this.htmlElement.media.seekable.end(this.htmlElement.media.seekable.length-1)/100;else if(this.htmlElement.media.duration>0&&!isNaN(this.htmlElement.media.duration))this.htmlElement.media.currentTime=a*this.htmlElement.media.duration/100;else throw"e";}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.playHead(a)},100);return}this.status.waitForLoad||this._html_checkWaitForPlay()},_html_checkWaitForPlay:function(){if(this.status.waitForPlay)this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&
+this.css.jq.videoPlay.hide(),this.status.video&&(this.internal.poster.jq.hide(),this.internal.video.jq.css({width:this.status.width,height:this.status.height}))},_html_volume:function(a){if(this.html.audio.available)this.htmlElement.audio.volume=a;if(this.html.video.available)this.htmlElement.video.volume=a},_html_mute:function(a){if(this.html.audio.available)this.htmlElement.audio.muted=a;if(this.html.video.available)this.htmlElement.video.muted=a},_flash_setAudio:function(a){var c=this;try{if(b.each(this.formats,
+function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4a":case "fla":c._getMovie().fl_setAudio_m4a(a[d]);break;case "mp3":c._getMovie().fl_setAudio_mp3(a[d])}c.status.src=a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),this.options.preload==="auto")this._flash_load(),this.status.waitForLoad=!1}catch(d){this._flashError(d)}},_flash_setVideo:function(a){var c=this;try{if(b.each(this.formats,function(b,d){if(c.flash.support[d]&&a[d]){switch(d){case "m4v":case "flv":c._getMovie().fl_setVideo_m4v(a[d])}c.status.src=
+a[d];c.status.format[d]=!0;c.status.formatType=d;return!1}}),this.options.preload==="auto")this._flash_load(),this.status.waitForLoad=!1}catch(d){this._flashError(d)}},_flash_resetMedia:function(){this.internal.flash.jq.css({width:"0px",height:"0px"});this._flash_pause(NaN)},_flash_clearMedia:function(){try{this._getMovie().fl_clearMedia()}catch(a){this._flashError(a)}},_flash_load:function(){try{this._getMovie().fl_load()}catch(a){this._flashError(a)}this.status.waitForLoad=!1},_flash_play:function(a){try{this._getMovie().fl_play(a)}catch(b){this._flashError(b)}this.status.waitForLoad=
+!1;this._flash_checkWaitForPlay()},_flash_pause:function(a){try{this._getMovie().fl_pause(a)}catch(b){this._flashError(b)}if(a>0)this.status.waitForLoad=!1,this._flash_checkWaitForPlay()},_flash_playHead:function(a){try{this._getMovie().fl_play_head(a)}catch(b){this._flashError(b)}this.status.waitForLoad||this._flash_checkWaitForPlay()},_flash_checkWaitForPlay:function(){if(this.status.waitForPlay)this.status.waitForPlay=!1,this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide(),this.status.video&&
+(this.internal.poster.jq.hide(),this.internal.flash.jq.css({width:this.status.width,height:this.status.height}))},_flash_volume:function(a){try{this._getMovie().fl_volume(a)}catch(b){this._flashError(b)}},_flash_mute:function(a){try{this._getMovie().fl_mute(a)}catch(b){this._flashError(b)}},_getMovie:function(){return document[this.internal.flash.id]},_checkForFlash:function(a){var b=!1,d;if(window.ActiveXObject)try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+a),b=!0}catch(e){}else navigator.plugins&&
+navigator.mimeTypes.length>0&&(d=navigator.plugins["Shockwave Flash"])&&navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/,"$1")>=a&&(b=!0);return b},_validString:function(a){return a&&typeof a==="string"},_limitValue:function(a,b,d){return a<b?b:a>d?d:a},_urlNotSetError:function(a){this._error({type:b.jPlayer.error.URL_NOT_SET,context:a,message:b.jPlayer.errorMsg.URL_NOT_SET,hint:b.jPlayer.errorHint.URL_NOT_SET})},_flashError:function(a){var c;c=this.internal.ready?"FLASH_DISABLED":
+"FLASH";this._error({type:b.jPlayer.error[c],context:this.internal.flash.swf,message:b.jPlayer.errorMsg[c]+a.message,hint:b.jPlayer.errorHint[c]});this.internal.flash.jq.css({width:"1px",height:"1px"})},_error:function(a){this._trigger(b.jPlayer.event.error,a);this.options.errorAlerts&&this._alert("Error!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_warning:function(a){this._trigger(b.jPlayer.event.warning,f,a);this.options.warningAlerts&&this._alert("Warning!"+
+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_alert:function(a){alert("jPlayer "+this.version.script+" : id='"+this.internal.self.id+"' : "+a)},_emulateHtmlBridge:function(){var a=this;b.each(b.jPlayer.emulateMethods.split(/\s+/g),function(b,d){a.internal.domNode[d]=function(b){a[d](b)}});b.each(b.jPlayer.event,function(c,d){var e=!0;b.each(b.jPlayer.reservedEvent.split(/\s+/g),function(a,b){if(b===c)return e=!1});e&&a.element.bind(d+".jPlayer.jPlayerHtml",
+function(){a._emulateHtmlUpdate();var b=document.createEvent("Event");b.initEvent(c,!1,!0);a.internal.domNode.dispatchEvent(b)})})},_emulateHtmlUpdate:function(){var a=this;b.each(b.jPlayer.emulateStatus.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.status[d]});b.each(b.jPlayer.emulateOptions.split(/\s+/g),function(b,d){a.internal.domNode[d]=a.options[d]})},_destroyHtmlBridge:function(){var a=this;this.element.unbind(".jPlayerHtml");b.each((b.jPlayer.emulateMethods+" "+b.jPlayer.emulateStatus+
+" "+b.jPlayer.emulateOptions).split(/\s+/g),function(b,d){delete a.internal.domNode[d]})}};b.jPlayer.error={FLASH:"e_flash",FLASH_DISABLED:"e_flash_disabled",NO_SOLUTION:"e_no_solution",NO_SUPPORT:"e_no_support",URL:"e_url",URL_NOT_SET:"e_url_not_set",VERSION:"e_version"};b.jPlayer.errorMsg={FLASH:"jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ",FLASH_DISABLED:"jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ",
+NO_SOLUTION:"No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.",NO_SUPPORT:"It is not possible to play any media format provided in setMedia() on this browser using your current options.",URL:"Media URL could not be loaded.",URL_NOT_SET:"Attempt to issue media playback commands, while no media url is set.",VERSION:"jPlayer "+b.jPlayer.prototype.version.script+" needs Jplayer.swf version "+b.jPlayer.prototype.version.needFlash+" but found "};b.jPlayer.errorHint=
+{FLASH:"Check your swfPath option and that Jplayer.swf is there.",FLASH_DISABLED:"Check that you have not display:none; the jPlayer entity or any ancestor.",NO_SOLUTION:"Review the jPlayer options: support and supplied.",NO_SUPPORT:"Video or audio formats defined in the supplied option are missing.",URL:"Check media URL is valid.",URL_NOT_SET:"Use setMedia() to set the media URL.",VERSION:"Update jPlayer files."};b.jPlayer.warning={CSS_SELECTOR_COUNT:"e_css_selector_count",CSS_SELECTOR_METHOD:"e_css_selector_method",
+CSS_SELECTOR_STRING:"e_css_selector_string",OPTION_KEY:"e_option_key"};b.jPlayer.warningMsg={CSS_SELECTOR_COUNT:"The number of css selectors found did not equal one: ",CSS_SELECTOR_METHOD:"The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",CSS_SELECTOR_STRING:"The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",OPTION_KEY:"The option requested in jPlayer('option') is undefined."};b.jPlayer.warningHint={CSS_SELECTOR_COUNT:"Check your css selector and the ancestor.",
+CSS_SELECTOR_METHOD:"Check your method name.",CSS_SELECTOR_STRING:"Check your css selector is a string.",OPTION_KEY:"Check your option name."}})(jQuery);
\ No newline at end of file
--- /dev/null
+(function($) {
+ $(function() {
+ $.fn.toggle_slide = function(p) {
+ cont = $(this);
+ short_el = p['short_el'] || $(':first-child', this);
+ long_el = p['long_el'] || short_el.next();
+ button = p['button'];
+ short_text = p['short_text'],
+ long_text = p['long_text'];
+
+ var toggle_fun = function(cont, short_el, long_el, button, short_text, long_text) {
+ var toggle = function() {
+ if (cont.hasClass('short')) {
+ cont.animate({"height": long_el.attr("cont_h")+'px'}, {duration: "fast" }).removeClass('short');
+ short_el.hide();
+ long_el.show();
+ if (button && long_text) button.html(long_text);
+ } else {
+ cont.animate({"height": short_el.attr("cont_h")+'px'}, {duration: "fast" }).addClass('short');
+ long_el.hide();
+ short_el.show();
+ if (button && short_text) button.html(short_text);
+ }
+ return false;
+ }
+ return toggle;
+ }
+ if (long_el.html().length <= short_el.html().length)
+ return;
+
+ // ensure long element shown first
+ long_el.show();short_el.hide();
+ long_el.attr("cont_h", $(this).height()).hide();
+ short_el.show().attr("cont_h", $(this).height());
+ $(this).addClass('short');
+
+ if (button && short_text) button.html(short_text);
+ if (button) button.hover(
+ function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
+ function() { $(this).css({background: '#EEE'}); }
+ ).click(toggle_fun(cont, short_el, long_el, button, short_text, long_text));
+ short_el.hover(
+ function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
+ function() { $(this).css({background: '#FFF'}); }
+ ).click(toggle_fun(cont, short_el, long_el, button, short_text, long_text));
+ long_el.hover(
+ function() { $(this).css({background: '#F3F3F3', cursor: 'pointer'}); },
+ function() { $(this).css({background: '#FFF'}); }
+ ).click(toggle_fun(cont, short_el, long_el, button, short_text, long_text));
+ };
+
+
+ // Fragments
+ $('.fragment-short-text').each(function() {
+ var fragment = $(this).closest('.fragment');
+ fragment.toggle_slide({
+ short_el: $(this),
+ long_el: fragment.find('.fragment-text')
+ })
+ });
+
+
+
+
+
+
+$('#themes-list-toggle').click(function(event) {
+ event.preventDefault();
+ $('#themes-list').toggle('slow');
+});
+
+
+$('.open-player').click(function(event) {
+ event.preventDefault();
+ window.open($(this).attr('href'),
+ 'player',
+ 'width=420, height=500'
+ );
+});
+
+
+ $('.book-list-index').click(function(){
+ $('.book-list-show-index').hide('slow');
+ if($(this).parent().next('ul:not(:hidden)').length == 0){
+ $(this).parent().next('ul').toggle('slow');
+ }
+ return false;
+ });
+
+
+ });
+})(jQuery)
+
}
}
-function autocomplete_result_handler(event, item) {
- $(event.target).closest('form').submit();
+function autocomplete_format_item(ul, item) {
+ return $("<li></li>").data('item.autocomplete', item)
+ .append('<a href="'+item.url+'">'+item.label+ ' ('+item.category+')</a>')
+ .appendTo(ul);
}
+
+function autocomplete_result_handler(event, ui) {
+ if (ui.item.url != undefined) {
+ location.href = ui.item.url;
+ } else {
+ $(event.target).closest('form').submit();
+ }
+}
+
function serverTime() {
var time = null;
$.ajax({url: '/katalog/zegar/',
}
});
}*/
-
+ $("#custom-pdf-link").toggle(
+ function(ev) { $(".custom-pdf").show(); return false; },
+ function(ev) { $(".custom-pdf").hide(); return false; }
+ );
});
})(jQuery)
--- /dev/null
+(function($) {
+ $(function() {
+
+ // create containers for all ajaxable form links
+ $('.ajaxable').each(function() {
+ var $window = $("#ajaxable-window").clone();
+ $window.attr("id", this.id + "-window");
+ $('body').append($window);
+
+ var trigger = '#' + this.id;
+
+ var href = $(this).attr('href');
+ if (href.search('\\?') != -1)
+ href += '&ajax=1';
+ else href += '?ajax=1';
+
+ $window.jqm({
+ ajax: href,
+ ajaxText: '<p><img src="' + STATIC_URL + 'img/indicator.gif" alt="*"/> ' + gettext("Loading") + '</p>',
+ target: $('.target', $window)[0],
+ overlay: 60,
+ trigger: trigger,
+ onShow: function(hash) {
+ var offset = $(hash.t).offset();
+ hash.w.css({position: 'absolute', left: offset.left - hash.w.width() + $(hash.t).width(), top: offset.top});
+ $('.header', hash.w).css({width: $(hash.t).width()});
+ hash.w.show();
+ },
+ onLoad: function(hash) {
+ $('form', hash.w).each(function() {
+ if (this.action.search('[\\?&]ajax=1') != -1)
+ return;
+ if (this.action.search('\\?') != -1)
+ this.action += '&ajax=1';
+ else this.action += '?ajax=1';
+ });
+ $('form', hash.w).ajaxForm({
+ dataType: 'json',
+ target: $('.target', $window),
+ success: function(response) {
+ if (response.success) {
+ $('.target', $window).text(response.message);
+ setTimeout(function() { $window.jqmHide() }, 1000);
+ if (response.redirect)
+ window.location = response.redirect;
+ }
+ else {
+ $('.error', $window).remove();
+ $.each(response.errors, function(id, errors) {
+ $('#id_' + id, $window).before('<span class="error">' + errors[0] + '</span>');
+ });
+ $('input[type=submit]', $window).removeAttr('disabled');
+ return false;
+ }
+ }
+ });
+ }
+ });
+ });
+
+
+ });
+})(jQuery)
+
--- /dev/null
+/*!
+ * jQuery UI 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.16",
+keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({propAttr:c.fn.prop||c.fn.attr,_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=
+this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,
+"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":
+"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,
+outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,
+"tabindex"),d=isNaN(b);return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&
+a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&
+c.ui.isOverAxis(b,e,i)}})}})(jQuery);
+;/*!
+ * jQuery UI Widget 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)try{b(d).triggerHandler("remove")}catch(e){}k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(d){}});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=
+function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):
+d;if(e&&d.charAt(0)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=
+b.extend(true,{},this.options,this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+
+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",
+c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
+;/*!
+ * jQuery UI Mouse 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ */
+(function(b){var d=false;b(document).mouseup(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+
+this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"&&a.target.nodeName?b(a.target).closest(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=
+this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&&
+!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=
+false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
+;/*
+ * jQuery UI Position 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
+left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
+m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
+d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
+a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
+g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
+;/*
+ * jQuery UI Draggable 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
+"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
+this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;if(b.iframeFix)d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;
+this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});
+this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true},
+_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=
+false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,
+10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||
+!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&
+a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=
+this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),
+10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),
+10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,
+(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!=
+"hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),
+10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+
+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&
+!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.left<g[0])e=g[0]+this.offset.click.left;
+if(a.pageY-this.offset.click.top<g[1])h=g[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>g[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.top<g[1]||h-this.offset.click.top>g[3])?h:!(h-this.offset.click.top<g[1])?h-b.grid[1]:h+b.grid[1]:h;e=b.grid[0]?this.originalPageX+Math.round((e-this.originalPageX)/
+b.grid[0])*b.grid[0]:this.originalPageX;e=g?!(e-this.offset.click.left<g[0]||e-this.offset.click.left>g[2])?e:!(e-this.offset.click.left<g[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<
+526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,
+c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.16"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var h=d.data(this,"sortable");if(h&&!h.options.disabled){c.sortables.push({instance:h,shouldRevert:h.options.revert});
+h.refreshPositions();h._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=
+false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",true);
+this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;
+c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&
+this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=
+a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!=
+"x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<
+c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-
+c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,
+width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,h=b.offset.left,g=h+c.helperProportions.width,n=b.offset.top,o=n+c.helperProportions.height,i=c.snapElements.length-1;i>=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e<h&&h<l+e&&k-e<n&&n<m+e||j-e<h&&h<l+e&&k-e<o&&o<m+e||j-e<g&&g<l+e&&k-e<n&&n<m+e||j-e<g&&g<l+e&&k-e<o&&
+o<m+e){if(f.snapMode!="inner"){var p=Math.abs(k-o)<=e,q=Math.abs(m-n)<=e,r=Math.abs(j-g)<=e,s=Math.abs(l-h)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left}var t=
+p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(k-n)<=e;q=Math.abs(m-o)<=e;r=Math.abs(j-h)<=e;s=Math.abs(l-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&&
+(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||q||r||s||t}else{c.snapElements[i].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
+10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
+;/*
+ * jQuery UI Autocomplete 1.8.16
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.propAttr("readOnly"))){g=
+false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=
+a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};
+this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&&
+a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");
+d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&
+b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source=
+this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();
+this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||
+b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this;
+d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,
+"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery);
+(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
+-1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");
+this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b,
+this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||
+this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||
+this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[d.fn.prop?"prop":"attr"]("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery);
+;
\ No newline at end of file
/*
* jqModal - Minimalist Modaling with jQuery
+ * (http://dev.iceburg.net/jquery/jqModal/)
*
- * Copyright (c) 2007 Brice Burgess <bhb@iceburg.net>, http://www.iceburg.net
- * Licensed under the MIT License:
- * http://www.opensource.org/licenses/mit-license.php
- *
- * $Version: 2007.??.?? +r12 beta
- * Requires: jQuery 1.1.3+
+ * Copyright (c) 2007,2008 Brice Burgess <bhb@iceburg.net>
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * $Version: 03/01/2009 +r14
*/
(function($) {
-/**
- * Initialize a set of elements as "modals". Modals typically are popup dialogs,
- * notices, modal windows, and image containers. An expando ("_jqm") containing
- * the UUID or "serial" of the modal is added to each element. This expando helps
- * reference the modal's settings in the jqModal Hash Object (jQuery.jqm.hash)
- *
- * Accepts a parameter object with the following modal settings;
- *
- * (Integer) zIndex - Desired z-Index of the modal. This setting does not override (has no effect on) preexisting z-Index styling (set via CSS or inline style).
- * (Integer) overlay - [0-100] Translucency percentage (opacity) of the body covering overlay. Set to 0 for NO overlay, and up to 100 for a 100% opaque overlay.
- * (String) overlayClass - This class is applied to the body covering overlay. Allows CSS control of the overlay look (tint, background image, etc.).
- * (String) closeClass - A close trigger is added to all elements matching this class within the modal.
- * (Mixed) trigger - An open trigger is added to all matching elements within the DOM. Trigger can be a selector String, a jQuery collection of elements, a DOM element, or a False boolean.
- * (Mixed) ajax - If not false; The URL (string) to load content from via an AJAX request.
- * If ajax begins with a "@", the URL is extracted from the requested attribute of the triggering element.
- * (Mixed) target - If not false; The element within the modal to load the ajax response (content) into. Allows retention of modal design (e.g. framing and close elements are not overwritten by the AJAX response).
- * Target may be a selector string, jQuery collection of elements, or a DOM element -- but MUST exist within (as a child of) the modal.
- * (Boolean) modal - If true, user interactivity will be locked to the modal window until closed.
- * (Boolean) toTop - If true, modal will be posistioned as a first child of the BODY element when opened, and its DOM posistion restored when closed. This aids in overcoming z-Index stacking order/containment issues where overlay covers whole page *including* modal.
- * (Mixed) onShow - User defined callback function fired when modal opened.
- * (Mixed) onHide - User defined callback function fired when modal closed.
- * (Mixed) onLoad - User defined callback function fired when ajax content loads.
- *
- * @name jqm
- * @param Map options User defined settings for the modal(s).
- * @type jQuery
- * @cat Plugins/jqModal
- */
-$.fn.jqm=function(p){
-var o = {
-zIndex: 3000,
+$.fn.jqm=function(o){
+var p={
overlay: 50,
overlayClass: 'jqmOverlay',
closeClass: 'jqmClose',
trigger: '.jqModal',
-ajax: false,
-target: false,
-modal: false,
-toTop: false,
-onShow: false,
-onHide: false,
-onLoad: false
+ajax: F,
+ajaxText: '',
+target: F,
+modal: F,
+toTop: F,
+onShow: F,
+onHide: F,
+onLoad: F
};
-
-// For each element (aka "modal") $.jqm() has been called on;
-// IF the _jqm expando exists, return (do nothing)
-// ELSE increment serials and add _jqm expando to element ("serialization")
-// *AND*...
-return this.each(function(){if(this._jqm)return;s++;this._jqm=s;
-
-// ... Add this element's serial to the jqModal Hash Object
-// Hash is globally accessible via jQuery.jqm.hash. It consists of;
-// c: {obj} config/options
-// a: {bool} active state (true: active/visible, false: inactive/hidden)
-// w: {JQ DOM Element} The modal element (window/dialog/notice/etc. container)
-// s: {int} The serial number of this modal (same as "H[s].w[0]._jqm")
-// t: {DOM Element} The triggering element
-// *AND* ...
-H[s]={c:$.extend(o,p),a:false,w:$(this).addClass('jqmID'+s),s:s};
-
-// ... Attach events to trigger showing of this modal
-o.trigger&&$(this).jqmAddTrigger(o.trigger);
+return this.each(function(){if(this._jqm)return H[this._jqm].c=$.extend({},H[this._jqm].c,o);s++;this._jqm=s;
+H[s]={c:$.extend(p,$.jqm.params,o),a:F,w:$(this).addClass('jqmID'+s),s:s};
+if(p.trigger)$(this).jqmAddTrigger(p.trigger);
});};
-// Adds behavior to triggering elements via the hide-show (HS) function.
-//
-$.fn.jqmAddClose=function(e){return HS(this,e,'jqmHide');};
-$.fn.jqmAddTrigger=function(e){return HS(this,e,'jqmShow');};
-
-// Hide/Show a modal -- first check if it is already shown or hidden via the toggle state (H[{modal serial}].a)
-$.fn.jqmShow=function(t){return this.each(function(){!H[this._jqm].a&&$.jqm.open(this._jqm,t)});};
-$.fn.jqmHide=function(t){return this.each(function(){H[this._jqm].a&&$.jqm.close(this._jqm,t)});};
+$.fn.jqmAddClose=function(e){return hs(this,e,'jqmHide');};
+$.fn.jqmAddTrigger=function(e){return hs(this,e,'jqmShow');};
+$.fn.jqmShow=function(t){return this.each(function(){t=t||window.event;$.jqm.open(this._jqm,t);});};
+$.fn.jqmHide=function(t){return this.each(function(){t=t||window.event;$.jqm.close(this._jqm,t)});};
$.jqm = {
hash:{},
-
-// Function is executed by $.jqmShow to show a modal
-// s: {INT} serial of modal
-// t: {DOM Element} the triggering element
-
-// set local shortcuts
-// h: {obj} this Modal's "hash"
-// c: {obj} (h.c) config/options
-// cc: {STR} closing class ('.'+h.c.closeClass)
-// z: {INT} z-Index of Modal. If the Modal (h.w) has the z-index style set it will use this value before defaulting to the one passed in the config (h.c.zIndex)
-// o: The overlay object
-// mark this modal as active (h.a === true)
-// set the triggering object (h.t) and the modal's z-Index.
-open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=/^\d+$/.test(h.w.css('z-index'))&&h.w.css('z-index')||c.zIndex,o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});h.t=t;h.a=true;h.w.css('z-index',z);
-
- // IF the modal argument was passed as true;
- // Bind the Keep Focus Function if no other Modals are open (!A[0]),
- // Add this modal to the opened modals stack (A) for nested modal support,
- // and Mark overlay to show wait cursor when mouse hovers over it.
- if(c.modal) {!A[0]&&F('bind');A.push(s);o.css('cursor','wait');}
-
- // ELSE IF an overlay was requested (translucency set greater than 0);
- // Attach a Close event to overlay to hide modal when overlay is clicked.
+open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=(parseInt(h.w.css('z-index'))),z=(z>0)?z:3000,o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});if(h.a)return F;h.t=t;h.a=true;h.w.css('z-index',z);
+ if(c.modal) {if(!A[0])L('bind');A.push(s);}
else if(c.overlay > 0)h.w.jqmAddClose(o);
+ else o=F;
- // ELSE disable the overlay
- else o=false;
+ h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):F;
+ if(ie6){$('html,body').css({height:'100%',width:'100%'});if(o){o=o.css({position:'absolute'})[0];for(var y in {Top:1,Left:1})o.style.setExpression(y.toLowerCase(),"(_=(document.documentElement.scroll"+y+" || document.body.scroll"+y+"))+'px'");}}
- // Add the Overlay to BODY if not disabled.
- h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):false;
-
- // IF IE6;
- // Set the Overlay to 100% height/width, and fix-position it via JS workaround
- if(ie6&&$('html,body').css({height:'100%',width:'100%'})&&o){o=o.css({position:'absolute'})[0];for(var y in {Top:1,Left:1})o.style.setExpression(y.toLowerCase(),"(_=(document.documentElement.scroll"+y+" || document.body.scroll"+y+"))+'px'");}
-
- // IF the modal's content is to be loaded via ajax;
- // determine the target element {JQ} to recieve content (r),
- // determine the URL {STR} to load content from (u)
if(c.ajax) {var r=c.target||h.w,u=c.ajax,r=(typeof r == 'string')?$(r,h.w):$(r),u=(u.substr(0,1) == '@')?$(t).attr(u.substring(1)):u;
+ r.html(c.ajaxText).load(u,function(){if(c.onLoad)c.onLoad.call(this,h);if(cc)h.w.jqmAddClose($(cc,h.w));e(h);});}
+ else if(cc)h.w.jqmAddClose($(cc,h.w));
- // Load the Content (and once loaded);
- // Fire the onLoad callback (if exists),
- // Attach closing events to elements inside the modal that match the closingClass,
- // and Execute the jqModal default Open Callback
- r.load(u,function(){c.onLoad&&c.onLoad.call(this,h);cc&&h.w.jqmAddClose($(cc,h.w));O(h);});}
-
- // ELSE the modal content is NOT to be loaded via ajax;
- // Attach closing events to elements inside the modal that match the closingClass
- else cc&&h.w.jqmAddClose($(cc,h.w));
-
- // IF toTop was passed and an overlay exists;
- // Remember the DOM posistion of the modal by inserting a tagged (matching serial) <SPAN> before the modal
- // Move the Modal from its current position to a first child of the body tag (after the overlay)
- c.toTop&&h.o&&h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);
-
- // Execute user defined onShow callback, or else show (make visible) the modal.
- // Execute the jqModal default Open Callback.
- // Return false to prevent trigger click from being followed.
- (c.onShow)?c.onShow(h):h.w.show();O(h);return false;
-
+ if(c.toTop&&h.o)h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);
+ (c.onShow)?c.onShow(h):h.w.show();e(h);return F;
},
-
-// Function is executed by $.jqmHide to hide a modal
- // mark this modal as inactive (h.a === false)
-close:function(s){var h=H[s];h.a=false;
- // If modal, remove from modal stack.
- // If no modals in modal stack, unbind the Keep Focus Function
- if(h.c.modal){A.pop();!A[0]&&F('unbind');}
-
- // IF toTop was passed and an overlay exists;
- // Move modal back to its previous ("remembered") position.
- h.c.toTop&&h.o&&$('#jqmP'+h.w[0]._jqm).after(h.w).remove();
-
- // Execute user defined onHide callback, or else hide (make invisible) the modal and remove the overlay.
- if(h.c.onHide)h.c.onHide(h);else{h.w.hide()&&h.o&&h.o.remove()}return false;
-}};
-
-// set jqModal scope shortcuts;
-// s: {INT} serials placeholder
-// H: {HASH} shortcut to jqModal Hash Object
-// A: {ARRAY} Array of active/visible modals
-// ie6: {bool} True if client browser is Internet Explorer 6
-// i: {JQ, DOM Element} iframe placeholder used to prevent active-x bleedthrough in IE6
-// NOTE: It is important to include the iframe styling (iframe.jqm) in your CSS!
-// *AND* ...
-var s=0,H=$.jqm.hash,A=[],ie6=$.browser.msie&&($.browser.version == "6.0"),i=$('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({opacity:0}),
-
-// O: The jqModal default Open Callback;
-// IF ie6; Add the iframe to the overlay (if overlay exists) OR to the modal (if an iframe doesn't already exist from a previous opening)
-// Execute the Modal Focus Function
-O=function(h){if(ie6)h.o&&h.o.html('<p style="width:100%;height:100%"/>').prepend(i)||(!$('iframe.jqm',h.w)[0]&&h.w.prepend(i)); f(h);},
-
-// f: The Modal Focus Function;
-// Attempt to focus the first visible input within the modal
-f=function(h){try{$(':input:visible',h.w)[0].focus();}catch(e){}},
-
-// F: The Keep Focus Function;
-// Binds or Unbinds (t) the Focus Examination Function to keypresses and clicks
-F=function(t){$()[t]("keypress",x)[t]("keydown",x)[t]("mousedown",x);},
-
-// x: The Focus Examination Function;
-// Fetch the current modal's Hash as h (supports nested modals)
-// Determine if the click/press falls within the modal. If not (r===true);
-// call the Modal Focus Function and prevent click/press follow-through (return false [!true])
-// ELSE if so (r===false); follow event (return true [!false])
-x=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);r&&f(h);return !r;},
-
-// hide-show function; assigns click events to trigger elements that
-// hide, show, or hide AND show modals.
-
-// Expandos (jqmShow and/or jqmHide) are added to all trigger elements.
-// These Expandos hold an array of modal serials {INT} to show or hide.
-
-// w: {DOM Element} The modal element (window/dialog/notice/etc. container)
-// e: {DOM Elemet||jQ Selector String} The triggering element
-// y: {String} Type (jqmHide||jqmShow)
-
-// s: {array} the serial number of passed modals, calculated below;
-HS=function(w,e,y){var s=[];w.each(function(){s.push(this._jqm)});
-
-// for each triggering element attach the jqmHide or jqmShow expando (y)
-// or else expand the expando with the current serial array
- $(e).each(function(){if(this[y])$.extend(this[y],s);
-
- // Assign a click event on the trigger element which examines the element's
- // jqmHide/Show expandos and attempts to execute $.jqmHide/Show on matching modals
- else{this[y]=s;$(this).click(function(){for(var i in {jqmShow:1,jqmHide:1})for(var s in this[i])if(H[this[i][s]])H[this[i][s]].w[i](this);return false;});}});return w;};
+close:function(s){var h=H[s];if(!h.a)return F;h.a=F;
+ if(A[0]){A.pop();if(!A[0])L('unbind');}
+ if(h.c.toTop&&h.o)$('#jqmP'+h.w[0]._jqm).after(h.w).remove();
+ if(h.c.onHide)h.c.onHide(h);else{h.w.hide();if(h.o)h.o.remove();} return F;
+},
+params:{}};
+var s=0,H=$.jqm.hash,A=[],ie6=$.browser.msie&&($.browser.version == "6.0"),F=false,
+i=$('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({opacity:0}),
+e=function(h){if(ie6)if(h.o)h.o.html('<p style="width:100%;height:100%"/>').prepend(i);else if(!$('iframe.jqm',h.w)[0])h.w.prepend(i); f(h);},
+f=function(h){try{$(':input:visible',h.w)[0].focus();}catch(_){}},
+L=function(t){$()[t]("keypress",m)[t]("keydown",m)[t]("mousedown",m);},
+m=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);if(r)f(h);return !r;},
+hs=function(w,t,c){return w.each(function(){var s=this._jqm;$(t).each(function() {
+ if(!this[c]){this[c]=[];$(this).click(function(){for(var i in {jqmShow:1,jqmHide:1})for(var s in this[i])if(H[this[i][s]])H[this[i][s]].w[i](this);return F;});}this[c].push(s);});});};
})(jQuery);
\ No newline at end of file
--- /dev/null
+var LOCALE_TEXTS = {
+ "pl": {
+ "Loading": "Ładowanie"
+ },
+ "de": {
+ "Loading": "Herunterladen"
+ },
+ "fr": {
+ "Loading": "Chargement"
+ },
+ "en": {
+ "Loading": "Loading"
+ },
+ "ru": {
+ "Loading": "Загрузка"
+ },
+ "es": {
+ "Loading": "Cargando"
+ },
+ "lt":{
+ "Loading": "Krovimas"
+ },
+ "uk":{
+ "Loading": "Завантажується"
+ }
+}
+function gettext(text) {
+ return LOCALE_TEXTS[LANGUAGE_CODE][text];
+}
\ No newline at end of file
--- /dev/null
+(function($) {
+ $(function() {
+
+
+ $('#countdown').each(function() {
+ var $this = $(this);
+
+ var serverTime = function() {
+ var time = null;
+ $.ajax({url: '/zegar/',
+ async: false, dataType: 'text',
+ success: function(text) {
+ time = new Date(text);
+ }, error: function(http, message, exc) {
+ time = new Date();
+ }});
+ return time;
+ }
+
+ if (LANGUAGE_CODE != 'en') {
+ $.countdown.setDefaults($.countdown.regional[LANGUAGE_CODE]);
+ }
+ else {
+ $.countdown.setDefaults($.countdown.regional['']);
+ }
+
+ var d = new Date($this.attr('data-year'), 0, 1);
+ function re() {location.reload()};
+ $this.countdown({until: d, format: 'ydHMS', serverSync: serverTime,
+ onExpiry: re, alwaysExpire: true});
+
+ });
+
+
+ });
+})(jQuery)
\ No newline at end of file
--- /dev/null
+(function($) {
+ $(function() {
+
+
+ $("#jplayer").jPlayer({
+ swfPath: "/static/jplayer/",
+ solution: "html,flash",
+ supplied: $(this).attr('data-supplied'),
+
+ ready: function() {
+ var player = $(this);
+ var setMedia = function(elem) {
+ var li = $(elem).parent();
+ $('.jp-playlist-current').removeClass('jp-playlist-current');
+ $(li).addClass('jp-playlist-current');
+ var media = {}
+
+ $('.mp3', li).each(function() {media['mp3'] = $(this).attr('href')});
+ $('.ogg', li).each(function() {media['oga'] = $(this).attr('href')});
+
+ return player.jPlayer("setMedia", media);
+ };
+ setMedia($('.play').first()).jPlayer("play");
+
+ $('.play').click(function() {
+ setMedia(this).jPlayer("play");
+ });
+ }
+ });
+
+
+ });
+})(jQuery)
\ No newline at end of file
--- /dev/null
+
+var __bind = function (self, fn) {
+ return function() { fn.apply(self, arguments); };
+};
+
+(function($){
+ $.widget("wl.search", {
+ options: {
+ minLength: 0,
+ },
+
+ _create: function() {
+ var opts = {
+ minLength: this.options.minLength,
+ select: __bind(this, this.enter),
+ focus: function() { return false; },
+ source: this.element.data('source'),
+ };
+ this.element.autocomplete(opts).data("autocomplete")._renderItem = __bind(this, this.render_item);
+ },
+
+ enter: function(event, ui) {
+ if (ui.item.url != undefined) {
+ location.href = ui.item.url;
+ } else {
+ this.element.closest('form').submit();
+ }
+ },
+
+ render_item: function (ul, item) {
+ return $("<li></li>").data('item.autocomplete', item)
+ .append('<a href="'+item.url+'">'+item.label+ ' ('+item.category+')</a>')
+ .appendTo(ul);
+ },
+
+ destroy: function() {
+
+ },
+
+
+
+ });
+
+ $(function() {
+ $("#search").search().labelify({labelledClass: "blur"});
+ });
+
+
+})(jQuery);
--- /dev/null
+(function($) {
+ $(function() {
+
+ $('.sponsor-logos').cycle({timeout: 3000});
+
+ });
+})(jQuery)
+
<Image height="16" width="16" type="image/x-icon">http://www.wolnelektury.pl/static/img/favicon.ico</Image>
<Image height="64" width="64" type="image/png">http://www.wolnelektury.pl/static/img/wl_icon_64.png</Image>
<Url type="application/atom+xml;profile=opds-catalog"
- template="http://www.wolnelektury.pl/opds/search/?q={searchTerms}" />
+ template="http://www.wolnelektury.pl/opds/search/?q={searchTerms}&author={atom:author}&translator={atom:contributor}&title={atom:title}" />
<Url type="text/html" method="GET" template="http://www.wolnelektury.pl/katalog/szukaj?q={searchTerms}" />
<Url type="application/x-suggestions+json" method="GET" template="http://www.wolnelektury.pl/katalog/jtags?mozhint=1&q={searchTerms}" />
<moz:SearchForm>http://www.wolnelektury.pl/katalog/</moz:SearchForm>
background-color: #EEE;
cursor: default;
}
+
+.sponsors-sponsor img {
+ max-width: 120px;
+ max-height: 120px;
+}
+{% extends "base.html" %}
{% load i18n %}
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="pl" xml:lang="pl">
-<head>
-<title>404 - {% trans "Page does not exist" %} - WolneLektury.pl</title>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.2/build/reset/reset-min.css">
-<link rel="stylesheet" href="{{ STATIC_URL }}css/error.css" type="text/css" />
-</head>
-
-<body>
-
-<a href="/"><img src="{{ STATIC_URL }}img/logo.png" /></a>
-<p class="haj" style="font-weight: bold">{% trans "Page does not exist" %}</p>
+
+
+{% block titleextra %}404 - {% trans "Page does not exist" %}{% endblock %}
+
+
+{% block body %}
+
+<h1>{% trans "Page not found" %}</h1>
+
+
<p>
{% trans "We are sorry, but this page does not exist. Please check if you entered correct address or go to "%} <a href="/">{% trans "main page" %}</a>.
</p>
-<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
-</script>
-<script type="text/javascript">
- _uacct = "UA-2576694-1";
- urchinTracker();
-</script>
-</body>
-</html>
\ No newline at end of file
+
+
+{% endblock body %}
+++ /dev/null
-{% extends "base.html" %}
-{% load i18n %}
-
-{% block title %}{% trans "Sign in" %} / {% trans "Register on"%} WolneLektury.pl{% endblock %}
-
-{% block body %}
- <h1>{% trans "Sign in" %} / {% trans "Register"%}</h1>
- <form action="." method="get" accept-charset="utf-8" id="search-form">
- <p><li>{{ search_form.q }} <input type="submit" value="{% trans "Search" %}" /></li> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
- <form method="post" action="." id="login-form" class="cuteform">
- <h2>{% trans "Sign in" %}</h2>
- <ol>
- {{ form.as_ul }}
- <li><input type="submit" value="{% trans "Sign in" %}" /></li>
- </ol>
- <p><input type="hidden" name="next" value="{{ next }}" /></p>
- </form>
-
- <form action="." method="post" accept-charset="utf-8" id="registration-form">
- <h2>{% trans "Register" %}</h2>
-
- <p><input type="submit" value="{% trans "Register" %}"/></p>
- </form>
-{% endblock %}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
- {% load i18n chunks compressed catalogue_tags sponsor_tags %}
+ {% load i18n compressed catalogue_tags sponsor_tags %}
+ {% load reporting_stats %}
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="description"
content="{% block metadescription %}Darmowe opracowane, pełne teksty lektur, e-booki, audiobooki i pliki DAISY na wolnej licencji.{% endblock %}" />
- <title>{% block title %}WolneLektury.pl{% endblock %}</title>
+ <title>{% block title %}{% trans "Wolne Lektury" %} ::
+ {% block titleextra %}{% endblock %}{% endblock %}</title>
<link rel="icon" href="{{ STATIC_URL }}img/favicon.png" type="image/png" />
<link rel="search" type="application/opensearchdescription+xml" title="Wolne Lektury" href="{{ STATIC_URL }}opensearch.xml" />
{% compressed_css "all" %}
- <script type="text/javascript">var LANGUAGE_CODE = "{{ LANGUAGE_CODE }}";</script>
- {% compressed_js "jquery" %}
- {% compressed_js "all" %}
+
{% block extrahead %}
{% endblock %}
</head>
<body id="{% block bodyid %}base{% endblock %}">
- <!--[if lt IE 7]><link href={{ STATIC_URL }}infobar/infobar.css rel=stylesheet>
- <div id=infobar><a href=http://browsehappy.pl/infobar>
- {% trans "Internet Explorer cannot display this site properly. Click here to read more..." %}
- </a></div><div id=viewplot><script src={{ STATIC_URL }}infobar/infobar.js></script><![endif]-->
+
{% block bodycontent %}
- <div id="top-message">
- {% chunk "top-message" %}
- </div>
+
<div id="header">
+
+ <div id="header-content">
<div id="logo">
- <a class="logo" href="/"><img src="{% block logo_url %}{{ STATIC_URL }}img/logo-bez.png{% endblock %}" alt="WolneLektury.pl" />
- <br/>szkolna biblioteka internetowa</a>
- {% block tagline %}{% endblock %}
+ <a class="logo" href="/">
+ Wolne Lektury</a>
+ </div>
+
+ <div id="tagline">
+ <span>
+ {% count_books book_count %}
+ {% url book_list as b %}
+ {% url book_list as r %}
+ {% 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 %}
+ </span>
</div>
- <div id="user-info" style="display:none">
+
+ <p id="user-info" class="mono">
{% if user.is_authenticated %}
- <p>
- {% trans "Welcome" %}, <strong>{{ user.username }}</strong>
- | <a href="{% url user_shelves %}" id="user-shelves-link">{% trans "Your shelves" %}</a>
- {% if user.is_staff %}
- | <a href="/admin/">{% trans "Administration" %}</a>
- {% endif %}
- | <a href="{% url suggest %}" id="suggest-link">{% trans "Report a bug" %}</a>
- | <a href="{% url logout %}?next={{ request.get_full_path }}">{% trans "Logout" %}</a>
- </p>
+ {% trans "Welcome" %}, <strong>{{ user.username }}</strong>
+ | <a href="{% url user_shelves %}" id="user-shelves-link">{% trans "Your shelves" %}</a>
+ {% if user.is_staff %}
+ | <a href="/admin/">{% trans "Administration" %}</a>
+ {% endif %}
+ | <a href="{% url logout %}?next={{ request.get_full_path }}">{% trans "Logout" %}</a>
{% else %}
- <p><a href="{% url suggest %}" id="suggest-link">{% trans "Report a bug" %}</a>
- | <a href="{% url login %}" class="login-register-link">{% trans "Sign in" %} / {% trans "Register" %}</a></p>
+ <a href="{% url login %}?next={{ request.path }}"
+ id="login" class="ajaxable">
+ {% trans "Sign in" %}</a>
+ /
+ <a href="{% url register %}?next={{ request.path }}"
+ id="register" class="ajaxable">
+ {% trans "Register" %}</a>
{% endif %}
+ </p>
+
+
+ <div class="clearboth"></div>
+
+ </div>
+ </div>
+
+ <div id="half-header">
+ <div id="half-header-content">
+
+
+
+ <form id="search-area" action="/fullsearch/">
+
+ <span id="search-field" class="grid-line">
+ {{search_form.q}}
+<!-- <input title="np. Leśmian" name="q" autocomplete="off" data-source="/fullsearch/hint/">-->
+ </span><span id="search-button">
+ <button type='submit'><span class="mono">{% trans "Search" %}</span></button>
+ </span>
+
+ <div class="clearboth"></div>
+ </form>
+
+
+
+ </div>
+ </div>
+
+
+
+ <div id="main-content">
+
+ <div id="nav-line">
+ <ul id="catalogue">
+ <li><a href="{% url catalogue %}#autorzy"><span class='mono'>{% trans "Authors" %}</span></a></li>
+ <li><a href="{% url catalogue %}#gatunki"><span class='mono'>{% trans "Genres" %}</span></a></li>
+ <li><a href="{% url catalogue %}#rodzaje"><span class='mono'>{% trans "Kinds" %}</span></a></li>
+ <li><a href="{% url catalogue %}#epoki"><span class='mono'>{% trans "Epochs" %}</span></a></li>
+ <li><a href="{% url catalogue %}#motywy"><span class='mono'>{% trans "Themes" %}</span></a></li>
+ <li><a href="{% url book_list %}"><span class='mono'>{% trans "All books" %}</span></a></li>
+ <li><a href="{% url audiobook_list %}"><span class='mono'>{% trans "Audiobooks" %}</span></a></li>
+ <li><a href="{% url daisy_list %}"><span class='mono'>{% trans "DAISY" %}</span></a></li>
+ </ul>
+
+ <form action="{% url django.views.i18n.set_language %}" method="post">
+ <div id="lang-menu">
+ <span id='lang-button' class='mono'>
+ {% trans "Language versions" %}</span>
+ <div id="lang-menu-items">
+ {% for lang in LANGUAGES %}
+ <button type="submit" name="language"
+ class="{% ifequal lang.0 LANGUAGE_CODE %}active{% endifequal %} mono"
+ value="{{ lang.0 }}">{{ lang.1 }}</button>
+ {% endfor %}
+ </div>
</div>
- <div class="social-links" style="float:right">
- <a href="http://pl-pl.facebook.com/pages/Wolne-Lektury/203084073268"><img src="{{ STATIC_URL }}img/social/facebook.png" alt="WolneLektury @ Facebook" /></a>
- <a href="http://nk.pl/profile/30441509"><img src="{{ STATIC_URL }}img/social/naszaklasa.png" alt="WolneLektury @ NK" /></a>
- </div>
- <form action="{% url django.views.i18n.set_language %}" method="post">
- <div class="lang-menu" style="float:right;">
- {% spaceless %}
- {% for lang in LANGUAGES %}
- <button type="submit" name="language" title="{{ lang.1 }}"
- class="{% ifequal lang.0 LANGUAGE_CODE %}active{% endifequal %} {% if forloop.last %}last{% endif %}"
- value="{{ lang.0 }}">{{ lang.0|upper }}</button>
- {% endfor %}
- {% endspaceless %}
- </div>
- </form>
- {# publication plan consultations - form link #}
- <div style="clear:right;float:right" class="big-top-link">
- <a href="{% url suggest_publishing %}" data-ajax="{% url suggest_publishing %}?ajax=1" id="suggest-publishing-link">
- {% trans "Didn't find a book? Make a suggestion." %}
- </a>
+ </form>
</div>
+
<div class="clearboth"></div>
- </div>
- <div id="maincontent">
+
+
+
{% block body %}
{% endblock %}
- </div>
+
+
+
+
<div class="clearboth"></div>
+
+ </div>{# end main-content #}
+
+
<div id="footer">
+ <div id="footer-content">
<p>
{% blocktrans %}
Wolne Lektury is a project lead by <a href="http://nowoczesnapolska.org.pl/">Modern Poland Foundation</a>.
{% sponsor_page "footer" %}
</div>
- <div id="login-register-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <form method="post" action="{% url login %}" id="login-form" class="cuteform">
- <h2>{% trans "Sign in" %} / <a href="#" id="show-registration-form" style="font-size: 0.85em; font-weight: normal">{% trans "Register" %}</a></h2>
- <p><span id="id_login-__all__"></span></p>
- <ol>
- {% authentication_form %}
- <li><input type="submit" value="{% trans "Sign in" %}" /></li>
- </ol>
- </form>
- <form method="post" action="{% url register %}" id="registration-form" class="cuteform" style="display: none;">
- <h2><a href="#" id="show-login-form" style="font-size: 0.85em; font-weight: normal">{% trans "Sign in" %}</a> / {% trans "Register" %}</h2>
- <p><span id="id_registration-__all__"></span></p>
- <ol>
- {% user_creation_form %}
- <li><input type="submit" value="{% trans "Register" %}" /></li>
- </ol>
- </form>
- </div>
- </div>
- <div id="user-shelves-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
- <div id="suggest-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
</div>
- <div id="suggest-publishing-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
+
+
+
+ {# template #}
+ <div id="ajaxable-window" class='dialog-window'>
+ <div class="header mono"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
<div class="target">
<p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
</div>
</div>
+
+
{% endblock bodycontent %}
- {{ piwik_tag|safe }}
+
+
+ <script type="text/javascript" src="http://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>
+ {% compressed_js "base" %}
+
+ <!--{{ piwik_tag|safe }}
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2576694-1");
pageTracker._trackPageview();
- </script>
+ </script>-->
</body>
</html>
{% block bodyid %}book-a-list{% endblock %}
-{% block title %}{% trans "Listing of all audiobooks on WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{% trans "Listing of all audiobooks" %}{% endblock %}
{% block metadescription %}Darmowe audiobooki na wolnej licencji. Lektury czytane przez znanych aktorów.{% endblock %}
{% load i18n %}
{% load catalogue_tags pagination_tags %}
-{% block title %}{{ book.title }} {% trans "on WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{{ book.title }}{% endblock %}
{% block metadescription %}{% book_title book %}. {{ block.super }}{% endblock %}
{% block bodyid %}book-detail{% endblock %}
{% block body %}
- <h1>{% book_title book %}</h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
- <div id="books-list">
- <div id='breadcrumbs'>
- {% if categories.author %}
- {% for tag in categories.author %}
- <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
- {% endfor %}
- »
- {% endif %}
- {% for parent in parents %}
- <a href="{{ parent.get_absolute_url }}">{{ parent }}</a> »
- {% endfor %}
- </div>
+{% book_wide book %}
- {% if extra_info.license %}
- <p>{% trans "Work is licensed under " %} <a href="{{ extra_info.license }}">{{ extra_info.license_description }}</a>.</p>
- {% endif %}
- <p>{% trans "Based on" %}: {{ extra_info.source_name }}</p>
- {% if book.has_description %}
- <div id="description">
- <div id='description-long'>{{ book.description|safe }}</div>
- <div id='description-short'>{{ book.description|safe|truncatewords_html:30 }}</div>
- </div>
- <div id="toggle-description"><p></p></div>
- {% endif %}
- <div id="formats">
- <p class="change-sets">{% trans "Put a book" %} <span><a href="{% url catalogue.views.book_sets book.slug %}" class="jqm-trigger">{% trans "on the shelf!" %}</a></span></p>
- <div class="clearboth"></div>
- <div class="wrap">
- {% if book.has_html_file %}
- <a class="online" href="{% url book_text book.slug %}">{% trans "Read online" %}</a>
- {% endif %}
- <div class="download">
- {% if book.pdf_file %}
- <a href="{{ book.pdf_file.url }}"><img src="{{ STATIC_URL }}img/pdf.png" title="{% trans "Download PDF" %} – {% trans "for reading" %} {% trans "and printing using" %} Adobe Reader" %}" alt="{% trans "Download PDF" %}" /></a>
- {% endif %}
- {% if book.root_ancestor.epub_file %}
- <a href="{{ book.root_ancestor.epub_file.url }}"><img src="{{ STATIC_URL }}img/epub.png" title="{% trans "Download EPUB" %} – {% trans "for reading" %} {% trans "on mobile devices" %}" alt="{% trans "Download EPUB" %}" /></a>
- {% endif %}
- {% if book.mobi_file %}
- <a href="{{ book.mobi_file.url }}"><img src="{{ STATIC_URL }}img/mobi.png" title="{% trans "Download MOBI" %} – {% trans "for reading" %} {% trans "on mobile devices" %}" alt="{% trans "Download MOBI" %}" /></a>
- {% endif %}
- {% if book.txt_file %}
- <a href="{{ book.txt_file.url }}"><img src="{{ STATIC_URL }}img/txt.png" title="{% trans "Download TXT" %} – {% trans "for reading" %} {% trans "on small displays, for example mobile phones" %}" alt="{% trans "Download TXT" %}" /></a>
- {% endif %}
- {% for media in book.get_odt %}
- <a href="{{ media.file.url }}"><img src="{{ STATIC_URL }}img/odt.png" title="{% trans "Download ODT" %} – {% trans "for reading" %} {% trans "and editing using" %} OpenOffice.org: {{ media.name }}" alt="{% trans "Download ODT" %}" /></a>
- {% endfor %}
- </div>
- {% if book.has_mp3_file or book.has_ogg_file or book.has_daisy_file %}
- <p class="header">
- <span class="desc">{% trans "Audiobooks" %}:</span>
- <span class="audiotabs">
- {% if book.has_mp3_file %}<span class="active" data-format="mp3">MP3</span>{% endif %}
- {% if book.has_ogg_file %}<span data-format="ogg">Ogg Vorbis</span>{% endif %}
- {% if book.has_daisy_file %}<span data-format="daisy">DAISY</span>{% endif %}
- </span>
- </p>
- <div class="audiobooks">
- <img src="{{ STATIC_URL }}img/speaker.png" id="speaker" alt="Speaker icon"/>
- {% if book.has_mp3_file %}
- <ul class="audiobook-list" id="mp3-files">
- {% for media in book.get_mp3 %}
- <li class="mp3Player">
- <a href="{{ media.file.url }}">{{ media.name }}</a><br/>
- {% trans "Artist" %}: {{ media.get_extra_info_value.artist_name }}<br/>
- {% trans "Director"%}: {{ media.get_extra_info_value.director_name }}<br/>
- <object type="application/x-shockwave-flash" style="margin-top: 0.5em" data="{{ STATIC_URL }}player.swf" width="226" height="20">
- <param name="movie" value="{{ STATIC_URL }}player.swf" />
- <param name="bgcolor" value="#ffffff" />
- <param name="FlashVars" value="mp3={{ media.file.url }}&width=226&showvolume=1&bgcolor1=eeeeee&bgcolor2=eeeeee&buttoncolor=666666" />
- </object>
-
- </li>
- {% endfor %}
- </ul>
- {% endif %}
-
- {% if book.has_ogg_file %}
- <ul class="audiobook-list" id="ogg-files">
- {% for media in book.get_ogg %}
- <li><a href="{{ media.file.url }}">{{ media.name }}</a></li>
- {% endfor %}
- </ul>
- {% endif %}
- {% if book.has_daisy_file %}
- <ul class="audiobook-list" id="daisy-files">
- {% for media in book.get_daisy %}
- <li><a href="{{ media.file.url }}">{{ media.name }}</a></li>
- {% endfor %}
- </ul>
- {% endif %}
- </div> <!-- /audiobooks -->
- {% if projects|length > 1 %}
- <p>{% trans "Audiobooks were prepared as a part of the projects:" %}</p>
- <ul>
- {% for cs, fb in projects %}
- <li>
- {% if fb %}
- {% blocktrans %}{{ cs }}, funded by {{ fb }}{% endblocktrans %}
- {% else %}
- {{ cs }}
- {% endif %}
- </li>
- {% endfor %}
- </ul>
- {% else %}
- <p>
- {% with projects.0.0 as cs %}
- {% with projects.0.1 as fb %}
- {% if fb %}
- {% blocktrans %}Audiobooks were prepared as a part of the {{ cs }} project funded by {{ fb }}.{% endblocktrans %}
- {% else %}
- {% blocktrans %}Audiobooks were prepared as a part of the {{ cs }} project.{% endblocktrans %}
- {% endif %}
- {% endwith %}
- {% endwith %}
- </p>
- {% endif %}
- {% endif %}
- </div>
- </div>
-
- {% if book_children %}
- {% autopaginate book_children 10 %}
- <div id="book-children">
- <ol>
- {% for book in book_children %}
- <li>{{ book.short_html }}</li>
- {% endfor %}
- </ol>
- </div>
- {% paginate %}
- {% endif %}
-
- </div>
-
- <div id="tags-list">
- <div id="book-info">
- <h2>{% trans "Details" %}</h2>
- <ul>
- <li>
- {% trans "Author" %}:
- {% for tag in categories.author %}
- <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
- {% endfor %}
- </li>
- <li>
- {% trans "Epoch" %}:
- {% for tag in categories.epoch %}
- <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
- {% endfor %}
- </li>
- <li>
- {% trans "Kind" %}:
- {% for tag in categories.kind %}
- <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
- {% endfor %}
- </li>
- <li>
- {% trans "Genre" %}:
- {% for tag in categories.genre %}
- <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
- {% endfor %}
- </li>
- </ul>
- <h2>{% trans "Other resources" %}</h2>
- <ul>
- {% if extra_info.source_url %}
- <li><a href="{{ extra_info.source_url }}">{% trans "Source of the book" %}</a></li>
- {% endif %}
- {% if extra_info.about and not hide_about %}
- <li><a href="{{ extra_info.about }}">{% trans "Book on the Editor's Platform" %}</a></li>
- {% endif %}
- {% if book.gazeta_link %}
- <li><a href="{{ book.gazeta_link }}">{% trans "Book description on Lektury.Gazeta.pl" %}</a></li>
- {% endif %}
- {% if book.wiki_link %}
- <li><a href="{{ book.wiki_link }}">{% trans "Book description on Wikipedia" %}</a></li>
- {% endif %}
- </ul>
- <p><a href="{{ book.xml_file.url }}">{% trans "View XML source" %}</a></p>
- <p><a href="{% url poem_from_book book.slug %}">Miksuj ten utwór</a></p>
- </div>
- <div id="themes-list">
- <h2>{% trans "Work's themes " %}</h2>
- <ul>
- {% for theme in book_themes %}
- <li><a href="{% url book_fragments book.slug,theme.slug %}">{{ theme }} ({{ theme.count }})</a></li>
- {% endfor %}
- </ul>
- </div>
- <div class="clearboth"></div>
- </div>
- <div id="set-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
{% endblock %}
{% load i18n %}
{% load catalogue_tags pagination_tags %}
-{% block title %}{% trans "Theme" %} {{ theme }} {% trans "in work " %} {{ book }} {% trans "on" %} WolneLektury.pl{% endblock %}
+{% block titleextra %}{% trans "Theme" %} {{ theme }} {% trans "in work " %} {{ book }}{% endblock %}
{% block bodyid %}tagged-object-list{% endblock %}
{% block body %}
<h1>{% trans "Theme" %} {{ theme }} {% trans "in work " %} {{ book }} </h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{{ book.get_absolute_url }}">{% trans "return to book's page" %}</a></p>
- </form>
{% autopaginate fragments 10 %}
<div id="books-list">
</div>
<div class="clearboth"></div>
</div>
- <div id="set-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
{% endblock %}
\ No newline at end of file
{% block bodyid %}book-a-list{% endblock %}
-{% block title %}{% trans "Listing of all works on WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{% trans "Listing of all works" %}{% endblock %}
{% block body %}
<h1>{% block book_list_header %}{% trans "Listing of all works" %}{% endblock %}</h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} {{ form.tags }} <input type="submit" value="{% trans "Search" %}" />
- <strong>{% trans "or" %}</strong> {% trans "see" %}:
- <span class='collections'>
- <a href="{% url catalogue.views.book_list %}">{% trans "all books" %}</a>
- <a href="{% url catalogue.views.audiobook_list %}">{% trans "audiobooks" %}</a>
- <a href="{% url catalogue.views.daisy_list %}">{% trans "DAISY" %}</a>
- </span></p>
- </form>
- <div class="column-left">{% block book_list_info %}{% endblock %}</div><div style='clear:both;'></div>
+
+ <div class="left-column"><div class="normal-text">
+ {% block book_list_info %}{% endblock %}
+ </div></div>
+
+ <div style='clear:both;'></div>
+
<a name="top">
- <div id="book-list-nav">
+
+ <div id="book-list-nav" class="normal-text">
{% trans "Table of Content" %}
{% for index, authors in books_nav.items %}
<ul>
</ul>
{% endfor %}
</div>
- <div id="book-list">
+ <div id="book-list" class="normal-text">
+ {% block book_list %}
{% book_tree orphans books_by_parent %}
{% for author, group in books_by_author.items %}
{% if group %}
</div>
{% endif %}
{% endfor %}
+ {% endblock %}
</div>
<div id="book-list-up">
<p><a href="#top">{% trans "↑ top ↑" %}</a></p>
--- /dev/null
+{% load thumbnail %}
+<div class="book-mini-box">
+ <a href="{{ book.get_absolute_url }}">
+ {% if book.cover %}
+ <img src="
+ {% thumbnail book.cover "216x288" as thumb %}
+ {{ thumb.url }}
+ {% empty %}
+ {{ book.cover.url }}
+ {% endthumbnail %}
+ " alt="Cover" />
+ {% endif %}
+ {% for author in authors %}
+ <div class="desc">
+ <span class="mono author">{{ author }}</span>
+ <span class="title">{{ book.title }}</span>
+ </div>
+ {% endfor %}
+ </a>
+</div>
+
+
{% load i18n %}
-<div class="book">
- <div class="change-sets">
- <a href="{% url catalogue.views.book_sets book.slug %}" class="jqm-trigger">{% trans "Put on the shelf!" %}</a>
- </div>
- {% if book.children.all|length %}
- <div class="book-parent-thumbnail"></div>
- {% else %}
- <div class="book-thumbnail"></div>
- {% endif %}
- <div class="book-description">
- <h2><a href="{{ book.get_absolute_url }}">{{ book.title }}</a></h2>
- {% if formats %}
- <p style="margin: 0">{% trans "Jump to" %}: {{ formats|join:", " }}</p>
+{% load thumbnail %}
+<div class="{% block box-class %}book-box{% endblock %}">
+<div class="book-box-inner">
+ <a href="{{ book.get_absolute_url }}">
+ {% if book.cover %}
+ <img src="
+ {% thumbnail book.cover "216x288" as thumb %}
+ {{ thumb.url }}
+ {% empty %}
+ {{ book.cover.url }}
+ {% endthumbnail %}
+ " alt="Cover" />
{% endif %}
- <p style="margin: 0">{% trans "Categories" %}: {{ tags|join:", " }}</p>
+ </a>
+ {% block right-column %}
+ {% endblock %}
+ <div class="book-box-body">
+ <div class="book-box-head">
+ <div class="mono author">
+ {% for author in tags.author %}
+ {{ author }}
+ {% endfor %}
+ </div>
+ <div class="title">{{ book.title }}</div>
+ </div>
+ <div class="tags">
+ {% spaceless %}
+
+ <span class="mono">{% trans "Epoch" %}:</span> <span class="book-box-tag">
+ {% for tag in tags.epoch %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag.name }} </a>
+ {% endfor %}
+ </span>
+
+ <span class="mono">{% trans "Kind" %}:</span> <span class="book-box-tag">
+ {% for tag in tags.kind %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag.name }} </a>
+ {% endfor %}
+ </span>
+
+ <span class="mono">{% trans "Genre" %}:</span> <span class="book-box-tag">
+ {% for tag in tags.genre %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag.name }} </a>
+ {% endfor %}
+ </span>
+
+ {% endspaceless %}
+ </div>
</div>
-</div>
\ No newline at end of file
+ <ul class="book-box-tools">
+ <li class="book-box-read">
+ {% if book.html_file %}
+ <a href="{% url book_text book.slug %}" class="mono downarrow">{% trans "Read online" %}</a>
+ {% endif %}
+ </li>
+ <li class="book-box-download">
+ <a class="mono downarrow">{% trans "Download" %}</a>
+ <div class="book-box-formats mono">
+ {% if formats.pdf %}
+ <span><a href="{{formats.pdf.url}}">PDF</a> do wydruku</span>
+ {% endif %}
+ {% if formats.epub %}
+ <span><a href="{{formats.epub.url}}">EPUB</a> na czytnik</span>
+ {% endif %}
+ {% if formats.mobi %}
+ <span><a href="{{formats.mobi.url}}">MOBI</a> na Kindle</span>
+ {% endif %}
+ {% if formats.txt %}
+ <span><a href="{{formats.txt.url}}">TXT</a> do zadań specjalnych</span>
+ {% endif %}
+ </div>
+ </li>
+ <li class="book-box-audiobook">
+ {% if book.has_mp3_file %}
+ <a href="{% url book_player book.slug %}" class="open-player mono downarrow">{% trans "Listen" %}</a>
+ {% endif %}
+ </li>
+ </ul>
+ {% block box-append %}
+ {% endblock %}
+</div>
+</div>
<title>{% block title %}WolneLektury.pl{% endblock %}</title>
<link rel="icon" href="{{ STATIC_URL }}img/favicon.png" type="image/x-icon" />
{% compressed_css "book" %}
- {% compressed_js "jquery" %}
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
{% compressed_js "book" %}
<!--[if IE]>
{% compressed_js "book_ie" %}
--- /dev/null
+{% extends "catalogue/book_short.html" %}
+{% load i18n %}
+
+{% block box-class %}book-wide-box{% endblock %}
+
+{% block right-column %}
+<div class="right-column">
+ <blockquote id="quote" class="cite-body">
+ <div>Ten, który walczy z potworami powinien zadbać, by sam nie stał się potworem.
+ Gdy długo spoglądamy w otchłań, otchłań spogląda również w nas.</div>
+ </blockquote>
+
+ <div id="other-tools">
+ <h2 class="mono">{% trans "See" %}</h2>
+ <ul class="inline-items">
+ {% if extra_info.source_url %}
+ <li><a href="{{ extra_info.source_url }}">{% trans "Source" %}</a> {% trans "of the book" %}</li>
+ {% endif %}
+ {% if extra_info.about and not hide_about %}
+ <li>{% trans "Book on" %} <a href="{{ extra_info.about }}">{% trans "Editor's Platform" %}</a></li>
+ {% endif %}
+ {% if book.gazeta_link %}
+ <li><a href="{{ book.gazeta_link }}">{% trans "Book description on Lektury.Gazeta.pl" %}</a></li>
+ {% endif %}
+ {% if book.wiki_link %}
+ <li><a href="{{ book.wiki_link }}">{% trans "Book description on Wikipedia" %}</a></li>
+ {% endif %}
+ </ul>
+ </div>
+ <div id="other-download">
+ <h2 class="mono">{% trans "Download" %}</h2>
+ <ul class="inline-items">
+ <li>
+ {% if has_media.mp3 or has_media.ogg %}
+ {% trans "Download all audiobooks for this book" %}:
+ {% if has_media.mp3 %}<a href="{% url download_zip_mp3 book.slug %}">MP3</a>{% endif %}{% if has_media.mp4 and has_media.ogg %},{% endif %}
+ {% if has_media.ogg %}<a href="{% url download_zip_ogg book.slug %}">OGG</a>{% endif %}.
+ {% endif %}
+ </li>
+ <li>
+ <a href="{% url custom_pdf_form %}?slug={{book.slug}}" id="custom-pdf" class="ajaxable">{% trans "Download a custom PDF" %}</a>
+ </li>
+ </ul>
+ </div>
+</div>
+{% endblock %}
+++ /dev/null
-{% load i18n %}
-{% load catalogue_tags %}
-<div id="searchContainer">
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <ul class="facelist-selections" style="float:left;">
- {% for tag in tag_list %}
- <li class="facelist-selection-item">
- <span style="margin-left: 5px;">
- <a href="{% catalogue_url tag %}">{{ tag }}</a>
- <a class="facelist-close" href="{% catalogue_url tag_list -tag %}">x</a>
- </span>
- </li>
- {% empty %}
- <li class="facelist-selection-item">
- </li>
- {% endfor %}
- {% if search_form %}
- <li>{{ search_form.q }} {{ search_form.tags }}</li>
- {% endif %}
- </ul>
- <input type="submit" value="{% trans "Search" %}" id="searchSubmit"/>
- </form>
-</div>
-<div class="clearboth"></div>
--- /dev/null
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags %}
+
+
+{% block titleextra %}{% trans "Catalogue" %}{% endblock %}
+
+{% block bodyid %}catalogue-catalogue{% endblock %}
+
+{% block body %}
+ <h1>{% trans "Catalogue" %}</h1>
+
+ <div class="normal-text">
+
+ <p><a href="{% url reporting_catalogue_pdf %}">
+ {% trans "Download the catalogue in PDF format." %}
+ </a></p>
+
+ <h2></a>{% trans "Authors" %}<a name="autorzy"></a></h2>
+ {% tag_list categories.author %}
+
+ <h2>{% trans "Kinds" %}<a name="rodzaje"></a></h2>
+ {% tag_list categories.kind %}
+
+ <h2>{% trans "Genres" %}<a name="gatunki"></a></h2>
+ {% tag_list categories.genre %}
+
+ <h2>{% trans "Epochs" %}<a name="epoki"></a></h2>
+ {% tag_list categories.epoch %}
+
+ <h2>{% trans "Themes and topics" %}<a name="motywy"></a></h2>
+ {% tag_list fragment_tags %}
+ </div>
+{% endblock %}
{% extends "catalogue/book_list.html" %}
{% load i18n %}
-{% block title %}{{ context.collection.title }} {% trans "in WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{{ context.collection.title }}{% endblock %}
{% block book_list_header %}{{ context.collection.title }}{% endblock %}
{% block bodyid %}book-a-list{% endblock %}
-{% block title %}{% trans "Listing of all DAISY files on WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{% trans "Listing of all DAISY files" %}{% endblock %}
{% block extrahead %}
<link rel="alternate" type="application/atom+xml" title="{% trans "Latest DAISY audiobooks" %}" href="{% url audiobook_feed 'daisy' %}" />
{% load i18n %}
{% load catalogue_tags %}
-{% block title %}{% title_from_tags tags %} w WolneLektury.pl{% endblock %}
+{% block titleextra %}{% title_from_tags tags %}{% endblock %}
{% block bodyid %}differentiate_tags{% endblock %}
{% block body %}
<h1>{% title_from_tags tags %}</h1>
- {% breadcrumbs tags %}
<p>{% trans "The criteria are ambiguous. Please select one of the following options:" %}</p>
<div id="books-list">
</div>
{% endfor %}
</div>
-
- <div id="set-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
{% endblock %}
\ No newline at end of file
+++ /dev/null
-{% load i18n %}
-{% load catalogue_tags %}
-{% if one_tag %}
- <p>{% trans "Show full category" %} <a href="{% catalogue_url one_tag %}">{{ one_tag }}</a>.</p>
-{% else %}
- <div class="shown-tags">
- <ul class="shown-tags">
- {% for tag in shown_tags %}
- <li><a href="{% catalogue_url choices tag %}">{{ tag }} ({{ tag.count }})</a></li>
- {% endfor %}
- </ul>
- {% if some_tags_hidden %}
- <p><a href="#" class="show-all-tags">{% trans "See more" %}</a></p>
- {% endif %}
- </div>
- <div class="all-tags">
- <ul>
- {% for tag in tags %}
- <li><a href="{% catalogue_url choices tag %}">{{ tag }} ({{ tag.count }})</a></li>
- {% endfor %}
- </ul>
- <p><a href="#" class="hide-all-tags">{% trans "Hide" %}</a></p>
- </div>
-{% endif %}
--- /dev/null
+{% load i18n %}
+{% load catalogue_tags %}
+{% if one_tag %}
+ {% trans "See full category" %} <a href="{% catalogue_url one_tag %}">{{ one_tag }}</a>
+{% else %}
+ {% for tag in tags %}
+ <a href="{% catalogue_url choices tag %}">{{ tag }} ({{ tag.book_count }})</a>
+ {% endfor %}
+{% endif %}
+++ /dev/null
-{% extends "base.html" %}
-{% load i18n %}
-{% load catalogue_tags chunks cache reporting_stats %}
-
-
-{% block tagline %}
-<div id='tagline'>
-
-{% count_books_nonempty count_books %}
-{% blocktrans count count_books as c %}
-{{c}} book from <a href='http://domenapubliczna.org'>public domain</a> or under
-a <a href='http://creativecommons.org/licenses/by-sa/3.0/deed.pl'>free license</a>.
-{% plural %}
-{{c}} books from <a href='http://domenapubliczna.org'>public domain</a> or under
-a <a href='http://creativecommons.org/licenses/by-sa/3.0/deed.pl'>free license</a>.
-{% endblocktrans %}
-
-</div>
-{% endblock %}
-
-
-{% block bodyid %}main-page{% endblock %}
-
-{% block body %}
- <div id="site-description">
- {% chunk "site-description" %}
- </div>
- <div class="clearboth"></div>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} {{ form.tags }} <input type="submit" value="{% trans "Search" %}" />
- <strong>{% trans "or" %}</strong> {% trans "see" %}:
- <span class='collections'>
- <a href="{% url catalogue.views.book_list %}">{% trans "all books" %}</a>
- <a href="{% url catalogue.views.audiobook_list %}">{% trans "audiobooks" %}</a>
- <a href="{% url catalogue.views.daisy_list %}">{% trans "DAISY" %}</a>
- </span></p>
- </form>
-
- <div id="intro">
- <p id="tags-description">↓ {% trans "Browse books by categories" %} ↓</p>
- <div id="propaganda">
-
- {% chunk "promo" %}
-
- {% comment %}
- <h2>Spot promocyjny</h2>
- <p><iframe width="260" height="162"
- src="http://www.youtube.com/embed/IteV_EoTrZE"
- frameborder="0" allowfullscreen></iframe></p>
- {% endcomment %}
-
- {% comment %} <h2>{% trans "Books for every school level" %}</h2>
- <ul>
- <li><a href="">{% trans "primary school" %}</a></li>
- <li><a href="">{% trans "gymnasium" %}</a></li>
- <li><a href="">{% trans "high school" %}</a></li>
- </ul> {% endcomment %}
-
- <br/>
- <h2>{% trans "Your shelves with books" %}</h2>
- {% if user.is_authenticated %}
- {% if shelves %}
- <ul class="shelf-list">
- {% for shelf in shelves %}
- <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">{% trans "delete" %}</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.get_count }})</a></li>
- {% endfor %}
- </ul>
- {% else %}
- <p>{% trans "You do not own any shelves. You can create one below, if you want to." %}</p>
- {% endif %}
- <hr />
- <form action="{% url catalogue.views.new_set %}" method="post" accept-charset="utf-8" class="cuteform">
- <ol>
- <li>{{ new_set_form.name }} <input type="submit" value="{% trans "Create shelf" %}"/></li>
- </ol>
- </form>
- <br/>
- {% else %}
- <p>{% trans "Create your own book set. You can share it with friends by sending them link to your shelf." %}</p>
- <p>{% trans "You need to " %} <a class="login-register-link" href="#">{% trans "sign in" %}</a> {% trans "to manage your shelves." %}</p>
- {% endif %}
-
- <h2>Leśmianator</h2>
- <p>Wybierz, co wpadnie do miksera, i pokaż efekt znajomym!
- </p>
- <p class="see-more" style="clear:both"><a href="{% url lesmianator %}">{% trans "Twórzże się!" %} ⇒</a></p>
-
- <h2>{% trans "Wolne Lektury Widget" %}</h2>
- <p>{% trans "Place our widget - search engine for Wolne Lektury which gives access to free books and audiobooks - on your homepage! Just copy the HTML code below onto your page:" %}</p>
- <textarea rows="1" cols="35" class='widget-code' title='widget'><!-- START {% trans "Insert this element in place where you want display the widget" %} -->
-<div id="wl" />
-<!-- END -->
-<!-- START {% trans "Place this element just before closing body tag: </body>" %} -->
-<script type="text/javascript" src="http://www.wolnelektury.pl/static/js/widget.js"></script>
-<!-- END --></textarea>
- <p class="see-more"><a href="{% url widget %}" title="{% trans "Wolne Lektury Widget" %}">{% trans "See more" %} ⇒</a></p>
-
- <div id="lessons">
- <h2><a href="{% url lessons_document_list %}">{% trans "Hand-outs for teachers" %}</a></h2>
- <p>{% trans "Lessons' prospects and other ideas for using Wolnelektury.pl for teaching." %}</p>
- <p class="see-more"><a href="{% url lessons_document_list %}" title="{% trans "Hand-outs for teachers" %}">{% trans "See more" %} ⇒</a></p>
- </div>
- </div>
- <div id="tags-list">
- <div id="categories-list">
- {% if categories.author %}
- <h2>{% trans "Authors" %}</h2>
- {% folded_tag_list categories.author 'Authors' %}
- {% endif %}
- {% if categories.kind %}
- <h2>{% trans "Kinds" %}</h2>
- {% folded_tag_list categories.kind 'Kinds' %}
- {% endif %}
- {% if categories.genre %}
- <h2>{% trans "Genres" %}</h2>
- {% folded_tag_list categories.genre 'Genres' %}
- {% endif %}
- {% if categories.epoch %}
- <h2>{% trans "Epochs" %}</h2>
- {% folded_tag_list categories.epoch 'Epochs' %}
- {% endif %}
- </div>
- <div id="themes-list">
- {% if fragment_tags %}
- <h2>{% trans "Themes and topics" %}</h2>
- {% folded_tag_list fragment_tags 'Themes' %}
- {% endif %}
- <h2>{% trans "Themes groups" %}</h2>
- <div class="shown-tags">
- <ol>
- <li>środowisko miejskie i wiejskie
- <span class="subcategories"><a href="/katalog/motyw/miasto/">Miasto</a>, <a href="/katalog/motyw/warszawa/">Warszawa</a>, <a href="/katalog/motyw/mieszczanin/">Mieszczanin</a>, <a href="/katalog/motyw/handel/">Handel</a>, <a href="/katalog/motyw/robotnik/">Robotnik</a>, <a href="/katalog/motyw/zyd/">Żyd</a>, <a href="/katalog/motyw/wies/">Wieś</a>, <a href="/katalog/motyw/sielanka/">Sielanka</a>, <a href="/katalog/motyw/chlop/">Chłop</a>, <a href="/katalog/motyw/ogrod/">Ogród</a>, <a href="/katalog/motyw/natura/">Natura</a>, <a href="/katalog/motyw/przestrzen/">Przestrzeń</a></span></li>
-
- <li>polityczny obraz świata
- <span class="subcategories"><a href="/katalog/motyw/panstwo/">Państwo</a>, <a href="/katalog/motyw/obowiazek/">Obowiązek</a>, <a href="/katalog/motyw/cnota/">Cnota</a>, <a href="/katalog/motyw/obywatel/">Obywatel</a>, <a href="/katalog/motyw/patriota/">Patriota</a>, <a href="/katalog/motyw/ojczyzna/">Ojczyzna</a>, <a href="/katalog/motyw/narod/">Naród</a>, <a href="/katalog/motyw/przywodca/">Przywódca</a>, <a href="/katalog/motyw/wladza/">Władza</a>, <a href="/katalog/motyw/urzednik/">Urzędnik</a>, <a href="/katalog/motyw/krol/">Król</a>, <a href="/katalog/motyw/rycerz/">Rycerz</a>, <a href="/katalog/motyw/zolnierz/">Żołnierz</a>, <a href="/katalog/motyw/wojna/">Wojna</a>, <a href="/katalog/motyw/wrog/">Wróg</a>, <a href="/katalog/motyw/zwyciestwo/">Zwycięstwo</a>, <a href="/katalog/motyw/walka/">Walka</a>, <a href="/katalog/motyw/sila/">Siła</a>, <a href="/katalog/motyw/historia/">Historia</a>, <a href="/katalog/motyw/powstanie/">Powstanie</a>, <a href="/katalog/motyw/smierc-bohaterska/">Śmierć bohaterska</a>, <a href="/katalog/motyw/slawa/">Sława</a>, <a href="/katalog/motyw/rewolucja/">Rewolucja</a>, <a href="/katalog/motyw/sad/">Sąd</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a></span></li>
-
- <li>przyroda
- <span class="subcategories"><a href="/katalog/motyw/natura/">Natura</a>, <a href="/katalog/motyw/zywioly/">Żywioły</a>, <a href="/katalog/motyw/ogien/">Ogień</a>, <a href="/katalog/motyw/ziemia/">Ziemia</a>, <a href="/katalog/motyw/wiatr/">Wiatr</a>, <a href="/katalog/motyw/woda/">Woda</a>, <a href="/katalog/motyw/wiosna/">Wiosna</a>, <a href="/katalog/motyw/lato/">Lato</a>, <a href="/katalog/motyw/jesien/">Jesień</a>, <a href="/katalog/motyw/zima/">Zima</a>, <a href="/katalog/motyw/przemijanie/">Przemijanie</a>, <a href="/katalog/motyw/slonce/">Słońce</a>, <a href="/katalog/motyw/ksiezyc/">Księżyc</a>, <a href="/katalog/motyw/gwiazda/">Gwiazda</a>, <a href="/katalog/motyw/oblok/">Obłok</a>, <a href="/katalog/motyw/noc/">Noc</a>, <a href="/katalog/motyw/swiatlo/">Światło</a>, <a href="/katalog/motyw/gora/">Góra</a>, <a href="/katalog/motyw/rzeka/">Rzeka</a>, <a href="/katalog/motyw/morze/">Morze</a>, <a href="/katalog/motyw/burza/">Burza</a>, <a href="/katalog/motyw/deszcz/">Deszcz</a>, <a href="/katalog/motyw/bloto/">Błoto</a>, <a href="/katalog/motyw/przyroda-nieozywiona/">Przyroda nieożywiona</a>, <a href="/katalog/motyw/rosliny/">Rośliny</a>, <a href="/katalog/motyw/kwiaty/">Kwiaty</a>, <a href="/katalog/motyw/ogrod/">Ogród</a>, <a href="/katalog/motyw/sielanka/">Sielanka</a>, <a href="/katalog/motyw/raj/">Raj</a>, <a href="/katalog/motyw/jablko/">Jabłko</a>, <a href="/katalog/motyw/drzewo/">Drzewo</a>, <a href="/katalog/motyw/zwierzeta/">Zwierzęta</a>, <a href="/katalog/motyw/ptak/">Ptak</a>, <a href="/katalog/motyw/motyl/">Motyl</a>, <a href="/katalog/motyw/kot/">Kot</a>, <a href="/katalog/motyw/kon/">Koń</a>, <a href="/katalog/motyw/pies/">Pies</a>, <a href="/katalog/motyw/waz/">Wąż</a>, <a href="/katalog/motyw/potwor/">Potwór</a></span></li>
- </ol>
- <p><a href="#" class="show-all-tags" title="{% trans "Themes and topics" %}">{% trans "See more" %}</a></p>
- </div>
- <div class="all-tags">
- <ol>
- <li>cielesność
- <span class="subcategories"><a href="/katalog/motyw/cialo/">Ciało</a>, <a href="/katalog/motyw/krew/">Krew</a>, <a href="/katalog/motyw/zdrowie/">Zdrowie</a>, <a href="/katalog/motyw/choroba/">Choroba</a>, <a href="/katalog/motyw/kaleka/">Kaleka</a></span></li>
-
- <li>dom
- <span class="subcategories"><a href="/katalog/motyw/dom/">Dom</a>, <a href="/katalog/motyw/ogrod/">Ogród</a>, <a href="/katalog/motyw/przestrzen/">Przestrzeń</a>, <a href="/katalog/motyw/gospodarz/">Gospodarz</a>, <a href="/katalog/motyw/gospodyni/">Gospodyni</a>, <a href="/katalog/motyw/sasiad/">Sąsiad</a>, <a href="/katalog/motyw/gosc/">Gość</a>, <a href="/katalog/motyw/bezdomnosc/">Bezdomność</a>, <a href="/katalog/motyw/bezpieczenstwo/">Bezpieczeństwo</a>, <a href="/katalog/motyw/niebezpieczenstwo/">Niebezpieczeństwo</a></span></li>
-
- <li>działania nieczyste
- <span class="subcategories"><a href="/katalog/motyw/szantaz/">Szantaż</a>, <a href="/katalog/motyw/zazdrosc/">Zazdrość</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a>, <a href="/katalog/motyw/zemsta/">Zemsta</a>, <a href="/katalog/motyw/klamstwo/">Kłamstwo</a>, <a href="/katalog/motyw/falsz/">Fałsz</a>, <a href="/katalog/motyw/pozory/">Pozory</a>, <a href="/katalog/motyw/tajemnica/">Tajemnica</a></span></li>
-
- <li>dziedzictwo
- <span class="subcategories"><a href="/katalog/motyw/dziedzictwo/">Dziedzictwo</a>, <a href="/katalog/motyw/obyczaje/">Obyczaje</a>, <a href="/katalog/motyw/pamiec/">Pamięć</a>, <a href="/katalog/motyw/historia/">Historia</a>, <a href="/katalog/motyw/narod/">Naród</a>, <a href="/katalog/motyw/krew/">Krew</a>, <a href="/katalog/motyw/panstwo/">Państwo</a>, <a href="/katalog/motyw/obowiazek/">Obowiązek</a>, <a href="/katalog/motyw/patriota/">Patriota</a>, <a href="/katalog/motyw/ruiny/">Ruiny</a>, <a href="/katalog/motyw/dom/">Dom</a>, <a href="/katalog/motyw/przywodca/">Przywódca</a></span></li>
-
- <li>dźwięk
- <span class="subcategories"><a href="/katalog/motyw/cisza/">Cisza</a>, <a href="/katalog/motyw/muzyka/">Muzyka</a>, <a href="/katalog/motyw/spiew/">Śpiew</a>, <a href="/katalog/motyw/poezja/">Poezja</a></span></li>
-
- <li>edukacja
- <span class="subcategories"><a href="/katalog/motyw/uczen/">Uczeń</a>, <a href="/katalog/motyw/szkola/">Szkoła</a>, <a href="/katalog/motyw/nauczyciel/">Nauczyciel</a>, <a href="/katalog/motyw/nauczycielka/">Nauczycielka</a>, <a href="/katalog/motyw/nauka/">Nauka</a>, <a href="/katalog/motyw/wiedza/">Wiedza</a>, <a href="/katalog/motyw/dziecinstwo/">Dzieciństwo</a>, <a href="/katalog/motyw/mlodosc/">Młodość</a>, <a href="/katalog/motyw/doroslosc/">Dorosłość</a></span></li>
-
- <li>egzystencja ludzka
- <span class="subcategories"><a href="/katalog/motyw/kondycja-ludzka/">Kondycja ludzka</a>, <a href="/katalog/motyw/los/">Los</a>, <a href="/katalog/motyw/bladzenie/">Błądzenie</a>, <a href="/katalog/motyw/bunt/">Bunt</a>, <a href="/katalog/motyw/buntownik/">Buntownik</a>, <a href="/katalog/motyw/pielgrzym/">Pielgrzym</a>, <a href="/katalog/motyw/theatrum-mundi/">Theatrum mundi</a>, <a href="/katalog/motyw/zycie-jako-wedrowka/">Życie jako wędrówka</a>, <a href="/katalog/motyw/zycie-snem/">Życie snem</a></span></li>
-
- <li>etapy życia
- <span class="subcategories"><a href="/katalog/motyw/dziecinstwo/">Dzieciństwo</a>, <a href="/katalog/motyw/mlodosc/">Młodość</a>, <a href="/katalog/motyw/doroslosc/">Dorosłość</a>, <a href="/katalog/motyw/panna-mloda/">Panna młoda</a>, <a href="/katalog/motyw/zona/">Żona</a>, <a href="/katalog/motyw/maz/">Mąż</a>, <a href="/katalog/motyw/wdowa/">Wdowa</a>, <a href="/katalog/motyw/wdowiec/">Wdowiec</a>, <a href="/katalog/motyw/starosc/">Starość</a>, <a href="/katalog/motyw/czas/">Czas</a>, <a href="/katalog/motyw/przemijanie/">Przemijanie</a>, <a href="/katalog/motyw/przemiana/">Przemiana</a>, <a href="/katalog/motyw/kondycja-ludzka/">Kondycja ludzka</a></span></li>
-
- <li>fauna
- <span class="subcategories"><a href="/katalog/motyw/zwierzeta/">Zwierzęta</a>, <a href="/katalog/motyw/kot/">Kot</a>, <a href="/katalog/motyw/kon/">Koń</a>, <a href="/katalog/motyw/motyl/">Motyl</a>, <a href="/katalog/motyw/pies/">Pies</a>, <a href="/katalog/motyw/ptak/">Ptak</a>, <a href="/katalog/motyw/waz/">Wąż</a></span></li>
-
- <li>flora
- <span class="subcategories"><a href="/katalog/motyw/rosliny/">Rośliny</a>, <a href="/katalog/motyw/kwiaty/">Kwiaty</a>, <a href="/katalog/motyw/ogrod/">Ogród</a>, <a href="/katalog/motyw/drzewo/">Drzewo</a></span></li>
-
- <li>historie miłosne
- <span class="subcategories"><a href="/katalog/motyw/milosc/">Miłość</a>, <a href="/katalog/motyw/milosc-platoniczna/">Miłość platoniczna</a>, <a href="/katalog/motyw/milosc-romantyczna/">Miłość romantyczna</a>, <a href="/katalog/motyw/milosc-silniejsza-niz-smierc/">Miłość silniejsza niż śmierć</a>, <a href="/katalog/motyw/milosc-spelniona/">Miłość spełniona</a>, <a href="/katalog/motyw/milosc-tragiczna/">Miłość tragiczna</a>, <a href="/katalog/motyw/kochanek/">Kochanek</a>, <a href="/katalog/motyw/kochanek-romantyczny/">Kochanek romantyczny</a>, <a href="/katalog/motyw/flirt/">Flirt</a>, <a href="/katalog/motyw/pocalunek/">Pocałunek</a>, <a href="/katalog/motyw/pozadanie/">Pożądanie</a>, <a href="/katalog/motyw/list/">List</a>, <a href="/katalog/motyw/serce/">Serce</a>, <a href="/katalog/motyw/lzy/">Łzy</a>, <a href="/katalog/motyw/przysiega/">Przysięga</a>, <a href="/katalog/motyw/tesknota/">Tęsknota</a>, <a href="/katalog/motyw/wspomnienia/">Wspomnienia</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a>, <a href="/katalog/motyw/rozczarowanie/">Rozczarowanie</a>, <a href="/katalog/motyw/rozpacz/">Rozpacz</a>, <a href="/katalog/motyw/malzenstwo/">Małżeństwo</a>, <a href="/katalog/motyw/slub/">Ślub</a>, <a href="/katalog/motyw/panna-mloda/">Panna młoda</a>, <a href="/katalog/motyw/przyjazn/">Przyjaźń</a></span></li>
-
- <li>jedzenie i picie
- <span class="subcategories"><a href="/katalog/motyw/glod/">Głód</a>, <a href="/katalog/motyw/bieda/">Bieda</a>, <a href="/katalog/motyw/chleb/">Chleb</a>, <a href="/katalog/motyw/jedzenie/">Jedzenie</a>, <a href="/katalog/motyw/uczta/">Uczta</a>, <a href="/katalog/motyw/wino/">Wino</a>, <a href="/katalog/motyw/alkohol/">Alkohol</a>, <a href="/katalog/motyw/pijanstwo/">Pijaństwo</a></span></li>
-
- <li>konflikty
- <span class="subcategories"><a href="/katalog/motyw/klotnia/">Kłótnia</a>, <a href="/katalog/motyw/bijatyka/">Bijatyka</a>, <a href="/katalog/motyw/sila/">Siła</a>, <a href="/katalog/motyw/przemoc/">Przemoc</a>, <a href="/katalog/motyw/krew/">Krew</a>, <a href="/katalog/motyw/konflikt/">Konflikt</a>, <a href="/katalog/motyw/walka/">Walka</a>, <a href="/katalog/motyw/wojna/">Wojna</a>, <a href="/katalog/motyw/powstanie/">Powstanie</a>, <a href="/katalog/motyw/bunt/">Bunt</a>, <a href="/katalog/motyw/rewolucja/">Rewolucja</a></span></li>
-
- <li>momenty graniczne
- <span class="subcategories"><a href="/katalog/motyw/narodziny/">Narodziny</a>, <a href="/katalog/motyw/smierc/">Śmierć</a>, <a href="/katalog/motyw/przemiana/">Przemiana</a>, <a href="/katalog/motyw/zmartwychwstanie/">Zmartwychwstanie</a></span></li>
-
- <li>nadużycie władzy
- <span class="subcategories"><a href="/katalog/motyw/wladza/">Władza</a>, <a href="/katalog/motyw/przemoc/">Przemoc</a>, <a href="/katalog/motyw/strach/">Strach</a>, <a href="/katalog/motyw/kara/">Kara</a></span></li>
-
- <li>nacjonalizm
- <span class="subcategories"><a href="/katalog/motyw/polak/">Polak</a>, <a href="/katalog/motyw/niemiec/">Niemiec</a>, <a href="/katalog/motyw/rosjanin/">Rosjanin</a>, <a href="/katalog/motyw/car/">Car</a>, <a href="/katalog/motyw/zyd/">Żyd</a>, <a href="/katalog/motyw/narod/">Naród</a>, <a href="/katalog/motyw/obcy/">Obcy</a>, <a href="/katalog/motyw/wrog/">Wróg</a>, <a href="/katalog/motyw/niebezpieczenstwo/">Niebezpieczeństwo</a></span></li>
-
- <li>nastroje melancholijne
- <span class="subcategories"><a href="/katalog/motyw/nuda/">Nuda</a>, <a href="/katalog/motyw/melancholia/">Melancholia</a>, <a href="/katalog/motyw/ruiny/">Ruiny</a>, <a href="/katalog/motyw/wspomnienia/">Wspomnienia</a>, <a href="/katalog/motyw/marzenie/">Marzenie</a>, <a href="/katalog/motyw/przemijanie/">Przemijanie</a>, <a href="/katalog/motyw/tesknota/">Tęsknota</a>, <a href="/katalog/motyw/rozpacz/">Rozpacz</a>, <a href="/katalog/motyw/smierc/">Śmierć</a>, <a href="/katalog/motyw/los/">Los</a>, <a href="/katalog/motyw/kondycja-ludzka/">Kondycja ludzka</a></span></li>
-
- <li>nastroje rewolucyjne
- <span class="subcategories"><a href="/katalog/motyw/rewolucja/">Rewolucja</a>, <a href="/katalog/motyw/walka-klas/">Walka klas</a>, <a href="/katalog/motyw/robotnik/">Robotnik</a>, <a href="/katalog/motyw/chlop/">Chłop</a>, <a href="/katalog/motyw/pozycja-spoleczna/">Pozycja społeczna</a>, <a href="/katalog/motyw/wladza/">Władza</a>, <a href="/katalog/motyw/przemoc/">Przemoc</a>, <a href="/katalog/motyw/sprawiedliwosc/">Sprawiedliwość</a></span></li>
-
- <li>podporządkowanie
- <span class="subcategories"><a href="/katalog/motyw/sluga/">Sługa</a>, <a href="/katalog/motyw/pan/">Pan</a>, <a href="/katalog/motyw/praca/">Praca</a>, <a href="/katalog/motyw/wladza/">Władza</a>, <a href="/katalog/motyw/obyczaje/">Obyczaje</a></span></li>
-
- <li>pokrewieństwo
- <span class="subcategories"><a href="/katalog/motyw/rodzina/">Rodzina</a>, <a href="/katalog/motyw/ojciec/">Ojciec</a>, <a href="/katalog/motyw/matka/">Matka</a>, <a href="/katalog/motyw/dziecko/">Dziecko</a>, <a href="/katalog/motyw/syn/">Syn</a>, <a href="/katalog/motyw/corka/">Córka</a>, <a href="/katalog/motyw/brat/">Brat</a>, <a href="/katalog/motyw/siostra/">Siostra</a>, <a href="/katalog/motyw/sierota/">Sierota</a>, <a href="/katalog/motyw/dziedzictwo/">Dziedzictwo</a>, <a href="/katalog/motyw/obowiazek/">Obowiązek</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a></span></li>
-
- <li>polityczny obraz świata
- <span class="subcategories"><a href="/katalog/motyw/panstwo/">Państwo</a>, <a href="/katalog/motyw/obowiazek/">Obowiązek</a>, <a href="/katalog/motyw/cnota/">Cnota</a>, <a href="/katalog/motyw/obywatel/">Obywatel</a>, <a href="/katalog/motyw/patriota/">Patriota</a>, <a href="/katalog/motyw/ojczyzna/">Ojczyzna</a>, <a href="/katalog/motyw/narod/">Naród</a>, <a href="/katalog/motyw/przywodca/">Przywódca</a>, <a href="/katalog/motyw/wladza/">Władza</a>, <a href="/katalog/motyw/urzednik/">Urzędnik</a>, <a href="/katalog/motyw/krol/">Król</a>, <a href="/katalog/motyw/rycerz/">Rycerz</a>, <a href="/katalog/motyw/zolnierz/">Żołnierz</a>, <a href="/katalog/motyw/wojna/">Wojna</a>, <a href="/katalog/motyw/wrog/">Wróg</a>, <a href="/katalog/motyw/zwyciestwo/">Zwycięstwo</a>, <a href="/katalog/motyw/walka/">Walka</a>, <a href="/katalog/motyw/sila/">Siła</a>, <a href="/katalog/motyw/historia/">Historia</a>, <a href="/katalog/motyw/powstanie/">Powstanie</a>, <a href="/katalog/motyw/smierc-bohaterska/">Śmierć bohaterska</a>, <a href="/katalog/motyw/slawa/">Sława</a>, <a href="/katalog/motyw/rewolucja/">Rewolucja</a>, <a href="/katalog/motyw/sad/">Sąd</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a></span></li>
-
- <li>pory roku
- <span class="subcategories"><a href="/katalog/motyw/wiosna/">Wiosna</a>, <a href="/katalog/motyw/lato/">Lato</a>, <a href="/katalog/motyw/jesien/">Jesień</a>, <a href="/katalog/motyw/zima/">Zima</a>, <a href="/katalog/motyw/czas/">Czas</a>, <a href="/katalog/motyw/przemijanie/">Przemijanie</a></span></li>
-
- <li>posiadanie
- <span class="subcategories"><a href="/katalog/motyw/pieniadz/">Pieniądz</a>, <a href="/katalog/motyw/handel/">Handel</a>, <a href="/katalog/motyw/korzysc/">Korzyść</a>, <a href="/katalog/motyw/chciwosc/">Chciwość</a>, <a href="/katalog/motyw/bieda/">Bieda</a>, <a href="/katalog/motyw/bogactwo/">Bogactwo</a>, <a href="/katalog/motyw/skapiec/">Skąpiec</a>, <a href="/katalog/motyw/wlasnosc/">Własność</a>, <a href="/katalog/motyw/zlodziej/">Złodziej</a>, <a href="/katalog/motyw/zebrak/">Żebrak</a></span></li>
-
- <li>poświęcenie
- <span class="subcategories"><a href="/katalog/motyw/poswiecenie/">Poświęcenie</a>, <a href="/katalog/motyw/ofiara/">Ofiara</a>, <a href="/katalog/motyw/prometeusz/">Prometeusz</a>, <a href="/katalog/motyw/milosierdzie/">Miłosierdzie</a>, <a href="/katalog/motyw/chrystus/">Chrystus</a>, <a href="/katalog/motyw/zbawienie/">Zbawienie</a></span></li>
-
- <li>poznanie
- <span class="subcategories"><a href="/katalog/motyw/filozof/">Filozof</a>, <a href="/katalog/motyw/madrosc/">Mądrość</a>, <a href="/katalog/motyw/medrzec/">Mędrzec</a>, <a href="/katalog/motyw/glupiec/">Głupiec</a>, <a href="/katalog/motyw/glupota/">Głupota</a>, <a href="/katalog/motyw/rozum/">Rozum</a>, <a href="/katalog/motyw/wiedza/">Wiedza</a>, <a href="/katalog/motyw/prawda/">Prawda</a>, <a href="/katalog/motyw/falsz/">Fałsz</a></span></li>
-
- <li>poznanie alternatywne
- <span class="subcategories"><a href="/katalog/motyw/szaleniec/">Szaleniec</a>, <a href="/katalog/motyw/szalenstwo/">Szaleństwo</a>, <a href="/katalog/motyw/prawda/">Prawda</a>, <a href="/katalog/motyw/pozory/">Pozory</a>, <a href="/katalog/motyw/obraz-swiata/">Obraz świata</a>, <a href="/katalog/motyw/serce/">Serce</a>, <a href="/katalog/motyw/wiedza/">Wiedza</a>, <a href="/katalog/motyw/madrosc/">Mądrość</a>, <a href="/katalog/motyw/dusza/">Dusza</a>, <a href="/katalog/motyw/duch/">Duch</a>, <a href="/katalog/motyw/cialo/">Ciało</a></span></li>
-
- <li>praca
- <span class="subcategories"><a href="/katalog/motyw/praca/">Praca</a>, <a href="/katalog/motyw/sluga/">Sługa</a></span></li>
-
- <li>przyroda
- <span class="subcategories"><a href="/katalog/motyw/natura/">Natura</a>, <a href="/katalog/motyw/zywioly/">Żywioły</a>, <a href="/katalog/motyw/ogien/">Ogień</a>, <a href="/katalog/motyw/ziemia/">Ziemia</a>, <a href="/katalog/motyw/wiatr/">Wiatr</a>, <a href="/katalog/motyw/woda/">Woda</a>, <a href="/katalog/motyw/wiosna/">Wiosna</a>, <a href="/katalog/motyw/lato/">Lato</a>, <a href="/katalog/motyw/jesien/">Jesień</a>, <a href="/katalog/motyw/zima/">Zima</a>, <a href="/katalog/motyw/przemijanie/">Przemijanie</a>, <a href="/katalog/motyw/slonce/">Słońce</a>, <a href="/katalog/motyw/ksiezyc/">Księżyc</a>, <a href="/katalog/motyw/gwiazda/">Gwiazda</a>, <a href="/katalog/motyw/oblok/">Obłok</a>, <a href="/katalog/motyw/noc/">Noc</a>, <a href="/katalog/motyw/swiatlo/">Światło</a>, <a href="/katalog/motyw/gora/">Góra</a>, <a href="/katalog/motyw/rzeka/">Rzeka</a>, <a href="/katalog/motyw/morze/">Morze</a>, <a href="/katalog/motyw/burza/">Burza</a>, <a href="/katalog/motyw/deszcz/">Deszcz</a>, <a href="/katalog/motyw/bloto/">Błoto</a>, <a href="/katalog/motyw/przyroda-nieozywiona/">Przyroda nieożywiona</a>, <a href="/katalog/motyw/rosliny/">Rośliny</a>, <a href="/katalog/motyw/kwiaty/">Kwiaty</a>, <a href="/katalog/motyw/ogrod/">Ogród</a>, <a href="/katalog/motyw/sielanka/">Sielanka</a>, <a href="/katalog/motyw/raj/">Raj</a>, <a href="/katalog/motyw/jablko/">Jabłko</a>, <a href="/katalog/motyw/drzewo/">Drzewo</a>, <a href="/katalog/motyw/zwierzeta/">Zwierzęta</a>, <a href="/katalog/motyw/ptak/">Ptak</a>, <a href="/katalog/motyw/motyl/">Motyl</a>, <a href="/katalog/motyw/kot/">Kot</a>, <a href="/katalog/motyw/kon/">Koń</a>, <a href="/katalog/motyw/pies/">Pies</a>, <a href="/katalog/motyw/waz/">Wąż</a>, <a href="/katalog/motyw/potwor/">Potwór</a></span></li>
-
- <li>regulacja postępowania
- <span class="subcategories"><a href="/katalog/motyw/cnota/">Cnota</a>, <a href="/katalog/motyw/sprawiedliwosc/">Sprawiedliwość</a>, <a href="/katalog/motyw/obowiazek/">Obowiązek</a></span></li>
-
- <li>role społeczne
- <span class="subcategories"><a href="/katalog/motyw/kobieta/">Kobieta</a>, <a href="/katalog/motyw/mezczyzna/">Mężczyzna</a>, <a href="/katalog/motyw/maz/">Mąż</a>, <a href="/katalog/motyw/zona/">Żona</a>, <a href="/katalog/motyw/matka/">Matka</a>, <a href="/katalog/motyw/ojciec/">Ojciec</a>, <a href="/katalog/motyw/dziecko/">Dziecko</a>, <a href="/katalog/motyw/syn/">Syn</a>, <a href="/katalog/motyw/corka/">Córka</a>, <a href="/katalog/motyw/brat/">Brat</a>, <a href="/katalog/motyw/siostra/">Siostra</a>, <a href="/katalog/motyw/wdowa/">Wdowa</a>, <a href="/katalog/motyw/wdowiec/">Wdowiec</a>, <a href="/katalog/motyw/nauczyciel/">Nauczyciel</a>, <a href="/katalog/motyw/nauczycielka/">Nauczycielka</a>, <a href="/katalog/motyw/uczen/">Uczeń</a>, <a href="/katalog/motyw/poeta/">Poeta</a>, <a href="/katalog/motyw/literat/">Literat</a>, <a href="/katalog/motyw/lekarz/">Lekarz</a>, <a href="/katalog/motyw/sedzia/">Sędzia</a>, <a href="/katalog/motyw/krol/">Król</a>, <a href="/katalog/motyw/przywodca/">Przywódca</a>, <a href="/katalog/motyw/zolnierz/">Żołnierz</a>, <a href="/katalog/motyw/urzednik/">Urzędnik</a>, <a href="/katalog/motyw/filozof/">Filozof</a>, <a href="/katalog/motyw/ksiadz/">Ksiądz</a></span></li>
-
- <li>rycerskie czasy
- <span class="subcategories"><a href="/katalog/motyw/zamek/">Zamek</a>, <a href="/katalog/motyw/ruiny/">Ruiny</a>, <a href="/katalog/motyw/rycerz/">Rycerz</a>, <a href="/katalog/motyw/honor/">Honor</a>, <a href="/katalog/motyw/wiernosc/">Wierność</a>, <a href="/katalog/motyw/obowiazek/">Obowiązek</a>, <a href="/katalog/motyw/walka/">Walka</a>, <a href="/katalog/motyw/krol/">Król</a>, <a href="/katalog/motyw/dama/">Dama</a></span></li>
-
- <li>rzeczywistość nadprzyrodzona
- <span class="subcategories"><a href="/katalog/motyw/bog/">Bóg</a>, <a href="/katalog/motyw/chrystus/">Chrystus</a>, <a href="/katalog/motyw/matka-boska/">Matka Boska</a>, <a href="/katalog/motyw/aniol/">Anioł</a>, <a href="/katalog/motyw/szatan/">Szatan</a>, <a href="/katalog/motyw/diabel/">Diabeł</a>, <a href="/katalog/motyw/duch/">Duch</a>, <a href="/katalog/motyw/dusza/">Dusza</a>, <a href="/katalog/motyw/wampir/">Wampir</a>, <a href="/katalog/motyw/upior/">Upiór</a>, <a href="/katalog/motyw/czary/">Czary</a>, <a href="/katalog/motyw/czarownica/">Czarownica</a></span></li>
-
- <li>struktura społeczna
- <span class="subcategories"><a href="/katalog/motyw/chlop/">Chłop</a>, <a href="/katalog/motyw/mieszczanin/">Mieszczanin</a>, <a href="/katalog/motyw/zyd/">Żyd</a>, <a href="/katalog/motyw/szlachcic/">Szlachcic</a>, <a href="/katalog/motyw/ksiadz/">Ksiądz</a>, <a href="/katalog/motyw/robotnik/">Robotnik</a>, <a href="/katalog/motyw/krol/">Król</a>, <a href="/katalog/motyw/przywodca/">Przywódca</a>, <a href="/katalog/motyw/pozycja-spoleczna/">Pozycja społeczna</a>, <a href="/katalog/motyw/dworek/">Dworek</a>, <a href="/katalog/motyw/obyczaje/">Obyczaje</a></span></li>
-
- <li>sarmatyzm
- <span class="subcategories"><a href="/katalog/motyw/polak/">Polak</a>, <a href="/katalog/motyw/sarmata/">Sarmata</a>, <a href="/katalog/motyw/szlachcic/">Szlachcic</a>, <a href="/katalog/motyw/przedmurze-chrzescijanstwa/">Przedmurze chrześcijaństwa</a>, <a href="/katalog/motyw/matka-boska/">Matka Boska</a>, <a href="/katalog/motyw/religia/">Religia</a></span></li>
-
- <li>sprawowanie władzy
- <span class="subcategories"><a href="/katalog/motyw/urzednik/">Urzędnik</a>, <a href="/katalog/motyw/panstwo/">Państwo</a>, <a href="/katalog/motyw/wladza/">Władza</a>, <a href="/katalog/motyw/przemoc/">Przemoc</a>, <a href="/katalog/motyw/sad/">Sąd</a>, <a href="/katalog/motyw/kara/">Kara</a>, <a href="/katalog/motyw/wiezienie/">Więzienie</a></span></li>
-
- <li>śmierć
- <span class="subcategories"><a href="/katalog/motyw/smierc/">Śmierć</a>, <a href="/katalog/motyw/danse-macabre/">Danse macabre</a>, <a href="/katalog/motyw/gotycyzm/">Gotycyzm</a>, <a href="/katalog/motyw/grob/">Grób</a>, <a href="/katalog/motyw/otchlan/">Otchłań</a>, <a href="/katalog/motyw/pogrzeb/">Pogrzeb</a>, <a href="/katalog/motyw/samobojstwo/">Samobójstwo</a>, <a href="/katalog/motyw/krew/">Krew</a>, <a href="/katalog/motyw/trup/">Trup</a>, <a href="/katalog/motyw/morderstwo/">Morderstwo</a>, <a href="/katalog/motyw/zaloba/">Żałoba</a>, <a href="/katalog/motyw/zmartwychwstanie/">Zmartwychwstanie</a>, <a href="/katalog/motyw/melancholia/">Melancholia</a>, <a href="/katalog/motyw/vanitas/">Vanitas</a>, <a href="/katalog/motyw/los/">Los</a>, <a href="/katalog/motyw/kondycja-ludzka/">Kondycja ludzka</a></span></li>
-
- <li>środowisko miejskie i wiejskie
- <span class="subcategories"><a href="/katalog/motyw/miasto/">Miasto</a>, <a href="/katalog/motyw/warszawa/">Warszawa</a>, <a href="/katalog/motyw/mieszczanin/">Mieszczanin</a>, <a href="/katalog/motyw/handel/">Handel</a>, <a href="/katalog/motyw/robotnik/">Robotnik</a>, <a href="/katalog/motyw/zyd/">Żyd</a>, <a href="/katalog/motyw/wies/">Wieś</a>, <a href="/katalog/motyw/sielanka/">Sielanka</a>, <a href="/katalog/motyw/chlop/">Chłop</a>, <a href="/katalog/motyw/ogrod/">Ogród</a>, <a href="/katalog/motyw/natura/">Natura</a>, <a href="/katalog/motyw/przestrzen/">Przestrzeń</a></span></li>
-
- <li>świat w perspektywie etycznej
- <span class="subcategories"><a href="/katalog/motyw/kuszenie/">Kuszenie</a>, <a href="/katalog/motyw/zwatpienie/">Zwątpienie</a>, <a href="/katalog/motyw/wyrzuty-sumienia/">Wyrzuty sumienia</a>, <a href="/katalog/motyw/wina/">Wina</a>, <a href="/katalog/motyw/grzech/">Grzech</a>, <a href="/katalog/motyw/kara/">Kara</a>, <a href="/katalog/motyw/los/">Los</a>, <a href="/katalog/motyw/koniec-swiata/">Koniec świata</a>, <a href="/katalog/motyw/wieza-babel/">Wieża Babel</a>, <a href="/katalog/motyw/zbawienie/">Zbawienie</a>, <a href="/katalog/motyw/zaswiaty/">Zaświaty</a>, <a href="/katalog/motyw/czysciec/">Czyściec</a>, <a href="/katalog/motyw/raj/">Raj</a>, <a href="/katalog/motyw/niesmiertelnosc/">Nieśmiertelność</a>, <a href="/katalog/motyw/przysiega/">Przysięga</a>, <a href="/katalog/motyw/przeklenstwo/">Przekleństwo</a>, <a href="/katalog/motyw/religia/">Religia</a>, <a href="/katalog/motyw/obrzedy/">Obrzędy</a>, <a href="/katalog/motyw/modlitwa/">Modlitwa</a>, <a href="/katalog/motyw/niedziela/">Niedziela</a>, <a href="/katalog/motyw/przedmurze-chrzescijanstwa/">Przedmurze chrześcijaństwa</a>, <a href="/katalog/motyw/ksiadz/">Ksiądz</a>, <a href="/katalog/motyw/poboznosc/">Pobożność</a>, <a href="/katalog/motyw/swietoszek/">Świętoszek</a>, <a href="/katalog/motyw/swiety/">Święty</a>, <a href="/katalog/motyw/wierzenia/">Wierzenia</a>, <a href="/katalog/motyw/zabobony/">Zabobony</a></span></li>
-
- <li>świętowanie
- <span class="subcategories"><a href="/katalog/motyw/wesele/">Wesele</a>, <a href="/katalog/motyw/uczta/">Uczta</a>, <a href="/katalog/motyw/jedzenie/">Jedzenie</a>, <a href="/katalog/motyw/pijanstwo/">Pijaństwo</a>, <a href="/katalog/motyw/zabawa/">Zabawa</a>, <a href="/katalog/motyw/taniec/">Taniec</a>, <a href="/katalog/motyw/muzyka/">Muzyka</a>, <a href="/katalog/motyw/smiech/">Śmiech</a>, <a href="/katalog/motyw/spiew/">Śpiew</a>, <a href="/katalog/motyw/bijatyka/">Bijatyka</a>, <a href="/katalog/motyw/obyczaje/">Obyczaje</a>, <a href="/katalog/motyw/wierzenia/">Wierzenia</a>, <a href="/katalog/motyw/zabobony/">Zabobony</a></span></li>
-
- <li>tożsamość pozorna i podwójna
- <span class="subcategories"><a href="/katalog/motyw/portret/">Portret</a>, <a href="/katalog/motyw/lustro/">Lustro</a>, <a href="/katalog/motyw/cien/">Cień</a>, <a href="/katalog/motyw/sobowtor/">Sobowtór</a>, <a href="/katalog/motyw/maska/">Maska</a>, <a href="/katalog/motyw/przebranie/">Przebranie</a>, <a href="/katalog/motyw/stroj/">Strój</a>, <a href="/katalog/motyw/przemiana/">Przemiana</a></span></li>
-
- <li>trunki
- <span class="subcategories"><a href="/katalog/motyw/alkohol/">Alkohol</a>, <a href="/katalog/motyw/wino/">Wino</a>, <a href="/katalog/motyw/carpe-diem/">Carpe diem</a>, <a href="/katalog/motyw/pijanstwo/">Pijaństwo</a>, <a href="/katalog/motyw/karczma/">Karczma</a>, <a href="/katalog/motyw/obyczaje/">Obyczaje</a></span></li>
-
- <li>typy bohaterów
- <span class="subcategories"><a href="/katalog/motyw/samotnik/">Samotnik</a>, <a href="/katalog/motyw/buntownik/">Buntownik</a>, <a href="/katalog/motyw/pielgrzym/">Pielgrzym</a>, <a href="/katalog/motyw/szaleniec/">Szaleniec</a>, <a href="/katalog/motyw/filozof/">Filozof</a>, <a href="/katalog/motyw/medrzec/">Mędrzec</a>, <a href="/katalog/motyw/obcy/">Obcy</a>, <a href="/katalog/motyw/przywodca/">Przywódca</a>, <a href="/katalog/motyw/realista/">Realista</a>, <a href="/katalog/motyw/idealista/">Idealista</a>, <a href="/katalog/motyw/spolecznik/">Społecznik</a>, <a href="/katalog/motyw/syzyf/">Syzyf</a>, <a href="/katalog/motyw/prometeusz/">Prometeusz</a>, <a href="/katalog/motyw/sluga/">Sługa</a>, <a href="/katalog/motyw/uczen/">Uczeń</a></span></li>
-
- <li>ukrywanie/ujawnianie
- <span class="subcategories"><a href="/katalog/motyw/tajemnica/">Tajemnica</a>, <a href="/katalog/motyw/przysiega/">Przysięga</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a>, <a href="/katalog/motyw/klamstwo/">Kłamstwo</a>, <a href="/katalog/motyw/falsz/">Fałsz</a></span></li>
-
- <li>upływ czasu
- <span class="subcategories"><a href="/katalog/motyw/wspomnienia/">Wspomnienia</a>, <a href="/katalog/motyw/marzenie/">Marzenie</a>, <a href="/katalog/motyw/pamiec/">Pamięć</a>, <a href="/katalog/motyw/przemijanie/">Przemijanie</a>, <a href="/katalog/motyw/czas/">Czas</a>, <a href="/katalog/motyw/smierc/">Śmierć</a></span></li>
-
- <li>widzenie
- <span class="subcategories"><a href="/katalog/motyw/oko/">Oko</a>, <a href="/katalog/motyw/wzrok/">Wzrok</a>, <a href="/katalog/motyw/sen/">Sen</a>, <a href="/katalog/motyw/marzenie/">Marzenie</a>, <a href="/katalog/motyw/wizja/">Wizja</a>, <a href="/katalog/motyw/przeczucie/">Przeczucie</a>, <a href="/katalog/motyw/duch/">Duch</a>, <a href="/katalog/motyw/dusza/">Dusza</a>, <a href="/katalog/motyw/proroctwo/">Proroctwo</a></span></li>
-
- <li>wina i przebaczenie
- <span class="subcategories"><a href="/katalog/motyw/grzech/">Grzech</a>, <a href="/katalog/motyw/wina/">Wina</a>, <a href="/katalog/motyw/wyrzuty-sumienia/">Wyrzuty sumienia</a>, <a href="/katalog/motyw/syn-marnotrawny/">Syn marnotrawny</a>, <a href="/katalog/motyw/pokora/">Pokora</a>, <a href="/katalog/motyw/przemiana/">Przemiana</a>, <a href="/katalog/motyw/milosierdzie/">Miłosierdzie</a>, <a href="/katalog/motyw/zbawienie/">Zbawienie</a></span></li>
-
- <li>wizerunki kobiety
- <span class="subcategories"><a href="/katalog/motyw/kobieta/">Kobieta</a>, <a href="/katalog/motyw/kobieta-demoniczna/">Kobieta demoniczna</a>, <a href="/katalog/motyw/kobieta-upadla/">Kobieta „upadła”</a>, <a href="/katalog/motyw/czarownica/">Czarownica</a>, <a href="/katalog/motyw/dama/">Dama</a>, <a href="/katalog/motyw/proznosc/">Próżność</a>, <a href="/katalog/motyw/cialo/">Ciało</a>, <a href="/katalog/motyw/corka/">Córka</a>, <a href="/katalog/motyw/siostra/">Siostra</a>, <a href="/katalog/motyw/zona/">Żona</a>, <a href="/katalog/motyw/matka/">Matka</a></span></li>
-
- <li>w kręgu sztuki
- <span class="subcategories"><a href="/katalog/motyw/artysta/">Artysta</a>, <a href="/katalog/motyw/sztuka/">Sztuka</a>, <a href="/katalog/motyw/literat/">Literat</a>, <a href="/katalog/motyw/poeta/">Poeta</a>, <a href="/katalog/motyw/poetka/">Poetka</a>, <a href="/katalog/motyw/poezja/">Poezja</a>, <a href="/katalog/motyw/muzyka/">Muzyka</a>, <a href="/katalog/motyw/taniec/">Taniec</a>, <a href="/katalog/motyw/spiew/">Śpiew</a>, <a href="/katalog/motyw/teatr/">Teatr</a>, <a href="/katalog/motyw/ksiazka/">Książka</a>, <a href="/katalog/motyw/slowo/">Słowo</a>, <a href="/katalog/motyw/slawa/">Sława</a>, <a href="/katalog/motyw/niesmiertelnosc/">Nieśmiertelność</a></span></li>
-
- <li>wychodźstwo i uwięzienie
- <span class="subcategories"><a href="/katalog/motyw/emigrant/">Emigrant</a>, <a href="/katalog/motyw/tesknota/">Tęsknota</a>, <a href="/katalog/motyw/obcy/">Obcy</a>, <a href="/katalog/motyw/wiezienie/">Więzienie</a>, <a href="/katalog/motyw/przemiana/">Przemiana</a>, <a href="/katalog/motyw/wiezien/">Więzień</a>, <a href="/katalog/motyw/wolnosc/">Wolność</a>, <a href="/katalog/motyw/niewola/">Niewola</a>, <a href="/katalog/motyw/wygnanie/">Wygnanie</a>, <a href="/katalog/motyw/zeslaniec/">Zesłaniec</a>, <a href="/katalog/motyw/zbrodnia/">Zbrodnia</a>, <a href="/katalog/motyw/zbrodniarz/">Zbrodniarz</a></span></li>
-
- <li>zagrożenie
- <span class="subcategories"><a href="/katalog/motyw/niebezpieczenstwo/">Niebezpieczeństwo</a>, <a href="/katalog/motyw/trucizna/">Trucizna</a>, <a href="/katalog/motyw/falsz/">Fałsz</a>, <a href="/katalog/motyw/zdrada/">Zdrada</a>, <a href="/katalog/motyw/choroba/">Choroba</a>, <a href="/katalog/motyw/smierc/">Śmierć</a></span></li>
-
- <li>zajęcia i zawody
- <span class="subcategories"><a href="/katalog/motyw/lekarz/">Lekarz</a>, <a href="/katalog/motyw/prawnik/">Prawnik</a>, <a href="/katalog/motyw/sedzia/">Sędzia</a>, <a href="/katalog/motyw/nauczyciel/">Nauczyciel</a>, <a href="/katalog/motyw/nauczycielka/">Nauczycielka</a>, <a href="/katalog/motyw/literat/">Literat</a>, <a href="/katalog/motyw/poeta/">Poeta</a>, <a href="/katalog/motyw/poetka/">Poetka</a>, <a href="/katalog/motyw/artysta/">Artysta</a>, <a href="/katalog/motyw/zolnierz/">Żołnierz</a>, <a href="/katalog/motyw/urzednik/">Urzędnik</a>, <a href="/katalog/motyw/sluga/">Sługa</a>, <a href="/katalog/motyw/rycerz/">Rycerz</a></span></li>
-
- <li>życie dworskie
- <span class="subcategories"><a href="/katalog/motyw/dworzanin/">Dworzanin</a>, <a href="/katalog/motyw/dwor/">Dwór</a>, <a href="/katalog/motyw/dama/">Dama</a>, <a href="/katalog/motyw/fircyk/">Fircyk</a>, <a href="/katalog/motyw/blazen/">Błazen</a>, <a href="/katalog/motyw/krol/">Król</a>, <a href="/katalog/motyw/urzednik/">Urzędnik</a>, <a href="/katalog/motyw/sluga/">Sługa</a>, <a href="/katalog/motyw/grzecznosc/">Grzeczność</a>, <a href="/katalog/motyw/obyczaje/">Obyczaje</a>, <a href="/katalog/motyw/pochlebstwo/">Pochlebstwo</a></span></li>
-
- <li>żywioły
- <span class="subcategories"><a href="/katalog/motyw/zywioly/">Żywioły</a>, <a href="/katalog/motyw/ogien/">Ogień</a>, <a href="/katalog/motyw/ziemia/">Ziemia</a>, <a href="/katalog/motyw/wiatr/">Wiatr</a>, <a href="/katalog/motyw/woda/">Woda</a>, <a href="/katalog/motyw/przestrzen/">Przestrzeń</a></span></li>
- </ol>
- <p><a href="#" class="hide-all-tags">{% trans "Hide" %}</a></p>
- </div>
- </div>
- <div class="clearboth"></div>
- </div>
- </div>
- <div class="clearboth"></div>
-
- <div id="site-info">
- <div id="latest-blog-posts">
- <h2>{% trans "News" %}</h2>
- {% cache 1800 latest-blog-posts %}
- {% latest_blog_posts "http://nowoczesnapolska.org.pl/category/wolne-lektury/feed/" %}
- {% endcache %}
- <p class="see-more"><a href="http://www.nowoczesnapolska.org.pl/">{% trans "See our blog" %} ⇒</a></p>
- </div>
- <div id="you-can-help">
- <h2>{% trans "You can help us!" %}</h2>
- <ul>
- <li>{% trans "Become a volunteer – an editor, developer or translator." %}</li>
- <li>{% trans "Gain new skills and experience." %}</li>
- <li>{% trans "Join an open project of creating an innovative online library." %}</li>
- </ul>
- <p class="see-more"><a href="{% url help_us %}" title="{% trans "You can help us!" %}">{% trans "You can help us!" %} ⇒</a></p>
- </div>
- <div id="about-us">
- <h2>{% trans "About us" %}</h2>
- <p>
- {% blocktrans %}
- Internet library with school readings “Wolne Lektury” (<a href="http://wolnelektury.pl">www.wolnelektury.pl</a>) is a project made by Modern Poland Foundation. It started in 2007 and shares school readings, which are recommended by Ministry of National Education and are in public domain.
- {% endblocktrans %}
- </p>
- <p class="see-more"><a href="{% url about_us %}" title="{% trans "About us" %}">{% trans "See more" %} ⇒</a></p>
- </div>
- </div>
-{% endblock %}
-
-
-{% block add_footer %}
-
-<p>
-{% blocktrans %}
-Portions of this page are modifications based on work created and <a href="http://code.google.com/policies.html">shared by Google</a> and used
-according to terms described in the <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons
-3.0 Attribution License</a>.
-{% endblocktrans %}
-</p>
-
-{% endblock %}
--- /dev/null
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags pagination_tags %}
+{% load thumbnail %}
+
+
+{% block titleextra %}{{ picture.title }}{% endblock %}
+
+{% block bodyid %}picture-detail{% endblock %}
+
+{% block body %}
+ <h1>{{picture.title}}</h1>
+
+ <div id="books-list">
+ <div id='breadcrumbs'>
+ {% if categories.author %}
+ {% for tag in categories.author %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ »
+ {% endif %}
+ </div>
+
+ {% thumbnail picture.image_file "400x500" upscale="false" as im %}
+ <img style="margin:{{ im|margin:"500x500" }}" src="{{ im.url }}" width="{{ im.x }}" height="{{ im.y }}" />
+ {% endthumbnail %}
+
+ {% if picture.info.license %}
+ <p>{% trans "Work is licensed under " %} <a href="{{ picture.info.license }}">{{ picture.info.license_description }}</a>.</p>
+ {% endif %}
+ <p>{% trans "Based on" %}: {{ picture.info.source_name }}</p>
+ {% if picture.info.description %}
+ <div id="description">
+ <div id='description-long'>{{ picture.info.description|safe }}</div>
+{%comment%} <div id='description-short'>{{ picture.info.description|safe|truncatewords_html:30 }}</div>{%endcomment%}
+ </div>
+ <div id="toggle-description"><p></p></div>
+ {% endif %}
+
+ </div>
+
+ <div id="tags-list">
+ <div id="book-info">
+ <h2>{% trans "Details" %}</h2>
+ <ul>
+ <li>
+ {% trans "Author" %}:
+ {% for tag in categories.author %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ </li>
+ <li>
+ {% trans "Epoch" %}:
+ {% for tag in categories.epoch %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ </li>
+ <li>
+ {% trans "Kind" %}:
+ {% for tag in categories.kind %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+ </li>
+ </ul>
+ <h2>{% trans "Other resources" %}</h2>
+ <ul>
+ {% if picture.info.source_url %}
+ <li><a href="{{ picture.info.source_url }}">{% trans "Source of the image" %}</a></li>
+ {% endif %}
+ {% if picture.info.about and not hide_about %}
+ <li><a href="{{ picture.info.about }}">{% trans "Image on the Editor's Platform" %}</a></li>
+ {% endif %}
+{% comment %}
+ {% if book.gazeta_link %}
+ <li><a href="{{ book.gazeta_link }}">{% trans "Picture description on Lektury.Gazeta.pl" %}</a></li>
+ {% endif %}
+ {% if book.wiki_link %}
+ <li><a href="{{ book.wiki_link }}">{% trans "Book description on Wikipedia" %}</a></li>
+ {% endif %}
+{% endcomment %}
+ </ul>
+ <p><a href="{{ picture.xml_file.url }}">{% trans "View XML source" %}</a></p>
+ </div>
+ <div id="themes-list">
+ <h2>{% trans "Work's themes " %}</h2>
+ <ul>
+ {% for theme in picture_themes %}
+ <li><a href="{{ theme.get_absolute_url }}">{{ theme }} ({{ theme.count }})</a></li>
+ {% endfor %}
+ </ul>
+ </div>
+ <div class="clearboth"></div>
+ </div>
+{% endblock %}
--- /dev/null
+{% extends "catalogue/book_list.html" %}
+{% load i18n %}
+{% load catalogue_tags chunks %}
+{% load thumbnail %}
+
+{% block bodyid %}picture-list{% endblock %}
+
+{% block titleextra %}{% trans "Listing of all pictures" %}{% endblock %}
+
+{% block picture_list_header %}{% trans "Listing of all pictures" %}{% endblock %}
+
+
+{% block book_list %}
+{% for author, group in pictures_by_author.items %}
+<a name="{{ author.slug }}"/>
+<div class="group">
+ <h2><a href="{{ author.get_absolute_url }}">{{ author }}</a></h2>
+ {% for picture in group %}
+ <div class="picture">
+ {% thumbnail picture.image_file "300x300" as im %}
+ <img style="float: left; margin:{{ im|margin:"300x300" }}" src="{{ im.url }}" width="{{ im.x }}" height="{{ im.y }}" />
+ {% endthumbnail %}
+ <span class="title"><a href="{{picture.get_absolute_url}}">{{picture.title}}</a></span>
+ <br class="clearboth"/>
+ </div>
+ {% endfor %}
+</div>
+
+{% endfor %}
+
+{% endblock %}
+
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ {% load i18n compressed %}
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Content-Style-Type" content="text/css" />
+ <meta name="description"
+ content="{{ book.title }} - darmowy audiobook na wolnej licencji" />
+ <title>{% trans "Wolne Lektury" %} ::
+ {{ book.title }} - {{ audiobook }}</title>
+ <link rel="icon" href="{{ STATIC_URL }}img/favicon.png" type="image/png" />
+ {% compressed_css "all" %}
+ {% compressed_css "player" %}
+
+ </head>
+ <body id="{% block bodyid %}player{% endblock %}">
+
+
+
+
+<div class="jp-type-playlist">
+ <div id="jplayer" class="jp-jplayer"
+ data-supplied="{% if have_oggs %}ogg,{% endif %}mp3"></div>
+ <div id="jp_container_1" class="jp-audio">
+ <div class="jp-type-single">
+ <div class="jp-gui jp-interface">
+ <ul class="jp-controls">
+ <li><a href="javascript:;" class="jp-play" tabindex="1">play</a></li>
+ <li><a href="javascript:;" class="jp-pause" tabindex="1">pause</a></li>
+ <li><a href="javascript:;" class="jp-stop" tabindex="1">stop</a></li>
+ <li><a href="javascript:;" class="jp-mute" tabindex="1" title="mute">mute</a></li>
+ <li><a href="javascript:;" class="jp-unmute" tabindex="1" title="unmute">unmute</a></li>
+ <li><a href="javascript:;" class="jp-volume-max" tabindex="1" title="max volume">max volume</a></li>
+ </ul>
+ <div class="jp-progress">
+ <div class="jp-seek-bar">
+ <div class="jp-play-bar"></div>
+ </div>
+ </div>
+ <div class="jp-volume-bar">
+ <div class="jp-volume-bar-value"></div>
+ </div>
+ <div class="jp-time-holder">
+ <div class="jp-current-time"></div>
+ <div class="jp-duration"></div>
+ </div>
+ </div>
+
+ <div class="jp-playlist">
+ <ul>
+
+ {% for i in audiobooks %}
+ <li>
+ <span class='jp-free-media'>
+ (<a class='mp3' href='{{ i.mp3.file.url }}'>mp3</a>{% if i.ogg %}
+ | <a class='ogg' href='{{ i.ogg.file.url }}'>ogg</a>{% endif %})
+ </span>
+ <span class='play'>{{ i.mp3.name }}</span>
+ <div class='extra-info'>
+ {% trans "Artist" %}: <span class='artist'>{{ i.mp3.get_extra_info_value.artist_name }}</span>,
+ {% trans "Director" %}: <span class='director'>{{ i.mp3.get_extra_info_value.director_name }}</span>
+ </div>
+ </li>
+ {% endfor %}
+
+ </ul>
+ </div>
+
+ <div class="jp-no-solution">
+ <span>Update Required</span>
+ To play the media you will need to either update your browser to a recent version or update your <a href="http://get.adobe.com/flashplayer/" target="_blank">Flash plugin</a>.
+ </div>
+ </div>
+ </div>
+</div>
+
+
+ <p>{% trans "Download as" %}:
+ <a href="{% url download_zip_mp3 book.slug %}">MP3</a>{% if have_oggs %},
+ <a href="{% url download_zip_ogg book.slug %}">Ogg Vorbis</a>{% endif %}.
+ </p>
+
+
+ {% if book.has_daisy_file %}
+ <p>DAISY:</p>
+ <ul class="audiobook-list" id="daisy-files">
+ {% for media in book.get_daisy %}
+ <li><a href="{{ media.file.url }}">{{ media.name }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+
+
+ {% if projects|length > 1 %}
+ <p>{% trans "Audiobooks were prepared as a part of the projects:" %}</p>
+ <ul>
+ {% for cs, fb in projects %}
+ <li>
+ {% if fb %}
+ {% blocktrans %}{{ cs }}, funded by {{ fb }}{% endblocktrans %}
+ {% else %}
+ {{ cs }}
+ {% endif %}
+ </li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p>
+ {% with projects.0.0 as cs %}
+ {% with projects.0.1 as fb %}
+ {% if fb %}
+ {% blocktrans %}Audiobooks were prepared as a part of the {{ cs }} project funded by {{ fb }}.{% endblocktrans %}
+ {% else %}
+ {% blocktrans %}Audiobooks were prepared as a part of the {{ cs }} project.{% endblocktrans %}
+ {% endif %}
+ {% endwith %}
+ {% endwith %}
+ </p>
+ {% endif %}
+
+
+
+
+
+
+
+
+
+ <div class="clearboth"></div>
+
+
+
+
+
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ {% compressed_js "player" %}
+
+ <!--{{ piwik_tag|safe }}
+ <script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+ </script>
+ <script type="text/javascript">
+ var pageTracker = _gat._getTracker("UA-2576694-1");
+ pageTracker._trackPageview();
+ </script>-->
+ </body>
+</html>
+++ /dev/null
-{% load i18n %}
-<form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{%trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to the main page" %}</a></p>
-</form>
{% load i18n %}
{% load catalogue_tags pagination_tags %}
-{% block title %}{% trans "Searching in" %} WolneLektury.pl{% endblock %}
+{% block titleextra %}{% trans "Search" %}{% endblock %}
{% block bodyid %}tagged-object-list{% endblock %}
{% block body %}
- <h1>{% title_from_tags tags %}</h1>
- {% breadcrumbs tags %}
+ <h1>{% trans "Search" %}</h1>
+ {% if did_you_mean %}
+ <span class="did_you_mean">{% trans "Dod you mean" %} <a href="{% url search %}?q={{did_you_mean|urlencode}}">{{did_you_mean|lower}}</a></b>?</span>
+ {% endif %}
+ <div id="results">
+ <ol>
+ {% for result in results %}
+ <li>
+ <p><a href="{{result.book.get_absolute_url}}">{{result.book.pretty_title}}</a> (id: {{result.book_id}}, score: {{result.score}})</p>
+ <ul>
+ {% for hit in result.hits %}
+ <li>
+ {% if hit.fragment %}
+ <a href="{{hit.fragment.get_absolute_url}}">Idź do fragmentu</a>
+ <div style="">Tagi/Motywy: {% for tag in hit.themes %}{{tag.name}} {% endfor %}</div>
+ {# snippets or short html? #}
+ {% if hit.snippets %}
+ {% for snip in hit.snippets %}
+ {{snip|safe}}<br/>
+ {% endfor %}
+ {% else %}
+ {{hit.fragment.short_text|safe}}
+ {% endif %}
+
+ {% else %}
+ {# it's a section #}
+ <a href="{% url book_text result.book.slug %}#f{{hit.section_number}}">{{hit.header_index}}</a>
+ {% if hit.snippets %}
+ {% for snip in hit.snippets %}
+ {{snip|safe}}<br/>
+ {% endfor %}
+ {% else %}
+ [section matched but no snippets :-(]
+ {% endif %}
+ {% endif %}
+ </li>
+ {% endfor %}
+
+ </ul>
+ </li>
+ {% empty %}
+ <p>No results.</p>
+ {% endfor %}
+ </ol>
+ </div>
+
+
+{% comment %}
<div id="books-list">
<p>{% trans "More than one result matching the criteria found." %}</p>
<ul class='matches'>
{% endfor %}
</ul>
</div>
+{% endcomment %}
- <div id="set-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}
{% load i18n %}
{% load catalogue_tags pagination_tags %}
-{% block title %}{% trans "Search in WolneLektury.pl" %}{% endblock %}
+{% block titleextra %}{% trans "Search" %}{% endblock %}
{% block bodyid %}tagged-object-list{% endblock %}
{% block body %}
- <h1>{% title_from_tags tags %}</h1>
- {% breadcrumbs tags %}
+ <h1>{% trans "Search" %}</h1>
- <div id="books-list">
+ <div class="left-column">
+ <div class="normal-text">
<p>{% trans "Sorry! Search cirteria did not match any resources." %}</p>
<p>{% blocktrans %}Search engine supports following criteria: title, author, theme/topic, epoch, kind and genre.
As for now we do not support full text search.{% endblocktrans %}</p>
{% include "info/join_us.html" %}
</div>
+ </div>
- <div class="column-right block-form">
+ <div class="right-column">
{% include "publishing_suggest.html" %}
</div>
{% endblock %}
{% load i18n %}
{% load catalogue_tags pagination_tags %}
-{% block title %}{% trans "Searching in" %} WolneLektury.pl{% endblock %}
+{% block titleextra %}{% trans "Search" %}{% endblock %}
{% block bodyid %}tagged-object-list{% endblock %}
{% block body %}
- <h1>{% title_from_tags tags %}</h1>
- {% breadcrumbs tags %}
+ <h1>{% trans "Search" %}</h1>
<div id="books-list">
<p>{% trans "Sorry! Search query must have at least two characters." %}</p>
{% include "info/join_us.html" %}
</div>
- <div id="set-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
{% endblock %}
\ No newline at end of file
{% else %}
<ul>
{% for tag in tags %}
- <li><a href="{% catalogue_url choices tag %}">{{ tag }} ({{ tag.count }})</a></li>
+ <li><a href="{% catalogue_url choices tag %}">{{ tag }} ({{ tag.book_count }})</a></li>
{% endfor %}
</ul>
{% endif %}
{% load i18n %}
{% load catalogue_tags pagination_tags switch_tag %}
-{% block title %}{% title_from_tags tags %} w WolneLektury.pl{% endblock %}
+{% block titleextra %}{% title_from_tags tags %}{% endblock %}
{% block bodyid %}tagged-object-list{% endblock %}
{% block body %}
+ <div class="left-column">
+ <div class="page-desc">
<h1>{% title_from_tags tags %}</h1>
- {% breadcrumbs tags %}
- {% if only_shelf and not object_list %}
- <div id="books-list">
- <h2>{% trans "Your shelf is empty" %}</h2>
- <p>{% trans "You can put a book on a shelf by entering page of the reading and clicking 'Put on the shelf'." %}</p>
+ {% with tags|last as last_tag %}
+ {% if last_tag.has_description %}
+ <div id="description">
+ <div id='description-long'>{{ last_tag.description|safe }}</div>
+ <div id='description-short'>{{ last_tag.description|safe|truncatewords_html:30 }}</div>
+ </div>
+ <div class="clearboth"></div>
+ <div id="toggle-description"><p></p></div>
+ {% endif %}
+
+
+ <div class="inline-tag-lists">
+ {% if categories.author %}
+ <p><span class="mono">{% trans "Authors" %}:</span>
+ {% inline_tag_list categories.author tags %}
+ </p>
+ {% endif %}
+ {% if categories.kind %}
+ <p><span class="mono">{% trans "Kinds" %}:</span>
+ {% inline_tag_list categories.kind tags %}
+ </p>
+ {% endif %}
+ {% if categories.genre %}
+ <p><span class="mono">{% trans "Genres" %}:</span>
+ {% inline_tag_list categories.genre tags %}
+ </p>
+ {% endif %}
+ {% if categories.epoch %}
+ <p><span class="mono">{% trans "Epochs" %}:</span>
+ {% inline_tag_list categories.epoch tags %}
+ </p>
+ {% endif %}
</div>
- {% else %}
- {% autopaginate object_list 10 %}
- <div id="books-list">
- {% with tags|last as last_tag %}
- {% if last_tag.has_description %}
- <div id="description">
- <div id='description-long'>{{ last_tag.description|safe }}</div>
- <div id='description-short'>{{ last_tag.description|safe|truncatewords_html:30 }}</div>
- </div>
- <div class="clearboth"></div>
- <div id="toggle-description"><p></p></div>
- {% endif %}
- {% if only_shelf %}
- <a id="download-shelf" href="{% url download_shelf last_tag.slug %}">
- {% trans "Download all books from this shelf" %}
- </a>
- <div id="download-shelf-menu" style="display:none;">
- <form action="{% url download_shelf last_tag.slug %}" method="get" accept-charset="utf-8" id="download-formats-form" data-formats-feed="{% url shelf_book_formats last_tag.slug %}">
- <p>{% trans "Choose books' formats which you want to download:" %}</p>
- <li data-format="pdf"><label for="id_formats_2"><input type="checkbox" name="formats" value="pdf" id="id_formats_2" /> PDF</label> <em><strong>{% trans "for reading" %}</strong> {% trans "and printing using" %} <a href="http://get.adobe.com/reader/">Adobe Reader</a></em></li>
- <li data-format="epub"><label for="id_formats_5"><input type="checkbox" name="formats" value="epub" id="id_formats_5" /> EPUB</label> <em><strong>{% trans "for reading" %}</strong> {% trans "on mobile devices" %}</em></li>
- <li data-format="mobi"><label for="id_formats_7"><input type="checkbox" name="formats" value="mobi" id="id_formats_7" /> MOBI</label> <em><strong>{% trans "for reading" %}</strong> {% trans "on mobile devices" %}</em></li>
- <li data-format="odt"><label for="id_formats_3"><input type="checkbox" name="formats" value="odt" id="id_formats_3" /> ODT</label> <em><strong>{% trans "for reading" %}</strong> {% trans "and editing using" %} <a href="http://pl.openoffice.org/">OpenOffice.org</a></em></li>
- <li data-format="txt"><label for="id_formats_4"><input type="checkbox" name="formats" value="txt" id="id_formats_4" /> TXT</label> <em><strong>{% trans "for reading" %}</strong> {% trans "on small displays, for example mobile phones" %}</em></li>
- <li data-format="mp3"><label for="id_formats_0"><input type="checkbox" name="formats" value="mp3" id="id_formats_0" /> MP3</label> <em><strong>{% trans "for listening" %}</strong> {% trans "on favourite MP3 player" %}</em></li>
- <li data-format="ogg"><label for="id_formats_1"><input type="checkbox" name="formats" value="ogg" id="id_formats_1" /> Ogg Vorbis</label> <em><strong>{% trans "for listening" %}</strong> — {% trans "open format" %} <a href="http://www.vorbis.com/">{% trans "Xiph.org Foundation" %}</a></em></li>
- <li data-format="daisy"><label for="id_formats_6"><input type="checkbox" name="formats" value="daisy" id="id_formats_6" /> DAISY</label> </li>
- <li id="download-formats-form-submit-li"><label><input type="submit" name="submit" value="{% trans "Download" %}" id="download-formats-form-submit" disabled="disabled" /> <img src="{{ STATIC_URL }}img/indicator.gif" /></label> <span id="updating-formats">{% trans "Updating list of books' formats on the shelf" %}</span><span id="formats-updated" style="display:none;">{% trans "or" %} <a href="#" id="download-formats-form-cancel">{% trans "cancel" %}</a></span></li>
- <div class="clearboth"></div>
- </form>
+
+ {% if categories.theme %}
+ <div id="themes-list-wrapper">
+ <p><a href="#" id="themes-list-toggle" class="mono">{% trans "Motifs and themes" %}</a></p>
+ <div id="themes-list">
+ {% tag_list categories.theme tags %}
</div>
- {% if only_my_shelf %}
- <div id="toggle-share-shelf"><p>{% trans "Share this shelf" %}</p></div>
- <div id="share-shelf">
- <p>{% trans "Copy this link and share it with other people to let them see your shelf." %}
- <input id="share-shelf-url" value='http://{{ request.META.HTTP_HOST }}{{ request.path }}' />
- </p>
+ </div>
+ {% endif %}
+
+ </div>
+ </div>
+
+
+ <div class="right-column">
+ <a href="" class="cite">
+ <div class="cite-body">
+ Dobranoc, obróć jeszcze raz na mnie oczęta,<br/>
+ (…) Daj mi pierś ucałować<br/>
+ Dobranoc, zapięta.
</div>
- {% endif %}
- {% endif %}
+ <p class="mono">Adam Mickiewicz, Dziady część III</p>
+ </a>
+
+ <div class="see-also">
+ <h2 class='mono'>{% trans "See also" %}:</h2>
+ <ul>
+ <li><a href="">Wiki</a></li>
+ <li><a href="">Gazeta</a></li>
+ </ul>
+ </div>
+
+ <div class="download">
+ <h2 class='mono'>{% trans "Download" %}:</h2>
+ <ul>
+ <li><a href="">wszystko</a></li>
+ <li><a href="">część</a></li>
+ </ul>
+ </div>
+
+ </div>
+
+ <div class="clearboth"></div>
+
+
+
+
+ {% autopaginate object_list 10 %}
+ <div id="books-list">
+
+
{% if last_tag.gazeta_link %}
<p><a href="{{ last_tag.gazeta_link }}">
{% switch last_tag.category %}
{% endif %}
{% if object_list %}
- <ol>
+ {% spaceless %}
+ <ol class='work-list'>
{% for book in object_list %}
- <li>
+ <li class='work-item'>
{% if user_is_owner %}
<a href="{% url remove_from_shelf last_tag.slug book.slug %}" class="remove-from-shelf">{% trans "Delete" %}</a>
{% endif %}
{{ book.short_html }}</li>
{% endfor %}
</ol>
+ {% endspaceless %}
{% paginate %}
{% else %}
{% trans "Sorry! Search cirteria did not match any resources." %}
</div>
{% if object_list %}
{% comment %} If we didn't find anything there will be nothing on the right side as well {% endcomment %}
- <div id="tags-list">
- <div id="categories-list">
- {% if categories.author %}
- <h2>{% trans "Authors" %}</h2>
- {% tag_list categories.author tags %}
- {% endif %}
- {% if categories.kind %}
- <h2>{% trans "Kinds" %}</h2>
- {% tag_list categories.kind tags %}
- {% endif %}
- {% if categories.genre %}
- <h2>{% trans "Genres" %}</h2>
- {% tag_list categories.genre tags %}
- {% endif %}
- {% if categories.epoch %}
- <h2>{% trans "Epochs" %}</h2>
- {% tag_list categories.epoch tags %}
- {% endif %}
- {% if only_shelf %}
- <p><a href="{% url poem_from_set tags.0.slug %}">Miksuj utwory z tej półki</a>
- {% endif %}
- </div>
- <div id="themes-list">
- {% if categories.theme %}
- <h2>{% trans "Themes" %}</h2>
- {% tag_list categories.theme tags %}
- {% endif %}
- </div>
- <div class="clearboth"></div>
- </div>
{% endif %}
- {% endif %}
- <div id="set-window">
- <div class="header"><a href="#" class="jqmClose">{% trans "Close" %}</a></div>
- <div class="target">
- <p><img src="{{ STATIC_URL }}img/indicator.gif" alt="*"/> {% trans "Loading" %}</p>
- </div>
- </div>
{% endblock %}
{% if shelves %}
<ul class="shelf-list">
{% for shelf in shelves %}
- <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">{% trans "remove" %}</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.get_count }})</a></li>
+ <li><a href="{% url delete_shelf shelf.slug %}" class="delete-shelf">{% trans "remove" %}</a> <a href="{{ shelf.get_absolute_url }}" class="visit-shelf">{{ shelf.name }} ({{ shelf.book_count }})</a></li>
{% endfor %}
</ul>
{% else %}
+++ /dev/null
-{% extends "base.html" %}
-{% load i18n %}
-{% load chunks %}
-
-{% block title %}{{ object.page_title }}{% endblock %}
-
-{% block metadescription %}{{ object.left_column|striptags|truncatewords:10 }}{% endblock %}
-
-{% block body %}
- <h1>{{ object.title }}</h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{%trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to the main page" %}</a></p>
- </form>
-
- {% autoescape off %}
- <div class="column-left">
- {{ object.left_column }}
- </div>
- <div class="column-right">
- {{ object.right_column }}
- </div>
- {% endautoescape %}
-{% endblock %}
{% load i18n %}
{% load reporting_stats %}
-{% count_books_nonempty book_count %}
+{% count_books book_count %}
<p>
{% blocktrans count book_count as c %}
We have {{c}} work published in Wolne Lektury!
<p>{% blocktrans %}Become an editor of Wolne Lektury! Find out if
we're currently working on a reading you're looking for and prepare
a publication by yourself by logging into the Editorial Platform.{% endblocktrans %}
-<a href='{% url help_us %}'>{% trans "More..." %}</a></p>
+<a href='{% url infopage 'mozesz-nam-pomoc' %}'>{% trans "More..." %}</a></p>
{% load i18n %}
{% load catalogue_tags %}
-{% block title %}Leśmianator w WolneLektury.pl{% endblock %}
+{% block titleextra %}Leśmianator{% endblock %}
{% block metadescription %}Stwórz własny wierszmiks z utworów znajdujących się na Wolnych Lekturach.{% endblock %}
{% block body %}
<h1>Leśmianator</h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
- <div id="books-list">
+ <div class="left-column">
+ <div class="normal-text">
<p>Leśmianator tworzy wierszmiksy – dzięki niemu
<a href="{% url new_poem %}">napiszesz wiersz jednym kliknięciem</a>.
W nowej odsłonie nowe możliwości zabawy – teraz możesz zdecydować, co wrzucasz do miksera,
{% endfor %}
</div>
+ </div>
- <div id="tags-list">
+ <div class="right-column">
+ <div class="normal-text">
<h3>Miksuj utwory</h3>
<p>Możesz <a href="{% url new_poem %}">zmiksować całą lirykę</a> w naszej bibliotece
albo tylko jeden konkretny utwór. Jak? Wejdź na
<p>Miłej zabawy!</p>
</div>
+ </div>
{% endblock %}
\ No newline at end of file
{% block bodyid %}document-list-body{% endblock %}
-{% block title %}{% trans "Hand-outs for teachers on " %}WolneLektury.pl{% endblock %}
+{% block titleextra %}{% trans "Hand-outs for teachers" %}{% endblock %}
{% block metadescription %}Scenariusze lekcji. Materiały dla nauczycieli na wolnej licencji.{% endblock %}
{% endblock extrahead %}
{% block body %}
<h1>{% trans "Hand-outs for teachers" %}</h1>
- <form action="{% url search %}" method="GET" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
+
<div id="document-list">
{% chunk "document-list" %}
</div>
--- /dev/null
+{% extends "base.html" %}
+{% load cache i18n catalogue_tags infopages_tags %}
+
+
+{% block title %}{% trans "Wolne Lektury internet library" %}{% endblock %}
+
+{% block body %}
+
+ <blockquote id="big-cite">
+ <a href='http://google.com'>
+ <h2 class="mono">Jarosław Lipszyc poleca:</h2>
+ <p id="big-cite-text">Dobranoc, obróć jeszcze raz na mnie oczęta,<br/>
+ (…) Daj mi pierś ucałować<br/>
+ Dobranoc, zapięta.</p>
+ <p class="mono" id="big-cite-source">Adam Mickiewicz, Dziady część III</p>
+ </a>
+ </blockquote>
+
+
+ {% spaceless %}
+
+
+ <div id="promo-box">
+ <div class="grid-line" id="promo-box-header">
+ <h2 class="mono">Trwa konkurs</h2>
+ </div>
+ <div id="promo-box-body" class="accent4">
+ <p id="promo-box-title" class="mono"><span>Konkurs poezji automatycznej</span></p>
+ <div id="promo-box-content">
+ <p>Znacie Leśmianatora? To niewielki skrypt miskujący na życzenie
+ wiersze z Wolnych Lektur.</p>
+ </div>
+ </div>
+ </div>
+
+
+ <h2 class="main-last"><span class="mono">Ostatnie publikacje</span></h2>
+ {% for book in last_published %}
+ {{ book.mini_box }}
+ {% endfor %}
+
+ <div class="clearboth"></div>
+
+ <div class="infopages-box">
+ <h2><span class='mono'>Aktualności</span></h2>
+ {% cache 1800 latest-blog-posts %}
+ {% latest_blog_posts "http://nowoczesnapolska.org.pl/category/wolne-lektury/feed/" %}
+ {% endcache %}
+ </div>
+
+
+ <div class="infopages-box">
+ <h2><span class='mono'>Narzędzia</span></h2>
+
+ <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 lesmianator %}">Leśmianator</a></li>
+ <li><a href="{% url infopage "mobilna" %}">{% trans "Mobile app" %}</a></li>
+ <li><a href="{% url infopage "widget" %}">{% trans "Widget" %}</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>
+ </ul>
+ </div>
+
+
+ <div class="infopages-box">
+ <h2><span class='mono'>Informacje</span></h2>
+
+ {% infopages_on_main %}
+
+ <div class="social-links">
+ <a href="http://pl-pl.facebook.com/pages/Wolne-Lektury/203084073268"><img src="{{ STATIC_URL }}img/social/facebook.png" alt="WolneLektury @ Facebook" /></a>
+ <a href="http://nk.pl/profile/30441509"><img src="{{ STATIC_URL }}img/social/naszaklasa.png" alt="WolneLektury @ NK" /></a>
+ </div>
+ </div>
+
+
+ {% endspaceless %}
+
+{% endblock %}
--- /dev/null
+{% extends "base.html" %}
+{% load i18n %}
+{% load catalogue_tags %}
+
+{% block title %}Search{% endblock %}
+
+{% block metadescription %}{% endblock %}
+
+{% block bodyid %}newsearch{% endblock %}
+
+{% block body %}
+ <h1>Search</h1>
+ <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form-x">
+ <p>
+ <input type="text" name="q" value="{{request.GET.q}}" style="width:250px; font-size: 1.2em;">
+ <input type="submit" value="{% trans "Search" %}" />
+ <br />
+ <input type="checkbox" value="true" name="fuzzy" {% if fuzzy %}checked{% endif %}/> fuzzy.
+ </p>
+ </form>
+ {% if did_you_mean %}
+ Czy miałeś na mysli <a href="?q={{did_you_mean|urlencode}}">{{did_you_mean}}</a>?
+ {% endif %}
+
+
+ <div id="results">
+ <ol>
+ {% for result in results %}
+ <li>
+ <p><a href="{{result.book.get_absolute_url}}">{{result.book.pretty_title}}</a> (id: {{result.book_id}}, score: {{result.score}})</p>
+ <ul>
+ {% for hit in result.hits %}
+ <li>
+ {% for snip in hit.3.snippets %}
+ {{snip|safe}}<br/>
+ {% endfor %}
+ </li>
+ {% endfor %}
+
+ {% for part in result.parts %}
+ {% if part.header %}
+ <li>W {{part.header}} nr {{part.position}}</li>
+ {% else %}
+ {% if part.fragment %}
+ <li>
+ <div style="">Tagi/Motywy: {% for tag in part.fragment.tags %}{{tag.name}} {% endfor %}</div>
+ {{part.fragment.short_html|safe}}
+ </li>
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ </ul>
+ </li>
+ {% empty %}
+ <p>No results.</p>
+ {% endfor %}
+ </ol>
+ </div>
+
+{% endblock %}
{% extends "base.html" %}
{% load i18n %}
-{% block title %}{{ author.name }} w WolneLektury.pl{% endblock %}
+{% block titleextra %}{{ author.name }}{% endblock %}
{% block metadescription %}Licznik domeny publicznej: {{author.name}}.{% endblock %}
{% block body %}
<h1>{{ author.name }}</h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
<div id="books-list">
{% if author.has_description %}
{% else %}
<div>
<p>{% trans "This author's works will become part of public domain and will be allowed to be published without restrictions in" %}</p>
- {% include "pdcounter/pd_counter.html" %}
+ <div id='countdown' data-year='{{ pd_counter }}'></div>
<p>{% trans "<a href='http://domenapubliczna.org/co-to-jest-domena-publiczna/'>Find out</a> why Internet libraries can't publish this author's works." %}</p>
</div>
{% endif %}
{% extends "base.html" %}
{% load i18n %}
-{% block title %}{{ book.title }} w WolneLektury.pl{% endblock %}
+{% block titleextra %}{{ book.title }}{% endblock %}
{% block metadescription %}Licznik domeny publicznej: {{ book.title }}.{% endblock %}
{% block body %}
<h1>{{ book.author }}, {{ book.title }}</h1>
- <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
- <p>{{ form.q }} <input type="submit" value="{% trans "Search" %}" /> <strong>{% trans "or" %}</strong> <a href="{% url main_page %}">{% trans "return to main page" %}</a></p>
- </form>
<div id="books-list">
{% if book.in_pd %}
{% else %}
{% if book.pd %}
<p>{% trans "This work will become part of public domain and will be allowed to be published without restrictions in" %}</p>
- {% include "pdcounter/pd_counter.html" %}
+ <div id='countdown' data-year='{{ pd_counter }}'></div>
<p>{% trans "<a href='http://domenapubliczna.org/co-to-jest-domena-publiczna/'>Find out</a> why Internet libraries can't publish this work." %}</p>
{% else %}
<p>{% trans "This work is copyrighted." %}
+++ /dev/null
-<div id='countdown'></div>
-<script>
-{% if LANGUAGE_CODE != 'en' %}
- $.countdown.setDefaults($.countdown.regional['{{ LANGUAGE_CODE }}']);
-{% else %}
- $.countdown.setDefaults($.countdown.regional['']);
-{% endif %}
-d = new Date({{ pd_counter }}, 0, 1);
-function re() {location.reload()};
-$('#countdown').countdown({until: d, format: 'ydHMS', serverSync: serverTime,
-onExpiry: re, alwaysExpire: true});
-</script>
--- /dev/null
+{% load i18n %}
+{% load thumbnail %}
+<div class="picture-box">
+<div class="picture-box-inner">
+ <a href="{{ picture.get_absolute_url }}">
+ {% thumbnail picture.image_file "216x288" as thumb %}
+ <img src="{{thumb.url}}"/>
+ {% endthumbnail %}
+ </a>
+ <div class="picture-box-body">
+ <div class="picture-box-head">
+ <div class="mono author">
+ {% for author in tags.author %}
+ {{ author }}
+ {% endfor %}
+ </div>
+ <div class="title">{{ picture.title }}</div>
+ </div>
+ <div class="tags">
+ {% spaceless %}
+
+ <span class="mono">{% trans "Epoch" %}: </span>
+ <span class="picture-box-tag">
+ {% for tag in tags.epoch %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag.name }} </a>
+ {% endfor %}
+ </span>
+
+ <span class="mono">{% trans "Kind" %}: </span>
+ <span class="picture-box-tag">
+ {% for tag in tags.kind %}
+ <a href="{{ tag.get_absolute_url }}">{{ tag.name }} </a>
+ {% endfor %}
+ </span>
+
+ {% endspaceless %}
+ </div>
+ </div>
+ <ul class="picture-box-tools">
+ </ul>
+</div>
+</div>
--- /dev/null
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block titleextra %}{% trans "Publishing plan" %}{% endblock titleextra %}
+
+
+{% block body %}
+<h1>{% trans "Publishing plan" %}</h1>
+
+<ul class="normal-text">
+{% for elem in plan %}
+ <li><a href="{{ elem.link }}">{{ elem.title }}</a></li>
+{% endfor %}
+</ul>
+
+{% endblock %}
from infopages.models import InfoPage
class InfoPageTranslationOptions(TranslationOptions):
- fields = ('page_title', 'title', 'left_column', 'right_column')
+ fields = ('title', 'left_column', 'right_column')
translator.register(InfoPage, InfoPageTranslationOptions)
from django.conf.urls.defaults import *
from django.conf import settings
from django.contrib import admin
+import views
-from catalogue.forms import SearchForm
-from infopages.models import InfoPage
+admin.autodiscover()
+urlpatterns = patterns('wolnelektury.views',
+ url(r'^$', 'main_page', name='main_page'),
+ url(r'^planowane/$', 'publish_plan', name='publish_plan'),
-admin.autodiscover()
+ url(r'^zegar/$', 'clock', name='clock'),
+
+ # Authentication
+ url(r'^uzytkownicy/zaloguj/$', views.LoginFormView(), name='login'),
+ url(r'^uzytkownicy/utworz/$', views.RegisterFormView(), name='register'),
+ url(r'^uzytkownicy/wyloguj/$', 'logout_then_redirect', name='logout'),
+)
-urlpatterns = patterns('',
+urlpatterns += patterns('',
url(r'^katalog/', include('catalogue.urls')),
url(r'^materialy/', include('lessons.urls')),
url(r'^opds/', include('opds.urls')),
url(r'^lesmianator/', include('lesmianator.urls')),
url(r'^przypisy/', include('dictionary.urls')),
url(r'^raporty/', include('reporting.urls')),
-
- # Static pages
- url(r'^mozesz-nam-pomoc/$', 'infopages.views.infopage', {'slug': 'help_us'}, name='help_us'),
- url(r'^o-projekcie/$', 'infopages.views.infopage', {'slug': 'about_us'}, name='about_us'),
- url(r'^widget/$', 'infopages.views.infopage', {'slug': 'widget'}, name='widget'),
+ url(r'^info/', include('infopages.urls')),
# Admin panel
url(r'^admin/catalogue/book/import$', 'catalogue.views.import_book', name='import_book'),
+ url(r'^admin/catalogue/picture/import$', 'picture.views.import_picture', name='import_picture'),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
- # Authentication
- url(r'^uzytkownicy/zaloguj/$', 'catalogue.views.login', name='login'),
- url(r'^uzytkownicy/wyloguj/$', 'catalogue.views.logout_then_redirect', name='logout'),
- url(r'^uzytkownicy/utworz/$', 'catalogue.views.register', name='register'),
- url(r'^uzytkownicy/login/$', 'django.contrib.auth.views.login', name='simple_login'),
-
# API
(r'^api/', include('api.urls')),
+ url(r'^fullsearch/', include('search.urls')),
+
# Static files
url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'^%s(?P<path>.*)$' % settings.STATIC_URL[1:], 'django.views.static.serve',
{'document_root': settings.STATIC_ROOT, 'show_indexes': True}),
- url(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'katalog/',
- 'permanent': False}),
url(r'^i18n/', include('django.conf.urls.i18n')),
)
urlpatterns += patterns('django.views.generic.simple',
# old static pages - redirected
- (r'^1procent/$', 'redirect_to', {'url': 'http://nowoczesnapolska.org.pl/wesprzyj_nas/'}),
- (r'^wolontariat/$', 'redirect_to', {'url': '/mozesz-nam-pomoc/'}),
- (r'^epub/$', 'redirect_to', {'url': '/katalog/lektury/'}),
+ url(r'^1procent/$', 'redirect_to',
+ {'url': 'http://nowoczesnapolska.org.pl/wesprzyj_nas/'}),
+ url(r'^epub/$', 'redirect_to',
+ {'url': '/katalog/lektury/'}),
+ url(r'^mozesz-nam-pomoc/$', 'redirect_to',
+ {'url': '/info/mozesz-nam-pomoc'}),
+ url(r'^o-projekcie/$', 'redirect_to',
+ {'url': '/info/o-projekcie'}),
+ url(r'^widget/$', 'redirect_to',
+ {'url': '/info/widget'}),
+ url(r'^wolontariat/$', 'redirect_to',
+ {'url': '/info/mozesz-nam-pomoc/'}),
)
--- /dev/null
+from datetime import datetime
+import feedparser
+
+from django.contrib import auth
+from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
+from django.core.cache import cache
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+from django.utils.http import urlquote_plus
+from django.utils.translation import ugettext_lazy as _
+from django.views.decorators.cache import never_cache
+
+from django.conf import settings
+from ajaxable.utils import AjaxableFormView
+from catalogue.models import Book
+
+
+def main_page(request):
+ last_published = Book.objects.exclude(html_file='').order_by('-created_at')[:4]
+
+ return render_to_response("main_page.html", locals(),
+ context_instance=RequestContext(request))
+
+
+class LoginFormView(AjaxableFormView):
+ form_class = AuthenticationForm
+ title = _('Sign in')
+ submit = _('Sign in')
+ ajax_redirect = True
+
+ def __call__(self, request):
+ if request.user.is_authenticated():
+ return HttpResponseRedirect('/')
+ return super(LoginFormView, self).__call__(request)
+
+ def success(self, form, request):
+ auth.login(request, form.get_user())
+
+
+class RegisterFormView(AjaxableFormView):
+ form_class = UserCreationForm
+ title = _('Register')
+ submit = _('Register')
+ ajax_redirect = True
+
+ def __call__(self, request):
+ if request.user.is_authenticated():
+ return HttpResponseRedirect('/')
+ return super(RegisterFormView, self).__call__(request)
+
+ def success(self, form, request):
+ user = form.save()
+ user = auth.authenticate(
+ username=form.cleaned_data['username'],
+ password=form.cleaned_data['password1']
+ )
+ auth.login(request, user)
+
+
+@never_cache
+def logout_then_redirect(request):
+ auth.logout(request)
+ return HttpResponseRedirect(urlquote_plus(request.GET.get('next', '/'), safe='/?='))
+
+
+def clock(request):
+ """ Provides server time for jquery.countdown,
+ in a format suitable for Date.parse()
+ """
+ return HttpResponse(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
+
+
+def publish_plan(request):
+ cache_key = "publish_plan"
+ plan = cache.get(cache_key)
+
+ if plan is None:
+ plan = []
+ try:
+ feed = feedparser.parse(settings.PUBLISH_PLAN_FEED)
+ except:
+ pass
+ else:
+ for i in range(len(feed['entries'])):
+ print i
+ plan.append({
+ 'title': feed['entries'][i].title,
+ 'link': feed['entries'][i].link,
+ })
+ cache.set(cache_key, plan, 1800)
+
+ return render_to_response("publish_plan.html", {'plan': plan},
+ context_instance=RequestContext(request))