Merge branch 'master' of https://github.com/fnp/wolnelektury
authorMarcin Koziej <marcin@lolownia.org>
Mon, 16 Apr 2012 12:20:12 +0000 (14:20 +0200)
committerMarcin Koziej <marcin@lolownia.org>
Mon, 16 Apr 2012 12:20:12 +0000 (14:20 +0200)
apps/opds/views.py
apps/search/index.py
apps/search/management/commands/optimizeindex.py
apps/wolnelektury_core/static/css/widget.css
apps/wolnelektury_core/static/img/search.png
apps/wolnelektury_core/static/js/search.js
apps/wolnelektury_core/static/js/widget.js
apps/wolnelektury_core/static/js/widgetInit.js
apps/wolnelektury_core/static/widget.html

index ec93da1..f793d7d 100644 (file)
@@ -16,11 +16,14 @@ from django.contrib.sites.models import Site
 from basicauth import logged_in_or_basicauth, factory_decorator
 from catalogue.models import Book, Tag
 
-from search import Search, SearchResult, JVM
+from search.views import get_search, SearchResult, JVM
 from lucene import Term, QueryWrapperFilter, TermQuery
 
+import logging
 import re
 
+log = logging.getLogger('opds')
+
 from stats.utils import piwik_track
 
 _root_feeds = (
@@ -345,22 +348,21 @@ class SearchFeed(AcquisitionFeed):
         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
+                log.info("get_criteria: %s" % e)
                 if not e:
                     return None
                 c = e[0][position]
-                print c
+                log.info("get_criteria: %s" % 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
@@ -378,8 +380,7 @@ class SearchFeed(AcquisitionFeed):
             categories = None
             fuzzy = False
 
-
-        srch = Search()
+        srch = get_search()
         hint = srch.hint()
 
         # Scenario 1: full search terms provided.
@@ -388,11 +389,11 @@ class SearchFeed(AcquisitionFeed):
             filters = []
 
             if author:
-                print "narrow to author %s" % author
+                log.info( "narrow to author %s" % author)
                 hint.tags(srch.search_tags(author, filt=srch.term_filter(Term('tag_category', 'author'))))
 
             if translator:
-                print "filter by translator %s" % translator
+                log.info( "filter by translator %s" % translator)
                 filters.append(QueryWrapperFilter(
                     srch.make_phrase(srch.get_tokens(translator, field='translators'),
                                      field='translators')))
@@ -404,18 +405,25 @@ class SearchFeed(AcquisitionFeed):
 
             flt = srch.chain_filters(filters)
             if title:
-                print "hint by book title %s" % title
+                log.info( "hint by book title %s" % title)
                 q = srch.make_phrase(srch.get_tokens(title, field='title'), field='title')
                 hint.books(*srch.search_books(q, filt=flt))
 
             toks = srch.get_tokens(query)
-            print "tokens: %s" % toks
-            #            import pdb; pdb.set_trace()
+            log.info("tokens for query: %s" % toks)
+            
             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]
+            books = []
+            for r in results:
+                try:
+                    books.append(r.book)
+                except Book.DoesNotExist:
+                    pass
+            log.info("books: %s" % books)
+            return books
         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.
index e8b7a5c..b689c76 100644 (file)
@@ -317,14 +317,19 @@ class Index(BaseIndex):
             doc.add(NumericField("parent_id", Field.Store.YES, True).setIntValue(int(book.parent.id)))
         return doc
 
-    def remove_book(self, book, remove_snippets=True):
+    def remove_book(self, book_or_id, remove_snippets=True):
         """Removes a book from search index.
         book - Book instance."""
-        q = NumericRangeQuery.newIntRange("book_id", book.id, book.id, True, True)
+        if isinstance(book_or_id, catalogue.models.Book):
+            book_id = book_or_id.id
+        else:
+            book_id = book_or_id
+
+        q = NumericRangeQuery.newIntRange("book_id", book_id, book_id, True, True)
         self.index.deleteDocuments(q)
 
         if remove_snippets:
-            snippets = Snippets(book.id)
+            snippets = Snippets(book_id)
             snippets.remove()
 
     def index_book(self, book, book_info=None, overwrite=True):
@@ -341,7 +346,8 @@ class Index(BaseIndex):
         book_doc = self.create_book_doc(book)
         meta_fields = self.extract_metadata(book, book_info, dc_only=['source_name', 'authors', 'title'])
         # let's not index it - it's only used for extracting publish date
-        del meta_fields['source_name']
+        if 'source_name' in meta_fields:
+            del meta_fields['source_name']
         
         for f in meta_fields.values():
             if isinstance(f, list) or isinstance(f, tuple):
@@ -1060,7 +1066,8 @@ class Search(IndexStore):
 
         return toks
 
-    def fuzziness(self, fuzzy):
+    @staticmethod
+    def fuzziness(fuzzy):
         """Helper method to sanitize fuzziness"""
         if not fuzzy:
             return None
@@ -1097,7 +1104,8 @@ class Search(IndexStore):
                 phrase.add(term)
         return phrase
 
-    def make_term_query(self, tokens, field='content', modal=BooleanClause.Occur.SHOULD, fuzzy=False):
+    @staticmethod
+    def make_term_query(tokens, field='content', modal=BooleanClause.Occur.SHOULD, fuzzy=False):
         """
         Returns term queries joined by boolean query.
         modal - applies to boolean query
index a8a4cf9..51bf95b 100644 (file)
@@ -1,14 +1,38 @@
 
 from django.core.management.base import BaseCommand
-from search import Index
+from search import Index, Search
+from lucene import IndexReader, IndexSearcher, Term
+from catalogue.models import Book
+
 
 class Command(BaseCommand):
     help = 'Optimize Lucene search index'
     args = ''
 
+    def delete_old(self, index):
+        existing_ids = set([book.id for book in Book.objects.all()])
+
+        reader = IndexReader.open(index.index, False)
+        searcher = IndexSearcher(reader)
+        try:
+            num = searcher.docFreq(Term('is_book', 'true'))
+            docs = searcher.search(Search.make_term_query(['true'], 'is_book'), num)
+            for result in docs.scoreDocs:
+                stored = searcher.doc(result.doc)
+                book_id = int(stored.get('book_id'))
+                if not book_id in existing_ids:
+                    print "book id %d doesn't exist." % book_id
+                    index.remove_book(book_id)
+        finally:
+            searcher.close()
+            reader.close()
+
     def handle(self, *args, **opts):
         index = Index()
         index.open()
+
+        self.delete_old(index)
+
         try:
             index.optimize()
         finally:
index 6266988..14aed95 100644 (file)
+
+/* 
+ *  RESET 
+ *  src: http://meyerweb.com/eric/tools/css/reset/
+ */
+
+#wl div, #wl span, #wl applet, #wl object, #wl iframe,
+#wl  #eh1, #wl h2, #wl h3, #wl h4, #wl h5, #wl h6, #wl p, #wl blockquote, #wl pre,
+#wl a, #wl abbr, #wl acronym, #wl address, #wl big, #wl cite, #wl code,
+#wl del, #wl dfn, #wl em, #wl img, #wl ins, #wl kbd, #wl q, #wl s, #wl samp,
+#wl small, #wl strike, #wl strong, #wl sub, #wl sup, #wl tt, #wl var,
+#wl b, #wl u, #wl i, #wl center,
+#wl dl, #wl dt, #wl dd, #wl ol, #wl ul, #wl li,
+#wl fieldset, #wl form, #wl label, #wl legend,
+#wl table, #wl caption, #wl tbody, #wl tfoot, #wl thead, #wl tr, #wl th, #wl td,
+#wl article, #wl aside, #wl canvas, #wl details, #wl embed,
+#wl figure, #wl figcaption, #wl footer, #wl header, #wl hgroup, 
+#wl menu, #wl nav, #wl output, #wl ruby, #wl section, #wl summary,
+#wl time, #wl mark, #wl audio, #wl video {
+       margin: 0;
+       padding: 0;
+       border: 0;
+       font-size: 100%;
+       font: inherit;
+       vertical-align: baseline;
+}
+
 #wl {
-background-color: white;
+       line-height: 1;
+}
+
+#wl ol, #wl ul {
+       list-style: none;
+}
+#wl blockquote, #wl q {
+       quotes: none;
+}
+
+#wl blockquote:before, #wl blockquote:after,
+#wl q:before, #wl q:after {
+       content: '';
+       content: none;
+}
+#wl table {
+       border-collapse: collapse;
+       border-spacing: 0;
 }
+
+/* END RESET */
+
+#wl {
+    background-color: white;
+}
+
 #wl a, a:visited, a:hover {
-border: 0;
+    border: 0;
 }
+
 #wl img {
-border: 0;
+    border: 0;
+    width: 8.625em;
+    margin: 0.375em 0;
 }
+
+
 .ui-menu {
-width: 160px;
-font-size: small;
-list-style-type: none;
-padding: 0;
-margin:0;
-border-left:  1px solid #696969;
-border-right: 1px solid #696969;
-border-bottom: 1px solid #696969;
+    width: 29em;
+    font-size: small;
+    list-style-type: none;
+    padding: 0;
+    margin:0;
+    border: 1px solid #ddd;
+}
+
+.ui-menu .search-hint-label {
+    display: inline-block;
+    width: 20em;
+    margin-right: 2em;
+    font-size: 1.1em;
+    line-height: 1.636em;
+    white-space: nowrap;
+    overflow: hidden;
+}
+
+.ui-menu .search-hint-category {
+    width: 9em;
+}
+
+.ui-corner-all {
+    /*width: 160px;*/
+    cursor: pointer;
+    display:block;
+}
+
+.ui-corner-all a {
+    text-decoration: none;
+    color: #0D7E85;
+    font-size: small;
+    padding: 5px;
+
 }
 
 .ui-menu li {
-font-size: small;
-padding: 5px;
-width: 150px
 }
 
 .ui-menu li:nth-child(odd) {
-background-color: white;
+    background-color: white;
 }
 
 .ui-menu li:nth-child(even){
-background-color: #EDF1F5;
+    background-color: #EEE;
+}
+
+.ui-menu li .ui-state-hover {
+    background-color: #fdf5ce;
 }
 
 .ui-menu li:hover{
-background-color: #053469;
-color:white;
+    background-color: #053469;
+    color:white;
 }
 
 .ui-menu a:hover {
-color:white;
-text-decoration: none;
+    color:white;
+    text-decoration: none;
 }
 
-.ui-corner-all {
-width: 160px;
-cursor: pointer;
-display:block;
+
+#wl #id_qq {
+    font-family: Georgia;
+    font-size: 0.75em;
+    
+    background-color: #FFFFFF;
+    border: medium none;
+    border-radius: 0.38em 0.38em 0.38em 0.38em;
+    box-shadow: 0 0 0.5em #444444 inset;
+    color: #000000;
+    height: 2.54em;
+    width: 9.125em;
+
+    line-height: 2.5em;
+    padding: 0 0 0 1em;
+    position: relative;
 }
 
-.ui-corner-all a{
-    color: black;
-    text-decoration: none;
+#wl input[type=image] {
+    width: 1.5em;
+    height: 1.5625em;
+    top: 0.375em;
+    position: relative;
+    margin-left: 0.625em;
 }
+
index 6bfc84c..16b2a50 100644 (file)
Binary files a/apps/wolnelektury_core/static/img/search.png and b/apps/wolnelektury_core/static/img/search.png differ
index 6afc4a3..293b9e3 100644 (file)
@@ -16,7 +16,9 @@ var __bind = function (self, fn) {
                focus: function() { return false; },
                source: this.element.data('source'),
            };
-           this.element.autocomplete(opts).data("autocomplete")._renderItem = __bind(this, this.render_item);
+
+           this.element.autocomplete($.extend(opts, this.options))
+               .data("autocomplete")._renderItem = __bind(this, this.render_item);
        },
 
        enter: function(event, ui) {
@@ -32,7 +34,7 @@ var __bind = function (self, fn) {
                .append('<a href="'+item.url+'"><span class="search-hint-label">'+item.label+'</span>'+
                        '<span class="search-hint-category mono">'+item.category+'</span></a>')
                .appendTo(ul);
-       },
+       }, 
 
        destroy: function() {
 
index de30eb7..2d9a42b 100644 (file)
@@ -8,15 +8,19 @@ var inputText   = document.createElement('input');
 var inputSubmit = document.createElement('input');
 var body        = document.getElementsByTagName('body')
 var stylesheet = document.createElement('link');
+var stylesheetJQUI = document.createElement('linl');
 
-var host = 'www.wolnelektury.pl';
+var host = 'localhost:8000'; //'www.wolnelektury.pl';
 
 /* set attributes of created elements */
 stylesheet.setAttribute('type', 'text/css');
 stylesheet.setAttribute('rel', 'stylesheet');
 stylesheet.setAttribute('href', 'http://'+host+'/static/css/widget.css');
+stylesheetJQUI.setAttribute('type', 'text/css');
+stylesheetJQUI.setAttribute('rel', 'stylesheet');
+stylesheetJQUI.setAttribute('href', 'http://'+host+'/static/css/ui-lightness/jquery-ui-1.8.16.custom.css');
 linkLogo.setAttribute('href', 'http://'+host);
-logo.setAttribute('src', 'http://'+host+'/static/img/logo.png');
+logo.setAttribute('src', 'http://'+host+'/static/img/logo-bez.png');
 form.setAttribute('action', 'http://'+host+'/szukaj/');
 form.setAttribute('method', 'get');
 form.setAttribute('accept-charset', 'utf-8');
@@ -26,30 +30,35 @@ inputText.setAttribute('title', 'tytul, autor, motyw/temat, epoka, rodzaj, gatun
 inputText.setAttribute('value', '');
 inputText.setAttribute('name', 'q');
 inputText.setAttribute('id', 'id_qq');
-inputText.setAttribute('size', '13');
+inputText.setAttribute('data-source', 'http://'+host+'/szukaj/hint');
+/*inputText.setAttribute('size', '13');*/
 inputSubmit.setAttribute('type', 'image');
 inputSubmit.setAttribute('src', 'http://'+host+'/static/img/search.png');
-inputSubmit.setAttribute('style', 'position:relative; top:5px; margin-left:5px');
+/* inputSubmit.setAttribute('style', 'position:relative; top:5px; margin-left:5px');*/
 
 /* import jquery and autocomplete */
 var scriptJ = document.createElement('script');
 scriptJ.setAttribute('type', 'text/javascript');
 scriptJ.setAttribute('src', 'http://'+host+'/static/js/jquery.js');
 
-var scriptAutoComplete = document.createElement('script');
-scriptAutoComplete.setAttribute('type', 'text/javascript');
-scriptAutoComplete.setAttribute('src', 'http://'+host+'/static/js/jquery-ui-1.8.2.custom.min.js');
+var scriptUI = document.createElement('script');
+scriptUI.setAttribute('type', 'text/javascript');
+scriptUI.setAttribute('src', 'http://'+host+'/static/js/jquery-ui-1.8.2.custom.min.js');
+scriptUI.setAttribute('id', 'wl-jquery-ui-script')
+
+var scriptSearch = document.createElement('script');
+scriptSearch.setAttribute('type', 'text/javascript');
+scriptSearch.setAttribute('src', 'http://'+host+'/static/js/search.js');
+scriptSearch.setAttribute('id', 'wl-search-script')
 
-var scriptInit = document.createElement('script');
-scriptInit.setAttribute('type', 'text/javascript');
-scriptInit.setAttribute('src', 'http://'+host+'/static/js/widgetInit.js');
 
 body[0].appendChild(scriptJ);
-body[0].appendChild(scriptAutoComplete);
-body[0].appendChild(scriptInit);
+body[0].appendChild(scriptUI);
+body[0].appendChild(scriptSearch);
 
 /* append elements to widget */
 widget.appendChild(stylesheet);
+//widget.appendChild(stylesheetJQUI);
 widget.appendChild(linkLogo);
 linkLogo.appendChild(logo);
 widget.appendChild(form);
@@ -57,6 +66,7 @@ form.appendChild(inputText);
 form.appendChild(inputSubmit);
 
 /* ...and a little make-up */
+/*
 widget.style.borderColor = "#84BF2A";
 widget.style.borderWidth = "2px";
 widget.style.borderStyle = "solid";
@@ -64,6 +74,7 @@ widget.style.width = "160px";
 widget.style.padding = "10px";
 widget.style.fontSize = "12px";
 form.style.paddingTop = "10px";
+*/
 
 /* resize - if needed */
 if(widget.getAttribute('width') == '140'){
@@ -71,3 +82,19 @@ if(widget.getAttribute('width') == '140'){
     inputText.setAttribute('size', '10');
     widget.style.width = "140px";
 }
+
+var wl_loaded_scripts = {};
+
+function wl_initialize_after_load(just_loaded) {
+    wl_loaded_scripts[just_loaded] = true;
+    if (wl_loaded_scripts.jquery 
+       && wl_loaded_scripts.ui 
+       && wl_loaded_scripts.search) {
+       var s = $('#id_qq');
+       s.search({source: s.attr('data-source')});
+    }
+}
+
+scriptJ.onload = function() { wl_initialize_after_load('jquery'); };
+scriptUI.onload = function() { wl_initialize_after_load('ui'); };
+scriptSearch.onload = function() { wl_initialize_after_load('search'); };
index ab57a30..4cfa85a 100644 (file)
@@ -1,5 +1,20 @@
-       $(function() {          
-               $("#id_qq").autocomplete({
+
+var wl_scripts_loaded = {};
+
+function wl_load_search_if_ready(id) {
+    wl_scripts_loaded[id] = true;
+    if (wl_scripts_loaded['wl-search-script'] &&
+       wl_scripts_loaded['wl-jquery-ui-script']) 
+    {
+       var s = $('#id_qq');
+       s.search({source: s.attr('data-source')});
+    }
+}
+
+$('#wl-search-script').ready(function(){wl_load_search_if_ready('wl-search-script');});
+$('#wl-jquery-ui-script').ready(function(){wl_load_search_if_ready('wl-jquery-ui-script');});
+
+/*autocomplete({
                        source: function(request, response) {
                                $.ajax({
                                        url: "http://www.wolnelektury.pl/katalog/jtags/",
@@ -27,3 +42,4 @@
             }                  
                });
        });
+*/
index 890184d..fffc016 100644 (file)
@@ -5,7 +5,7 @@
 <!-- KONIEC -->
 
 <!-- START Umiescic ten element zaraz przed zamknieciem taga body: </body> -->
-<script type="text/javascript" src="http://www.wolnelektury.pl/static/js/widget.js"></script>
+<script type="text/javascript" src="http://localhost:8000/static/js/widget.js"></script>
 <!-- KONIEC -->
 
 </body>