Merged with branch 1.0.
authorzuber@web50.webfaction.com <zuber@web50.webfaction.com>
Mon, 20 Oct 2008 14:18:18 +0000 (09:18 -0500)
committerzuber@web50.webfaction.com <zuber@web50.webfaction.com>
Mon, 20 Oct 2008 14:18:18 +0000 (09:18 -0500)
16 files changed:
.hgtags
apps/catalogue/fields.py
apps/catalogue/migrations/0002_add_extra_info_to_book.py [new file with mode: 0644]
apps/catalogue/models.py
apps/catalogue/urls.py
apps/catalogue/views.py
books/01/zapolska_moralnosc_pani_dulskiej1.2.xml
lib/librarian/book2html.xslt
lib/librarian/dcparser.py
lib/librarian/html.py
migrations/001_add_book_count_to_shelf.py [deleted file]
wolnelektury/deploy/wolnelektury.fcgi
wolnelektury/templates/base.html
wolnelektury/templates/catalogue/book_detail.html
wolnelektury/templates/catalogue/book_fragments.html [new file with mode: 0644]
wolnelektury/templates/catalogue/book_text.html

diff --git a/.hgtags b/.hgtags
index e32cfc6..0edbce6 100644 (file)
--- a/.hgtags
+++ b/.hgtags
@@ -1,7 +1 @@
-57ed361b5c5cea4c3fc6d4ea1d8c2a9addb087e2 wolnelektury-0.9
-5f1b5a4c1444518b6b4d151a9a20baf061b77179 wolnelektury-0.9
-4da7f67e38ed4599d3925c92a7fab8f61467bfc3 wolnelektury-0.9
-fed64f1e09c1859829839fe8c09dc1c2848389a4 wolnelektury-0.9.1
-5eee4534e79b9102c6e7c579cc2a6c8d74de9c05 wolnelektury-0.9.2
-293052c8f613021de21e6d036e48652f4a414b35 wolnelektury-0.9.3
-13036b75ecc3711e9270342fc8d7cd41d2676d6b wolnelektury-0.9.4
+fa4bcbf759901d7444c98e3f0a3a9aa7da1b8a1b wolnelektury-1.0
index e1a356e..d091b77 100644 (file)
@@ -1,10 +1,66 @@
 # -*- coding: utf-8 -*-
+import datetime
+
+from django.conf import settings
+from django.db import models
+from django.db.models import signals
 from django import forms
 from django.forms.widgets import flatatt
 from django.forms.util import smart_unicode
+from django.utils import simplejson as json
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
-from django.utils.simplejson import dumps
+
+
+class JSONEncoder(json.JSONEncoder):
+    def default(self, obj):
+        if isinstance(obj, datetime.datetime):
+            return obj.strftime('%Y-%m-%d %H:%M:%S')
+        elif isinstance(obj, datetime.date):
+            return obj.strftime('%Y-%m-%d')
+        elif isinstance(obj, datetime.time):
+            return obj.strftime('%H:%M:%S')
+        return json.JSONEncoder.default(self, obj)
+
+
+def dumps(data):
+    return JSONEncoder().encode(data)
+
+
+def loads(str):
+    return json.loads(str, encoding=settings.DEFAULT_CHARSET)
+
+
+class JSONField(models.TextField):
+    def db_type(self):
+        return 'text'
+    
+    def get_internal_type(self):
+        return 'TextField'
+
+    def pre_save(self, model_instance, add):
+        value = getattr(model_instance, self.attname, None)
+        return dumps(value)
+
+    def contribute_to_class(self, cls, name):
+        super(JSONField, self).contribute_to_class(cls, name)
+        signals.post_init.connect(self.post_init, sender=cls)
+
+        def get_json(model_instance):
+            return dumps(getattr(model_instance, self.attname, None))
+        setattr(cls, 'get_%s_json' % self.name, get_json)
+
+        def set_json(model_instance, json):
+            return setattr(model_instance, self.attname, loads(json))
+        setattr(cls, 'set_%s_json' % self.name, set_json)
+
+    def post_init(self, **kwargs):
+        instance = kwargs.get('instance', None)
+        value = self.value_from_object(instance)
+        if (value):
+            setattr(instance, self.attname, loads(value))
+        else:
+            setattr(instance, self.attname, None)
 
 
 class JQueryAutoCompleteWidget(forms.TextInput):
@@ -32,7 +88,7 @@ class JQueryAutoCompleteWidget(forms.TextInput):
             final_attrs['id'] = 'id_%s' % name
         
         html = u'''<input type="text" %(attrs)s/>
-            <script type="text/javascript"><!--//
+            <script type="text/javascript">//<!--
             %(js)s//--></script>
             ''' % {
                 'attrs' : flatatt(final_attrs),
diff --git a/apps/catalogue/migrations/0002_add_extra_info_to_book.py b/apps/catalogue/migrations/0002_add_extra_info_to_book.py
new file mode 100644 (file)
index 0000000..145d711
--- /dev/null
@@ -0,0 +1,11 @@
+from south.db import db
+from catalogue.fields import JSONField
+
+class Migration:
+    
+    def forwards(self):
+        db.add_column('catalogue_book', 'extra_info', JSONField())
+    
+    def backwards(self):
+        db.delete_column('catalogue_book', 'extra_info')
+
index 60d2785..483fdda 100644 (file)
@@ -10,6 +10,7 @@ from django.core.urlresolvers import reverse
 
 from newtagging.models import TagBase
 from newtagging import managers
+from catalogue.fields import JSONField
 
 from librarian import html, dcparser
 
@@ -21,6 +22,7 @@ TAG_CATEGORIES = (
     ('genre', _('genre')),
     ('theme', _('theme')),
     ('set', _('set')),
+    ('book', _('book')),
 )
 
 
@@ -41,7 +43,7 @@ class Tag(TagBase):
         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'), default=0, blank=False, null=False)
     
@@ -84,6 +86,7 @@ class Book(models.Model):
     created_at = models.DateTimeField(_('creation date'), auto_now=True)
     _short_html = models.TextField(_('short HTML'), editable=False)
     parent_number = models.IntegerField(_('parent number'), default=0)
+    extra_info = JSONField(_('extra information'))
     
     # Formats
     xml_file = models.FileField(_('XML file'), upload_to=book_upload_path('xml'), blank=True)
@@ -97,6 +100,7 @@ class Book(models.Model):
     objects = models.Manager()
     tagged = managers.ModelTaggedItemManager(Tag)
     tags = managers.TagDescriptor(Tag)
+
     
     @property
     def name(self):
@@ -106,7 +110,7 @@ class Book(models.Model):
         if len(self._short_html):
             return mark_safe(self._short_html)
         else:
-            tags = self.tags.filter(~Q(category__in=('set', 'theme')))
+            tags = self.tags.filter(~Q(category__in=('set', 'theme', 'book')))
             tags = [u'<a href="%s">%s</a>' % (tag.get_absolute_url(), tag.name) for tag in tags]
 
             formats = []
@@ -167,6 +171,7 @@ class Book(models.Model):
             book_shelves = list(book.tags.filter(category='set'))
         
         book.title = book_info.title
+        book.extra_info = book_info.to_dict()
         book._short_html = ''
         book.save()
         
@@ -184,6 +189,15 @@ class Book(models.Model):
                 tag.category = category
                 tag.save()
             book_tags.append(tag)
+            
+        book_tag, created = Tag.objects.get_or_create(slug=('l-' + book.slug)[:120])
+        if created:
+            book_tag.name = book.title[:50]
+            book_tag.sort_key = ('l-' + book.slug)[:120]
+            book_tag.category = 'book'
+            book_tag.save()
+        book_tags.append(book_tag)
+        
         book.tags = book_tags
         
         if hasattr(book_info, 'parts'):
@@ -193,7 +207,14 @@ class Book(models.Model):
                 child_book.parent = book
                 child_book.parent_number = n
                 child_book.save()
-        
+
+        book_descendants = list(book.children.all())
+        while len(book_descendants) > 0:
+            child_book = book_descendants.pop(0)
+            for fragment in child_book.fragments.all():
+                fragment.tags = set(list(fragment.tags) + [book_tag])
+            book_descendants += list(child_book.children.all())
+            
         # Save XML and HTML files
         book.xml_file.save('%s.xml' % book.slug, File(file(xml_file)), save=False)
         
@@ -226,7 +247,7 @@ class Book(models.Model):
                         tag.save()
                     themes.append(tag)
                 new_fragment.save()
-                new_fragment.tags = list(book.tags) + themes
+                new_fragment.tags = set(list(book.tags) + themes + [book_tag])
                 book_themes += themes
             
             book_themes = set(book_themes)
index b24212e..dc8cc9b 100644 (file)
@@ -17,6 +17,8 @@ urlpatterns = patterns('catalogue.views',
     # 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'),
 )
 
index c9d6ab2..1718d97 100644 (file)
@@ -67,6 +67,9 @@ def tagged_object_list(request, tags=''):
     except models.Tag.DoesNotExist:
         raise Http404
     
+    if len([tag for tag in tags if tag.category == 'book']):
+        raise Http404
+    
     model = models.Book
     shelf = [tag for tag in tags if tag.category == 'set']
     shelf_is_set = (len(tags) == 1 and tags[0].category == 'set')
@@ -76,7 +79,7 @@ def tagged_object_list(request, tags=''):
 
     user_is_owner = (len(shelf) and request.user.is_authenticated() and request.user == shelf[0].user)
     
-    extra_where = 'NOT catalogue_tag.category = "set"'
+    extra_where = 'catalogue_tag.category NOT IN ("set", "book")'
     related_tags = models.Tag.objects.related_for_model(tags, model, counts=True, extra={'where': [extra_where]})
     categories = split_tags(related_tags)
 
@@ -93,11 +96,25 @@ def tagged_object_list(request, tags=''):
     )
 
 
+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)
+    theme = get_object_or_404(models.Tag, slug=theme_slug)
+    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))
+
+
 def book_detail(request, slug):
     book = get_object_or_404(models.Book, slug=slug)
+    book_tag = get_object_or_404(models.Tag, slug = 'l-' + slug)
     tags = list(book.tags.filter(~Q(category='set')))
     categories = split_tags(tags)
     book_children = book.children.all().order_by('parent_number')
+    extra_where = 'catalogue_tag.category = "theme"'
+    book_themes = models.Tag.objects.related_for_model(book_tag, models.Fragment, counts=True, extra={'where': [extra_where]})
     
     form = forms.SearchForm()
     return render_to_response('catalogue/book_detail.html', locals(),
@@ -124,9 +141,9 @@ def _tags_starting_with(prefix, user):
     books = models.Book.objects.filter(title__icontains=prefix)
     tags = models.Tag.objects.filter(name__icontains=prefix)
     if user.is_authenticated():
-        tags = tags.filter(~Q(category='set') | Q(user=user))
+        tags = tags.filter(~Q(category='book') & (~Q(category='set') | Q(user=user)))
     else:
-        tags = tags.filter(~Q(category='set'))
+        tags = tags.filter(~Q(category='book') & ~Q(category='set'))
 
     return list(books) + list(tags)
         
@@ -157,7 +174,7 @@ def search(request):
 
 
 def tags_starting_with(request):
-    prefix = request.GET['q']
+    prefix = request.GET.get('q', '')
     # Prefix must have at least 2 characters
     if len(prefix) < 2:
         return HttpResponse('')
index 1fcc337..b64ec7a 100644 (file)
@@ -1,4 +1,32 @@
 <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/Lektury:Zapolska/Moralność_pani_Dulskiej">
+    <dc:creator xml:lang="pl">Zapolska, Gabriela</dc:creator>
+    <dc:title xml:lang="pl">Moralność pani Dulskiej</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">Modernizm</dc:subject.period>
+    <dc:subject.type xml:lang="pl">Dramat</dc:subject.type>
+    <dc:subject.genre xml:lang="pl">Tragifarsa</dc:subject.genre>
+    <dc:subject.genre xml:lang="pl">Komedia</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/moralnosc-pani-dulskiej</dc:identifier.url>
+    <dc:source.URL xml:lang="pl">http://www.polona.pl/dlibra/doccontent2?id=582&amp;from=&amp;from=generalsearch&amp;dirids=1&amp;lang=pl</dc:source.URL>
+    <dc:source xml:lang="pl">Zapolska, Gabriela (1857-1921), Moralność pani Dulskiej: komedya w trzech aktach, Tow. Akc. S. Orgelbranda S-ów, Warszawa, 1907</dc:source>
+    <dc:rights xml:lang="pl">Domena publiczna - Gabriela Zapolska, herbu Korwin, właśc. Maria Gabriela Korwin-Piotro, zm. 17 grudnia 1921</dc:rights>
+    <dc:date.pd xml:lang="pl">1921</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">2007-11-10</dc:date>
+    <dc:audience xml:lang="pl">G</dc:audience>
+    <dc:audience xml:lang="pl">L</dc:audience>
+    <dc:language xml:lang="pl">pol</dc:language>
+    </rdf:Description>
+    </rdf:RDF>
+
 <dramat_wspolczesny>
 
 
index d5e21cf..71f1182 100644 (file)
@@ -5,18 +5,17 @@
 
 
 <xsl:template match="utwor">
-    <html>
+    <!-- <html>
         <head>
             <title>Książka z serwisu WolneLektury.pl</title>
             <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
         </head>
         <style>
             body {
-                font-size: 14px;
+                font-size: 16px;
                 font: Georgia, "Times New Roman", serif;
                 line-height: 1.5em;
-                margin: 3em;
-                max-width: 36em;
+                margin: 0;
             }
 
             a {
                 text-decoration: none;
             }
 
+            #book-text {
+                margin: 3em;
+                max-width: 36em;
+            }
+
+            /* ================================== */
+            /* = Header with logo and menu      = */
+            /* ================================== */
+            #header {
+                margin: 3.4em 0 0 1.4em;
+            }
+
+            img {
+                border: none;
+            }
+
+
+            #menu {
+                position: fixed;
+                left: 0em;
+                top: 0em;
+                width: 100%;
+                height: 1.5em;
+                background: #333;
+                color: #FFF;
+                opacity: 0.9;
+            }
+
+            #menu ul {
+                list-style: none;
+                padding: 0;
+                margin: 0;
+            }
+
+            #menu li a {
+                display: block;
+                float: left;
+                width: 7.5em;
+                height: 1.5em;
+                margin-left: 0.5em;
+                text-align: center;
+                color: #FFF;
+            }
+
+            #menu li a:hover, #menu li a:active {
+                color: #000;
+                background: #FFF url(/media/img/arrow-down.png) no-repeat center right;
+            }
+
+            #menu li a.selected {
+                color: #000;
+                background: #FFF url(/media/img/arrow-up.png) no-repeat center right;
+            }
+
+            #toc, #themes {
+                position: fixed;
+                left: 0em;
+                top: 1.5em;
+                width: 37em;
+                padding: 1.5em;
+                background: #FFF;
+                border-bottom: 0.25em solid #DDD;
+                border-right: 0.25em solid #DDD;
+                display: none;
+                height: 16em;
+                overflow-x: hidden;
+                overflow-y: auto;
+                opacity: 0.9;
+            }
+
+            #toc ol, #themes ol {
+                list-style: none;
+                padding: 0;
+                margin: 0;
+            }
+
+            #toc ol li {
+                font-weight: bold;
+            }
+
+            #toc ol ol {
+                padding: 0 0 1.5em 1.5em;
+                margin: 0;
+            }
+
+            #toc ol ol li {
+                font-weight: normal;
+            }
+
+            #toc h2 {
+                display: none;
+            }
+
+            #toc .anchor {
+                float: none;
+                margin: 0;
+                color: blue;
+                font-size: 16px;
+                position: inherit;
+            }
+
             /* =================================================== */
             /* = Common elements: headings, paragraphs and lines = */
             /* =================================================== */
                 font-size: 0.875em;
             }
 
+            /* ============= */
+            /* = Numbering = */
+            /* ============= */
+            .anchor {
+                position: absolute;
+                margin: -0.25em -0.5em;
+                left: 1em;
+                color: #777;
+                font-size: 12px;
+                width: 2em;
+                text-align: center;
+                padding: 0.25em 0.5em;
+                line-height: 1.5em;
+            }
+
+            .anchor:hover, #book-text .anchor:active {
+                color: #FFF;
+                background-color: #CCC;
+            }
+
             /* =================== */
             /* = Custom elements = */
             /* =================== */
 
             div.didaskalia {
                 font-style: italic;
-                margin: 0.5em 0 0;
+                margin: 0.5em 0 0 1.5em;
             }
 
             div.kwestia {
 
             p.motto_podpis {
                 font-size: 0.875em;
+                text-align: right;
             }
 
             div.fragment {
                 padding-bottom: 1.5em;
             }
 
-            div.note p, div.note p.paragraph {
+            div.note p, div.dedication p, div.note p.paragraph, div.dedication p.paragraph {
                 text-align: right;
                 font-style: italic;
             }
                 visibility: hidden;
             }
 
-            .anchor {
-                position: absolute;
-                margin: -0.25em -0.5em;
-                left: 1em;
-                color: #777;
-                font-size: 12px;
-                width: 2em;
+            hr.spacer-line {
+                margin: 1.5em 0;
+                border: none;
+                border-bottom: 0.1em solid #000;
+            }
+
+            p.spacer-asterisk {
+                padding: 0;
+                margin: 1.5em 0;
                 text-align: center;
-                padding: 0.25em 0.5em;
-                line-height: 1.5em;
             }
 
-            .anchor:hover, #book-text .anchor:active {
-                color: #FFF;
-                background-color: #CCC;
+            div.person-list ol {
+                list-style: none;
+                padding: 0 0 0 1.5em;
             }
-            
-            #toc {
-                display: none;
+
+            p.place-and-time {
+                font-style: italic;
+            }
+
+            em.math, em.foreign-word, em.book-title, em.didaskalia {
+                font-style: italic;
+            }
+
+            em.author-emphasis {
+                letter-spacing: 0.1em;
+            }
+
+            em.person {
+                font-style: normal;
+                font-variant: small-caps;
             }
         </style>
-        <body>
+        <body> -->
         <div id="book-text">
             <xsl:apply-templates select="powiesc|opowiadanie|liryka_l|liryka_lp|dramat_wierszowany_l|dramat_wierszowany_lp|dramat_wspolczesny" />
             <xsl:if test="count(descendant::*[self::pe or self::pa or self::pr or self::pt][not(parent::extra)])">
                 </div>
             </xsl:if>
         </div>
-        </body>
-    </html>
+        <!-- </body>
+    </html> -->
 </xsl:template>
 
 
index 871ff3a..a410686 100644 (file)
@@ -134,6 +134,8 @@ class BookInfo(object):
             raise ParseError(e)
 
         description = tree.find('//' + book_info.RDF('Description'))
+        book_info.wiki_url = description.get(cls.RDF('about'), None)
+        
         if description is None:
             raise ParseError('no Description tag found in document')
         
@@ -157,6 +159,9 @@ class BookInfo(object):
         root = etree.Element(self.RDF('RDF'))
         description = etree.SubElement(root, self.RDF('Description'))
         
+        if self.wiki_url:
+            description.set(self.RDF('about'), self.wiki_url)
+        
         for tag, (attribute, converter) in self.mapping.iteritems():
             if hasattr(self, attribute):
                 e = etree.Element(tag)
@@ -165,6 +170,17 @@ class BookInfo(object):
         
         return unicode(etree.tostring(root, 'utf-8'), 'utf-8')
 
+    def to_dict(self):
+        etree._namespace_map[str(self.RDF)] = 'rdf'
+        etree._namespace_map[str(self.DC)] = 'dc'
+        
+        result = {'about': self.wiki_url}
+        for tag, (attribute, converter) in self.mapping.iteritems():
+            if hasattr(self, attribute):
+                result[attribute] = unicode(getattr(self, attribute))
+        
+        return result
+
 
 def parse(file_name):
     return BookInfo.from_file(file_name)
index f5ad138..b279e5d 100644 (file)
@@ -53,7 +53,7 @@ def transform(input_filename, output_filename):
     doc = etree.parse(doc_file, parser)
 
     result = doc.xslt(style)
-    if result.find('//h1') is not None:
+    if result.find('//p') is not None:
         add_anchors(result.getroot())
         add_table_of_contents(result.getroot())
         result.write(output_filename, xml_declaration=False, pretty_print=True, encoding='utf-8')
diff --git a/migrations/001_add_book_count_to_shelf.py b/migrations/001_add_book_count_to_shelf.py
deleted file mode 100644 (file)
index 4af55a1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-from django.core.management import setup_environ
-import settings
-
-setup_environ(settings)
-
-from catalogue.models import Tag, Book
-from django.db import connection
-
-query = 'ALTER TABLE catalogue_tag ADD COLUMN book_count integer NOT NULL DEFAULT 0'
-
-cursor = connection.cursor()
-cursor.execute(query)
-
-for shelf in Tag.objects.filter(category='set'):
-    shelf.book_count = len(Book.tagged.with_all(shelf))
-    shelf.save()
index ba9fbef..1f9c621 100644 (file)
@@ -1,4 +1,5 @@
 #!/usr/bin/env python
+import os
 from os.path import abspath, dirname, join
 import sys
 
index 1c60b41..0cc4ff5 100644 (file)
                 <p><img src="/media/img/indicator.gif" alt="*"/> Ładowanie</p>
             </div>
         </div>
-    <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
-    </script>
-    <script type="text/javascript">
-        _uacct = "UA-2576694-1";
-        urchinTracker();
-    </script>
+        <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>
index a61396a..1ffcccc 100644 (file)
@@ -12,6 +12,7 @@
     </form>
     
     <div id="books-list">
+        <p>Na podstawie: {{ book.extra_info.source_name }}</p>
         {% if book.has_description %}
             <div id="description">
                 {{ book.description|safe }}
                     <a href="{{ tag.get_absolute_url }}">{{ tag }}</a>
                     {% endfor %}
                 </li>
+                <li><a href="{{ book.extra_info.about }}">Lektura na wiki projektu</a></li>
+                <li><a href="{{ book.extra_info.source_url }}">Lektura w CBN Polona</a></li>
+                <li><a href="{{ book.xml_file.url }}">Kod źródłowy utworu (XML)</a></li>
             </ul>
         </div>
         <div id="themes-list">
-            {% if categories.theme %}
-                <h2>Motywy w utworze</h2>
-                <ul>
-                {% for theme in categories.theme %}
-                    <li><a href="{{ theme.get_absolute_url }}">{{ theme }}</a></li>
-                {% endfor %}
-                </ul>
-            {% endif %}
+            <h2>Motywy w utworze</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>
             <p><img src="/media/img/indicator.gif" alt="*"/> Ładowanie</p>
         </div>
     </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/wolnelektury/templates/catalogue/book_fragments.html b/wolnelektury/templates/catalogue/book_fragments.html
new file mode 100644 (file)
index 0000000..4f1c0eb
--- /dev/null
@@ -0,0 +1,37 @@
+{% extends "base.html" %}
+{% load catalogue_tags pagination_tags %}
+
+{% block title %}Motyw {{ theme }} w utworze {{ book }} w WolneLektury.pl{% endblock %}
+
+{% block bodyid %}tagged-object-list{% endblock %}
+
+{% block body %}
+    <h1>Motyw {{ theme }} w utworze {{ book }}</h1>
+    <form action="{% url search %}" method="get" accept-charset="utf-8" id="search-form">
+        <p>{{ form.q }} <input type="submit" value="Szukaj" /> <strong>lub</strong> <a href="{{ book.get_absolute_url }}">wróć do strony utworu</a></p>
+    </form>
+
+    {% autopaginate fragments 10 %}
+    <div id="books-list">
+        <ol>
+        {% for fragment in fragments %}
+            <li>{{ fragment.short_html }}</li>
+        {% endfor %}
+        </ol>
+        {% paginate %}
+    </div>
+    <div id="tags-list">
+        <div id="categories-list">
+            Zobacz opis <a href="{{ book.get_absolute_url }}">utworu {{ book }}</a>
+        </div>
+        <div id="themes-list">
+        </div>
+        <div class="clearboth"></div>
+    </div>
+    <div id="set-window">
+        <div class="header"><a href="#" class="jqmClose">Zamknij</a></div>
+        <div class="target">
+            <p><img src="/media/img/indicator.gif" alt="*"/> Ładowanie</p>
+        </div>
+    </div>
+{% endblock %}
\ No newline at end of file
index 8a6b0f6..d3f6a1c 100644 (file)
             </ol>
         </div>
         {{ book.html_file.read|safe }}
-    <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
-    </script>
-    <script type="text/javascript">
-        _uacct = "UA-2576694-1";
-        urchinTracker();
-    </script>
+        <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>