Merge branch 'pretty' of github.com:fnp/wolnelektury into pretty
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 19 Jan 2012 14:46:10 +0000 (15:46 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Thu, 19 Jan 2012 14:46:10 +0000 (15:46 +0100)
Conflicts:
wolnelektury/static/css/book_box.css
wolnelektury/templates/catalogue/book_wide.html

13 files changed:
apps/catalogue/models.py
apps/catalogue/tasks.py
apps/search/index.py
apps/search/templatetags/__init__.py [new file with mode: 0644]
apps/search/templatetags/search_tags.py [new file with mode: 0644]
scripts/make-xml-zip.py [new file with mode: 0755]
wolnelektury/static/css/base.css
wolnelektury/static/css/book_box.css
wolnelektury/static/css/master.css
wolnelektury/static/js/search.js
wolnelektury/templates/catalogue/book_searched.html [new file with mode: 0644]
wolnelektury/templates/catalogue/book_wide.html
wolnelektury/templates/catalogue/search_multiple_hits.html

index 1f6210d..ebecc36 100644 (file)
@@ -748,7 +748,8 @@ class Book(models.Model):
             book.build_mobi()
 
         if not settings.NO_SEARCH_INDEX and search_index:
-            index_book.delay(book.id, book_info)
+            book.search_index()
+            #index_book.delay(book.id, book_info)
 
         book_descendants = list(book.children.all())
         descendants_tags = set()
index 86e84a5..e1ff915 100755 (executable)
@@ -5,6 +5,7 @@
 from datetime import datetime
 from celery.task import task
 import catalogue.models
+from traceback import print_exc
 
 @task
 def touch_tag(tag):
@@ -18,4 +19,9 @@ def touch_tag(tag):
 
 @task
 def index_book(book_id, book_info=None):
-    return catalogue.models.Book.objects.get(id=book_id).search_index(book_info)
+    try:
+        return catalogue.models.Book.objects.get(id=book_id).search_index(book_info)
+    except Exception, e:
+        print "Exception during index: %s" % e
+        print_exc()
+        raise e
index cc478ee..307376d 100644 (file)
@@ -25,6 +25,7 @@ import re
 import errno
 from librarian import dcparser
 from librarian.parser import WLDocument
+from lxml import etree
 import catalogue.models
 from multiprocessing.pool import ThreadPool
 from threading import current_thread
@@ -212,7 +213,7 @@ class Index(BaseIndex):
 
         for tag in catalogue.models.Tag.objects.all():
             doc = Document()
-            doc.add(NumericField("tag_id", Field.Store.YES, True).setIntValue(tag.id))
+            doc.add(NumericField("tag_id", Field.Store.YES, True).setIntValue(int(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))
@@ -223,9 +224,9 @@ class Index(BaseIndex):
         Create a lucene document referring book id.
         """
         doc = Document()
-        doc.add(NumericField("book_id", Field.Store.YES, True).setIntValue(book.id))
+        doc.add(NumericField("book_id", Field.Store.YES, True).setIntValue(int(book.id)))
         if book.parent is not None:
-            doc.add(NumericField("parent_id", Field.Store.YES, True).setIntValue(book.parent.id))
+            doc.add(NumericField("parent_id", Field.Store.YES, True).setIntValue(int(book.parent.id)))
         return doc
 
     def remove_book(self, book):
@@ -401,28 +402,28 @@ class Index(BaseIndex):
 
                 if header.tag in self.skip_header_tags:
                     continue
+                if header.tag is etree.Comment:
+                    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)
+                # section content
+                content = []
 
                 for start, end in walker(header):
+                        # handle fragments and themes.
                     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
+                                      #                        import pdb; pdb.set_trace()
                         frag = fragments[fid]
                         if frag['themes'] == []:
                             continue  # empty themes list.
@@ -442,12 +443,23 @@ class Index(BaseIndex):
                                        themes=frag['themes'])
 
                         self.index.addDocument(doc)
+
+                        # Collect content.
                     elif start is not None:
                         for frag in fragments.values():
                             frag['content'].append(start.text)
+                        content.append(start.text)
                     elif end is not None:
                         for frag in fragments.values():
                             frag['content'].append(end.tail)
+                        content.append(end.tail)
+
+                        # in the end, add a section text.
+                doc = add_part(snippets, header_index=position, header_type=header.tag,
+                               content=fix_format(u' '.join(filter(lambda s: s is not None, content))))
+
+                self.index.addDocument(doc)
+
         finally:
             snippets.close()
 
@@ -563,6 +575,8 @@ class SearchResult(object):
 
         fragment = stored.get("fragment_anchor")
 
+        if snippets:
+            snippets = snippets.replace("/\n", "\n")
         hit = (sec + (header_span,), fragment, scoreDocs.score, {'how_found': how_found, 'snippets': snippets and [snippets] or []})
 
         self._hits.append(hit)
@@ -630,6 +644,7 @@ class SearchResult(object):
             frag = catalogue.models.Fragment.objects.get(anchor=f[FRAGMENT])
             m = {'score': f[SCORE],
                  'fragment': frag,
+                 'section_number': f[POSITION][POSITION_INDEX] + 1,
                  'themes': frag.tags.filter(category='theme')
                  }
             m.update(f[OTHER])
@@ -884,7 +899,7 @@ class Search(IndexStore):
                 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))
+                books.append(SearchResult(self.searcher, found, how_found="search_perfect_book"))
         return books
 
     def search_book(self, searched, max_results=20, fuzzy=False, hint=None):
@@ -910,7 +925,7 @@ class Search(IndexStore):
                                    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))
+            books.append(SearchResult(self.searcher, found, how_found="search_book"))
 
         return books
 
@@ -932,7 +947,7 @@ class Search(IndexStore):
                                                            flt]),
                                        max_results)
             for found in top.scoreDocs:
-                books.append(SearchResult(self.searcher, found, snippets=self.get_snippets(found, q)))
+                books.append(SearchResult(self.searcher, found, snippets=self.get_snippets(found, q), how_found='search_perfect_parts'))
 
         return books
 
@@ -964,7 +979,7 @@ class Search(IndexStore):
 
         topDocs = self.searcher.search(q, only_in, max_results)
         for found in topDocs.scoreDocs:
-            books.append(SearchResult(self.searcher, found))
+            books.append(SearchResult(self.searcher, found, how_found='search_everywhere_themesXcontent'))
             print "* %s theme x content: %s" % (searched, books[-1]._hits)
 
         # query themes/content x author/title/tags
@@ -983,7 +998,7 @@ class Search(IndexStore):
 
         topDocs = self.searcher.search(q, only_in, max_results)
         for found in topDocs.scoreDocs:
-            books.append(SearchResult(self.searcher, found))
+            books.append(SearchResult(self.searcher, found, how_found='search_everywhere'))
             print "* %s scatter search: %s" % (searched, books[-1]._hits)
 
         return books
diff --git a/apps/search/templatetags/__init__.py b/apps/search/templatetags/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/apps/search/templatetags/search_tags.py b/apps/search/templatetags/search_tags.py
new file mode 100644 (file)
index 0000000..03e33c8
--- /dev/null
@@ -0,0 +1,45 @@
+# -*- 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.
+#
+# import feedparser
+# import datetime
+
+from django import template
+from django.template import Node, Variable
+from django.utils.encoding import smart_str
+from django.core.urlresolvers import reverse
+# from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
+# from django.db.models import Q
+from django.conf import settings
+# from django.utils.translation import ugettext as _
+from catalogue.templatetags.catalogue_tags import book_wide
+from catalogue.models import Book
+# from catalogue.forms import SearchForm
+# from catalogue.utils import split_tags
+
+
+register = template.Library()
+
+
+@register.inclusion_tag('catalogue/book_searched.html')
+def book_searched(result):
+    book = Book.objects.get(pk=result.book_id)
+    vals = book_wide(book)
+
+    # snippets = []
+    # for hit in result.hits:
+    #     if hit['snippets']:
+    #         snippets.append(hit['snippets'])
+    #     elif hit['fragment']:
+    #         snippets.append(hit['fragment'].short_text)
+
+    # We don't need hits which lead to sections but do not have
+    # snippets.
+    vals['hits'] = filter(lambda h: 'fragment' in h or
+                          h['snippets'], result.hits)
+
+    for hit in vals['hits']:
+        hit['snippets'] = map(lambda s: s.replace("\n", "<br />").replace('---', '&mdash;'), hit['snippets'])
+
+    return vals
diff --git a/scripts/make-xml-zip.py b/scripts/make-xml-zip.py
new file mode 100755 (executable)
index 0000000..d8b3dde
--- /dev/null
@@ -0,0 +1,31 @@
+#!/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.
+#
+import sys
+sys.path.insert(0, '../apps')
+sys.path.insert(0, '../lib')
+sys.path.insert(0, '../lib/librarian')
+sys.path.insert(0, '../wolnelektury')
+sys.path.insert(0, '..')
+
+from django.core.management import setup_environ
+from wolnelektury import settings
+import sys
+import zipfile
+
+setup_environ(settings)
+
+from catalogue.models import Book
+
+
+if len(sys.argv) < 2:
+    print "Provide a zip name as first argument"
+    sys.exit(-1)
+
+zip = zipfile.ZipFile(sys.argv[1], 'w')
+for book in Book.objects.all():
+    zip.write(book.xml_file.path, "%s.xml" % book.slug)
+zip.close()
+
index 5ce2f5a..556d926 100755 (executable)
@@ -57,7 +57,7 @@ h2 {
 
 .mono {
     font-family: "Andale Mono", "Lucida Sans Typewriter", "Courier New";
-    font-weight: bold;
+/*    font-weight: bold; */
 }
 
 .accent1 {
index b816fc0..ca58a63 100755 (executable)
 
 .book-wide-box {
     width: 98.5em;
+
+    /** This is a fullpage box, it must be aligned with the top menu. 
+        This corresponds to a .1em margin below **/
     margin-left: -0.1em;
 }
 
+/* 
+ * A mini-box wraps it's contents (image + label) in an <a>
+ * other boxes have an inner box as a wrapper.
+ */
+
+.book-box-inner {
+    /* min, so it can grow */
+    min-height: 19.75em; 
+    margin: .5em;
+}
+
 .book-mini-box a, .book-box-inner {
     display: block;
     color: black;
     border: 1px solid #ddd;
-    height: 20em;
+/*    height: 20em; */
     padding: .8em 1em;
     margin: .1em;
     background: #fff;
     margin: .1em;
     overflow: hidden;
 }
-.book-box-inner {
-    height: 19.75em;
-    margin: .5em;
-}
+
 
 .book-wide-box .book-box-inner {
-    height: 24.4em;
+   /* min, so it can grow */ 
+   min-height: 24.4em;
 }
 
+/*.book-wide-box.search-result .book-box-inner, .book-wide-box.search-result blockquote {
+    height: auto !important;
+}*/
+
 .book-mini-box img, .book-box img, .book-wide-box img {
     width: 13.9em;
     height: 19.3em;
@@ -212,10 +228,16 @@ ul.book-box-tools {
     vertical-align: center;
 }
 
-.book-wide-box blockquote div {
+.book-wide-box blockquote div.cite-text {
     padding: 0.888em;
 }
 
+.book-wide-box blockquote p.cite-more {
+    display: inline;
+    font-size: 0.611em;
+    float: right;
+}
+
 ul.inline-items, ul.inline-items li {
     margin: 0;
     padding: 0;
@@ -225,22 +247,20 @@ ul.inline-items li {
     display: inline-block;
 }
 
-.book-wide-box #other-tools {
+.book-wide-box .other-tools {
     float: left;
     width: 14.5em;
     margin: 6em 0 0 1.5em;
     
 }
 
-.book-wide-box #other-download {
+.book-wide-box .other-download {
     float: left;
     width: 22.5em;
-    margin: 6em 1.5em 0em 1.5em
+    margin: 6em 1.5em 0em 1.5em;
 }
 
 
-
-
 .star {
     font-size: 2.25em;
     margin-right: .5em;
@@ -274,3 +294,7 @@ ul.inline-items li {
     display: none;
 }
 
+.snippets .snippet-text {
+    font-size: 1.2em;
+    margin: 1.083em 0em;
+}
index 85f1a40..26c13cc 100644 (file)
@@ -147,6 +147,10 @@ hr {
        border-right: none;
 }
 
+#lang-menu-items {
+    z-index: 1;
+}
+
 /* ======================== */
 /* = Footer with sponsors = */
 /* ======================== */
index 47b6665..5951b8b 100644 (file)
@@ -43,6 +43,10 @@ var __bind = function (self, fn) {
 
     $(function() {
         $("#search").search().labelify({labelledClass: "blur"});
+
+       $(".search-result .see-more-snippets").click(function() {
+           $(this).closest('.search-result').find('.snippets').removeClass('ui-helper-hidden');
+           });
     });
 
 
diff --git a/wolnelektury/templates/catalogue/book_searched.html b/wolnelektury/templates/catalogue/book_searched.html
new file mode 100644 (file)
index 0000000..d719f30
--- /dev/null
@@ -0,0 +1,34 @@
+{% extends "catalogue/book_wide.html" %}
+{% load i18n %}
+
+
+{% block box-class %}book-wide-box search-result{% endblock %}
+
+{% block quote %}
+{% if hits.0.snippets %}
+  <div class="cite-text"><a href="{% url book_text book.slug %}#f{{hits.0.section_number}}">{{hits.0.snippets.0|safe}}</a></div>
+{% else %}{% if hits.0.fragment %}
+  <div class="cite-text"><a href="{{hits.0.fragment.get_absolute_url}}">{{hits.0.fragment.short_text|safe}}</a></div>
+{% endif %}{% endif %}
+
+{% if hits.1 %}
+  <p class="cite-more mono"><a class="see-more-snippets" href="#snippets-{{book.id}}">{% trans "See more" %}</a></p>
+{% endif %}
+{% endblock %}
+
+
+{% block box-append %}
+<div class="snippets ui-helper-hidden">
+<a name="snippets-{{book.id}}">
+{% for hit in hits %}
+  {% if hit.snippets %}
+    <div class="snippet-text"><a href="{% url book_text book.slug %}#f{{hit.section_number}}">{{hit.snippets.0|safe}}</a></div>
+  {% else %}
+    {% if hit.fragment %}
+      <div class="snippet-text"><a href="{{hit.fragment.get_absolute_url}}">{{hit.fragment.short_text|safe}}</a></div>
+    {% endif %}
+  {% endif %}
+{% endfor %}
+</a>
+</div>
+{% endblock %}
index a13f1a6..cd52ff1 100644 (file)
@@ -6,12 +6,13 @@
 {% block right-column %}
 <div class="right-column">
   <blockquote id="quote" class="cite-body">
+    {% block quote %}
     <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>
+    {% endblock %}
   </blockquote>
 
-
-  <div id="other-tools">
+  <div class="other-tools">
     <h2 class="mono">{% trans "See" %}</h2>
     <ul class="inline-items">
       {% if extra_info.source_url %}
@@ -28,7 +29,7 @@
       {% endif %}
     </ul>
   </div>
-  <div id="other-download">
+  <div class="other-download">
     <h2 class="mono">{% trans "Download" %}</h2>
     <ul class="inline-items">
       <li>
index 7a3e580..5d22251 100644 (file)
@@ -1,75 +1,23 @@
 {% extends "base.html" %}
 {% load i18n %}
-{% load catalogue_tags pagination_tags %}
+{% load search_tags pagination_tags %}
 
 {% block titleextra %}{% trans "Search" %}{% endblock %}
 
 {% block bodyid %}tagged-object-list{% endblock %}
 
 {% block body %}
-    <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 %}
+    <!-- tu pójdą trafienia w tagi: Autorzy - z description oraz motywy i rodzaje (z book_count) -->
+
     <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>
+        {% book_searched result %}
       {% endfor %}
-      </ol>
     </div>
 
 
-{% comment %}
-    <div id="books-list">
-        <p>{% trans "More than one result matching the criteria found." %}</p>
-        <ul class='matches'>
-        {% for match, link, type in results %}
-          <li>{% trans type %}: <a href='{{ link }}'>
-            {% ifequal type "book" %}
-                {% book_title match %}
-            {% else %}
-                {{ match.name }}
-            {% endifequal %}
-          </a></li>
-        {% endfor %}
-        </ul>
-    </div>
-{% endcomment %}
 
 {% endblock %}