Back to index

plone3  3.1.7
livesearch_reply.py
Go to the documentation of this file.
00001 ## Script (Python) "livescript_reply"
00002 ##bind container=container
00003 ##bind context=context
00004 ##bind namespace=
00005 ##bind script=script
00006 ##bind subpath=traverse_subpath
00007 ##parameters=q,limit=10,path=None
00008 ##title=Determine whether to show an id in an edit form
00009 
00010 from Products.CMFCore.utils import getToolByName
00011 from Products.CMFPlone import PloneMessageFactory as _
00012 from Products.CMFPlone.browser.navtree import getNavigationRoot
00013 from Products.CMFPlone.utils import safe_unicode
00014 from Products.PythonScripts.standard import url_quote
00015 from Products.PythonScripts.standard import url_quote_plus
00016 from Products.PythonScripts.standard import html_quote
00017 
00018 ploneUtils = getToolByName(context, 'plone_utils')
00019 portal_url = getToolByName(context, 'portal_url')()
00020 pretty_title_or_id = ploneUtils.pretty_title_or_id
00021 plone_view = context.restrictedTraverse('@@plone')
00022 
00023 portalProperties = getToolByName(context, 'portal_properties')
00024 siteProperties = getattr(portalProperties, 'site_properties', None)
00025 useViewAction = []
00026 if siteProperties is not None:
00027     useViewAction = siteProperties.getProperty('typesUseViewActionInListings', [])
00028 
00029 # SIMPLE CONFIGURATION
00030 USE_ICON = True
00031 USE_RANKING = False
00032 MAX_TITLE = 29
00033 MAX_DESCRIPTION = 93
00034 
00035 # generate a result set for the query
00036 catalog = context.portal_catalog
00037 
00038 friendly_types = ploneUtils.getUserFriendlyTypes()
00039 
00040 def quotestring(s):
00041     return '"%s"' % s
00042 
00043 def quote_bad_chars(s):
00044     bad_chars = ["(", ")"]
00045     for char in bad_chars:
00046         s = s.replace(char, quotestring(char))
00047     return s
00048 
00049 # for now we just do a full search to prove a point, this is not the
00050 # way to do this in the future, we'd use a in-memory probability based
00051 # result set.
00052 # convert queries to zctextindex
00053 
00054 # XXX really if it contains + * ? or -
00055 # it will not be right since the catalog ignores all non-word
00056 # characters equally like
00057 # so we don't even attept to make that right.
00058 # But we strip these and these so that the catalog does
00059 # not interpret them as metachars
00060 ##q = re.compile(r'[\*\?\-\+]+').sub(' ', q)
00061 for char in '?-+*':
00062     q = q.replace(char, ' ')
00063 r=q.split()
00064 r = " AND ".join(r)
00065 r = quote_bad_chars(r)+'*'
00066 searchterms = url_quote_plus(r)
00067 
00068 site_encoding = context.plone_utils.getSiteEncoding()
00069 if path is None:
00070     path = getNavigationRoot(context)
00071 results = catalog(SearchableText=r, portal_type=friendly_types, path=path)
00072 
00073 searchterm_query = '?searchterm=%s'%url_quote_plus(q)
00074 
00075 RESPONSE = context.REQUEST.RESPONSE
00076 RESPONSE.setHeader('Content-Type', 'text/xml;charset=%s' % site_encoding)
00077 
00078 # replace named entities with their numbered counterparts, in the xml the named ones are not correct
00079 #   ↓      --> ↓
00080 #   …    --> …
00081 legend_livesearch = _('legend_livesearch', default='LiveSearch ↓')
00082 label_no_results_found = _('label_no_results_found', default='No matching results found.')
00083 label_advanced_search = _('label_advanced_search', default='Advanced Search…')
00084 label_show_all = _('label_show_all', default='Show all…')
00085 
00086 ts = getToolByName(context, 'translation_service')
00087 
00088 output = []
00089 
00090 def write(s):
00091     output.append(safe_unicode(s))
00092 
00093 
00094 if not results:
00095     write('''<fieldset class="livesearchContainer">''')
00096     write('''<legend id="livesearchLegend">%s</legend>''' % ts.translate(legend_livesearch))
00097     write('''<div class="LSIEFix">''')
00098     write('''<div id="LSNothingFound">%s</div>''' % ts.translate(label_no_results_found))
00099     write('''<div class="LSRow">''')
00100     write('<a href="search_form" style="font-weight:normal">%s</a>' % ts.translate(label_advanced_search))
00101     write('''</div>''')
00102     write('''</div>''')
00103     write('''</fieldset>''')
00104 
00105 else:
00106     write('''<fieldset class="livesearchContainer">''')
00107     write('''<legend id="livesearchLegend">%s</legend>''' % ts.translate(legend_livesearch))
00108     write('''<div class="LSIEFix">''')
00109     write('''<ul class="LSTable">''')
00110     for result in results[:limit]:
00111 
00112         icon = plone_view.getIcon(result)
00113         itemUrl = result.getURL()
00114         if result.portal_type in useViewAction:
00115             itemUrl += '/view'
00116         itemUrl = itemUrl + searchterm_query
00117 
00118         write('''<li class="LSRow">''')
00119         if icon.url is not None and icon.description is not None:
00120             write('''<img src="%s" alt="%s" width="%i" height="%i" />''' % (icon.url,
00121                                                                             icon.description,
00122                                                                             icon.width,
00123                                                                             icon.height))
00124         full_title = safe_unicode(pretty_title_or_id(result))
00125         if len(full_title) > MAX_TITLE:
00126             display_title = ''.join((full_title[:MAX_TITLE],'...'))
00127         else:
00128             display_title = full_title
00129         full_title = full_title.replace('"', '&quot;')
00130         write('''<a href="%s" title="%s">%s</a>''' % (itemUrl, full_title, display_title))
00131         write('''<span class="discreet">[%s%%]</span>''' % result.data_record_normalized_score_)
00132         display_description = safe_unicode(result.Description)
00133         if len(display_description) > MAX_DESCRIPTION:
00134             display_description = ''.join((display_description[:MAX_DESCRIPTION],'...'))
00135         # need to quote it, to avoid injection of html containing javascript and other evil stuff
00136         display_description = html_quote(display_description)
00137         write('''<div class="discreet" style="margin-left: 2.5em;">%s</div>''' % (display_description))
00138         write('''</li>''')
00139         full_title, display_title, display_description = None, None, None
00140 
00141     write('''<li class="LSRow">''')
00142     write( '<a href="search_form" style="font-weight:normal">%s</a>' % ts.translate(label_advanced_search))
00143     write('''</li>''')
00144 
00145     if len(results)>limit:
00146         # add a more... row
00147         write('''<li class="LSRow">''')
00148         write( '<a href="%s" style="font-weight:normal">%s</a>' % ('search?SearchableText=' + searchterms, ts.translate(label_show_all)))
00149         write('''</li>''')
00150     write('''</ul>''')
00151     write('''</div>''')
00152     write('''</fieldset>''')
00153 
00154 return '\n'.join(output).encode(site_encoding)
00155