[Checkins] SVN: jquery.livesearch/ Implemented JQuery based live search

Roger Ineichen roger at projekt01.ch
Fri May 25 02:11:38 EDT 2007


Log message for revision 75953:
  Implemented JQuery based live search

Changed:
  A   jquery.livesearch/branches/
  A   jquery.livesearch/tags/
  A   jquery.livesearch/trunk/
  A   jquery.livesearch/trunk/src/
  A   jquery.livesearch/trunk/src/jquery/
  A   jquery.livesearch/trunk/src/jquery/livesearch/
  A   jquery.livesearch/trunk/src/jquery/livesearch/SETUP.cfg
  A   jquery.livesearch/trunk/src/jquery/livesearch/__init__.py
  A   jquery.livesearch/trunk/src/jquery/livesearch/browser.py
  A   jquery.livesearch/trunk/src/jquery/livesearch/configure.zcml
  A   jquery.livesearch/trunk/src/jquery/livesearch/interfaces.py
  A   jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch-configure.zcml
  A   jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.css
  A   jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.js
  A   jquery.livesearch/trunk/src/jquery/livesearch/json.pt
  A   jquery.livesearch/trunk/src/jquery/livesearch/json.py
  A   jquery.livesearch/trunk/src/jquery/livesearch/json.zcml.sample
  A   jquery.livesearch/trunk/src/jquery/livesearch/result.py
  A   jquery.livesearch/trunk/src/jquery/livesearch/template.pt

-=-
Added: jquery.livesearch/trunk/src/jquery/livesearch/SETUP.cfg
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/SETUP.cfg	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/SETUP.cfg	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+  jquery.livesearch-*.zcml
+</data-files>

Added: jquery.livesearch/trunk/src/jquery/livesearch/__init__.py
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/__init__.py	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/__init__.py	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,16 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""

Added: jquery.livesearch/trunk/src/jquery/livesearch/browser.py
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/browser.py	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/browser.py	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,23 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+
+from zope.viewlet import viewlet
+
+
+LiveSearchJavaScriptViewlet = viewlet.JavaScriptViewlet('jquery.livesearch.js')
+
+LiveSearchCSSViewlet = viewlet.CSSViewlet('jquery.livesearch.css')

Added: jquery.livesearch/trunk/src/jquery/livesearch/configure.zcml
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/configure.zcml	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/configure.zcml	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,17 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:z3c="http://namespaces.zope.org/z3c"
+    i18n_domain="jquery">
+
+  <adapter
+      for="zope.interface.Interface"
+      factory="jquery.livesearch.result.LiveSearchResultItem"
+      />
+
+  <!-- page template for Live Search result -->
+  <z3c:template
+      template="json.pt"
+      for="jquery.livesearch.interfaces.IJSONLiveSearch"
+      />
+
+</configure>

Added: jquery.livesearch/trunk/src/jquery/livesearch/interfaces.py
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/interfaces.py	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/interfaces.py	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,47 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+
+
+class ILiveSearch(zope.interface.Interface):
+    """Live search interface."""
+
+    def getResults():
+        """Returns the catalog search result."""
+
+
+class IJSONLiveSearch(ILiveSearch):
+    """JSON live search interface."""
+
+    def getLiveSearchResult(searchString, searchId):
+        """Return a list of live search items."""
+
+
+class ILiveSearchResultItem(zope.interface.Interface):
+    """Live search result item is responsible for the presentation."""
+
+    def getURL(request):
+        """Returns the url used for rendering the link."""
+
+    def getText():
+        """Returns the test used for rendering the link text."""
+
+    def getScore(score):
+        """Returns the formatted score form the given catalog score."""
+

Added: jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch-configure.zcml
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch-configure.zcml	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch-configure.zcml	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1 @@
+<include package="jquery.livesearch" />

Added: jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.css
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.css	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.css	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,53 @@
+#liveSearch {
+    margin : 0;
+    padding : 0;
+}
+
+#liveSearchInput {
+    width: 200px;
+    vertical-align : middle;
+    border: #A7A78B solid 1px;
+}
+
+#liveSearchSubmit {
+    vertical-align : middle;
+}
+
+#liveSearchResult {
+    position: relative;
+    width: 200px;
+    border: #A7A78B solid 1px;
+    margin-top: 5px;
+}
+
+#liveSearchResult a {
+    color: #666;
+}
+
+#liveSearchResult .even {
+	background-color: #F3F3EE;
+    padding: 2px;
+}
+
+#liveSearchResult .odd {
+	background-color: #E4E4DA;
+    padding: 2px;
+}
+
+#liveSearchResult .left {
+    width: 140px;
+    text-align: left;
+    padding : 0;
+}
+
+#liveSearchResult .right {
+    float: right;
+    padding : 0;
+}
+	
+div.hideLiveSearchResult {
+	height: 18px;
+    text-align: right;
+	background-color: #F3F3EE;
+	padding: 2px;
+}

Added: jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.js
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.js	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/jquery.livesearch.js	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,66 @@
+//----------------------------------------------------------------------------
+/** 
+ * @fileoverview JSON-RPC based live search implementation
+ * @author Roger Ineichen dev at projekt01 dot ch
+ * @version Initial, not documented 
+ */
+//----------------------------------------------------------------------------
+
+function setLiveSearchResult(response) {
+    // we use a default element id, use a custom callback if this doesn't fit
+    ele = $('#liveSearchResultContainer');
+    if (response.content != null) {
+        $(ele).html(response.content)
+        $(ele).show('fast')
+    } else {
+        $(ele).hide('fast')
+    }
+}
+
+function closeLiveSearchResult(id) {
+    $('#'+id).hide();
+}
+
+//----------------------------------------------------------------------------
+// public API
+//----------------------------------------------------------------------------
+/**
+ * apply live search functionality. *
+ * @name     jsonLiveSearch
+ * @name     json live search with callback
+ * @param    settings Hash with the following options:
+ *               jsonURL   The url where the json view getLiveSearchResult is available
+ *               minQueryLenght The min length of the query string before we call json search
+ *               resultElementExpression The xpath expresseion for get the result element
+ *               requestId The is passed to the server via json, can be used for identify a search wquery
+ *               searchMethodName The json search method name, can be used if you need to call different json views
+ *               callback  The callback function which get called within the response as argument
+ * @author   Roger Ineichen dev - projekt01 - ch
+ * @example  $("#myInputField").jsonLiveSearch();
+ * @example  $("#myInputField").jsonLiveSearch({url:'http://localhost/page'});
+ * @example  $("#myInputField").jsonLiveSearch({url:'http://localhost/page', callback:setLiveSearchResult});
+ */
+jQuery.fn.jsonLiveSearch = function(settings) {
+    settings = jQuery.extend({
+        jsonURL: contextURL,
+        minQueryLenght: 2,
+        resultElementExpression: '#liveSearchResultContainer',
+        requestId: 'jsonLiveSearch',
+        searchMethodName: 'getLiveSearchResult',
+        callback: setLiveSearchResult
+    }, settings);
+    return this.each(function(){
+        $(this).keyup(function(){
+        	value = $(this).val();
+        	if (value != '' && value.length >= settings.minQueryLenght) {
+            	var proxy = getJSONRPCProxy(settings.jsonURL);
+            	proxy.addMethod(settings.searchMethodName, settings.callback, settings.requestId);
+            	proxy[settings.searchMethodName](value);
+            }else {
+                $(settings.resultElementExpression).hide();
+            }
+        });
+
+    });
+};
+

Added: jquery.livesearch/trunk/src/jquery/livesearch/json.pt
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/json.pt	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/json.pt	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,21 @@
+<div id="liveSearchResult">
+  <div class="hideLiveSearchResult">
+    <a href="javascript:closeLiveSearchResult('liveSearchResultContainer');">x</a>
+  </div>
+  <tal:block repeat="info view/results">
+    <div tal:define="oddrow repeat/info/odd;
+                     url info/url"
+         tal:attributes="class python:oddrow and 'even' or 'odd'" >
+      <div class="right">
+        <a href=""
+         tal:attributes="href info/url"
+         tal:content="info/score" />
+      </div>
+      <div class="left">
+        <a href=""
+         tal:attributes="href string:${info/url}/@@SelectedManagementView.html"
+         tal:content="info/text" />
+      </div>
+    </div>
+  </tal:block>
+</div>

Added: jquery.livesearch/trunk/src/jquery/livesearch/json.py
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/json.py	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/json.py	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,85 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+
+import zope.component
+import zope.interface
+from zope.pagetemplate.interfaces import IPageTemplate
+from zope.app.catalog.interfaces import ICatalog
+from zope.app.intid.interfaces import IIntIds
+
+from z3c.template.template import getPageTemplate
+from zif.jsonserver.jsonrpc import MethodPublisher
+from zif.jsonserver.interfaces import IJSONRPCRequest
+
+from jquery.livesearch import interfaces
+from jquery.livesearch.result import LiveSearchResult
+
+
+class JSONLiveSearch(MethodPublisher):
+    """JSON live search method with template for rendering the result."""
+
+    zope.interface.implements(interfaces.IJSONLiveSearch)
+    zope.component.adapts(zope.interface.Interface, IJSONRPCRequest)
+
+    # get the registered IPageTemplate template
+    template = getPageTemplate()
+    indexName = 'TextIndex'
+    jsonID = None # the json request id set in the javascript
+
+    def __init__(self, context, request):
+        super(JSONLiveSearch, self).__init__(context, request)
+        self.searchString = None
+        self.results = ()
+
+    def getCatalog(self):
+        """Returns the right catalog."""
+        return zope.component.getUtility(ICatalog)
+
+    def getLiveSearchResult(self, searchString):
+        """Returns JSON like dict/array containing a content attribute with the 
+        search result.
+        """
+        self.jsonID = self.request.jsonID
+        self.doSearch(searchString)
+        # return None for content variable if no result was found. This will 
+        # intepreted via JSON as null in javascript.
+        if len(self.results) == 0:
+            return {'content':None}
+        # render template only if result was found
+        else:
+            return {'content':self.render()}
+
+    def doSearch(self, searchString):
+        """Search the catalog for items and set the results."""
+        catResults = None
+        if searchString is not None:
+            catalog = self.getCatalog()
+            liveSearchString = searchString + '*'
+            if liveSearchString.strip('* ') != '':
+                catResults = catalog.apply({self.indexName:liveSearchString})
+        if catResults is not None:
+            uidutil = zope.component.getUtility(IIntIds)
+            self.results = LiveSearchResult(catResults, uidutil, self.request)
+
+    def getResults(self):
+        return self.results
+
+    def render(self):
+        # render live search results
+        template = zope.component.getMultiAdapter((self, self.request), 
+            IPageTemplate)
+        return template(self)

Added: jquery.livesearch/trunk/src/jquery/livesearch/json.zcml.sample
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/json.zcml.sample	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/json.zcml.sample	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,13 @@
+<configure 
+    xmlns:zope="http://namespaces.zope.org/zope"
+    xmlns:jsonrpc="http://namespaces.zope.org/jsonrpc"
+    i18n_domain="jquery">
+
+  <jsonrpc:view
+      for="*"
+      class="jquery.livesearch.json.JSONLiveSearch"
+      permission="zope.Public"
+      methods="getLiveSearchResult"
+      />
+
+</configure>
\ No newline at end of file

Added: jquery.livesearch/trunk/src/jquery/livesearch/result.py
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/result.py	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/result.py	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,83 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id: layer.py 197 2007-04-13 05:03:32Z rineichen $
+"""
+
+import zope.interface
+from zope.traversing import api
+from zope.traversing.browser import absoluteURL
+from zope.security.interfaces import Unauthorized
+from zope.security.proxy import removeSecurityProxy
+
+from jquery.livesearch import interfaces
+
+
+class LiveSearchResultItem(object):
+    """Live search result item presentation."""
+
+    zope.interface.implements(interfaces.ILiveSearchResultItem)
+
+    def __init__(self, context):
+        """Adatps the object and offers live search result infos.
+        
+        You need to implement this adapter for your searchable objects.
+        """
+        self.context = context
+
+    def getURL(self, request):
+        return absoluteURL(self.context, request)
+
+    def getText(self):
+        """Returns the test used for rendering the link text."""
+        try:
+            title = getattr(self.context, 'title', None)
+        except Unauthorized:
+            title = None
+
+        if title is None:
+            title = api.getName(self.context)
+
+        return title or u''
+
+    def getScore(self, score):
+        """Returns the score."""
+        return "%.4f" % score
+
+
+class LiveSearchResult:
+    """Lazily accessed set of object infos."""
+
+    def __init__(self, results, uidutil, request):
+        self.results = results
+        self.uidutil = uidutil
+        self.request = request
+
+    def __len__(self):
+        return len(self.results)
+
+    def __iter__(self):
+        for uid, score in self.results.items():
+            info = {}
+            obj = self.uidutil.getObject(uid)
+            obj = removeSecurityProxy(obj)
+            adapter = interfaces.ILiveSearchResultItem(obj)
+            info['obj'] = obj
+            info['text'] = adapter.getText()
+            info['score'] = adapter.getScore(score)
+            info['url'] = adapter.getURL(self.request)
+            yield info
+
+
+

Added: jquery.livesearch/trunk/src/jquery/livesearch/template.pt
===================================================================
--- jquery.livesearch/trunk/src/jquery/livesearch/template.pt	                        (rev 0)
+++ jquery.livesearch/trunk/src/jquery/livesearch/template.pt	2007-05-25 06:11:38 UTC (rev 75953)
@@ -0,0 +1,24 @@
+<metal:block define-macro="livesearch">
+	<table class="navibox" width="100%"  border="0" cellspacing="0" cellpadding="0">
+		<tr>
+			<th nowrap>
+				<img class="icon" src="../../browser/img/navibox_edge.gif" border="0" width="17" height="22"
+						 tal:attributes="src context/++resource++navibox_edge.gif" />
+				<div class="header"> 
+					<div class="title" i18n:translate="">Live Search</div>
+				</div>
+			</th>
+		</tr>
+		<tr>
+			<td>
+			<div id="liveSearch">
+				<form id="liveSearchForm" name="liveSearchForm" action="livesearch_result.html" method="post">
+				<input id="liveSearchInput" type="text" name="searchableText" onKeyPress="startLiveSearch()" />
+				<input id="liveSearchSubmit" type="submit" name="SUBMIT_SEARCH" value="Search" />
+				</form>
+				<div id="liveSearchResult" style="display: none;"></div>
+			</div>
+			</td>
+		</tr>
+	</table>
+</metal:block>



More information about the Checkins mailing list