changeset 186:be3fff614b93

Implement #66; use jQuery UI autocomplete widget to replace obsolete jquery-autocomplete plugin. I implemented a very simple caching system.
author Brian Neal <bgneal@gmail.com>
date Tue, 30 Mar 2010 01:30:32 +0000
parents afb65fa947f1
children a9ea104f49ed
files gpp/core/views.py gpp/core/widgets.py gpp/settings.py
diffstat 3 files changed, 49 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/core/views.py	Sun Mar 28 23:25:10 2010 +0000
+++ b/gpp/core/views.py	Tue Mar 30 01:30:32 2010 +0000
@@ -4,12 +4,12 @@
 """
 from django.contrib.auth.models import User
 from django.http import HttpResponse
-from django.http import HttpResponseBadRequest
-from django.http import HttpResponseForbidden
 from django.shortcuts import render_to_response
 from django.template import RequestContext
 from django.contrib.auth.decorators import login_required
 from django.views.decorators.http import require_GET
+import django.utils.simplejson as json
+
 
 @login_required
 @require_GET
@@ -23,20 +23,16 @@
 
 def ajax_users(request):
     """
-    If the user is authenticated, return a string of usernames whose names start with
-    the 'q' GET parameter, limited by the 'limit' GET parameters. The names are separated
-    by newlines. Only active usernames are returned.
-    If the user is not authenticated, return an empty string.
+    If the user is authenticated, return a JSON array of strings of usernames 
+    whose names start with the 'q' GET parameter, limited by the 'limit' GET 
+    parameter. Only active usernames are returned.
+    If the user is not authenticated, return an empty array.
     """
     q = request.GET.get('q', None)
-    if q is None:
-        return HttpResponseBadRequest()
+    if q is None or not request.user.is_authenticated():
+        return HttpResponse(json.dumps([]), content_type='application/json')
 
-    if request.user.is_authenticated():
-        q = request.GET.get('q', ' ')
-        limit = int(request.GET.get('limit', 10))
-        users = User.objects.filter(is_active=True, 
-                username__istartswith=q).values_list('username', flat=True)[:limit]
-        user_list = u"\n".join(users)
-        return HttpResponse(user_list)
-    return HttpResponseForbidden()
+    limit = int(request.GET.get('limit', 10))
+    users = User.objects.filter(is_active=True, 
+            username__istartswith=q).values_list('username', flat=True)[:limit]
+    return HttpResponse(json.dumps(list(users)), content_type='application/json')
--- a/gpp/core/widgets.py	Sun Mar 28 23:25:10 2010 +0000
+++ b/gpp/core/widgets.py	Tue Mar 30 01:30:32 2010 +0000
@@ -9,26 +9,47 @@
 
 
 class AutoCompleteUserInput(forms.TextInput):
-    class Media:
-        css = {
-            'all': settings.GPP_THIRD_PARTY_CSS['jquery-autocomplete'],
-        }
-        js = settings.GPP_THIRD_PARTY_JS['jquery-autocomplete']
 
     def render(self, name, value, attrs=None):
         url = reverse('core-ajax_users')
         output = super(AutoCompleteUserInput, self).render(name, value, attrs)
-        return output + mark_safe(u'''\
+        return output + mark_safe(u"""\
 <script type="text/javascript">
-jQuery("#id_%s").autocomplete("%s", {
-    width: 150,
-    max: 10,
-    highlight: false,
-    multiple: false,
-    scroll: true,
-    scrollHeight: 300,
-    matchContains: true,
-    autoFill: true
+$(function() {
+    var cache = {};
+    var cacheSize = 0;
+    $("#id_%s").autocomplete({
+        delay: 400,
+        minLength: 2,
+        source: function(request, response) {
+            if (cache[request.term]) {
+               response(cache[request.term]);
+               return;
+            }
+            $.ajax({
+                url: "%s",
+                type: "GET",
+                data: {
+                    q: request.term,
+                    limit: 10
+                },
+                dataType: "json",
+                success: function(data, textStatus) {
+                    if (cacheSize >= 16) {
+                       cache = {};
+                       cacheSize = 0;
+                    }
+                    cache[request.term] = data;
+                    ++cacheSize;
+                    response(data);
+                },
+                error: function(xhr, textStatus, ex) {
+                    alert('Oops, an error occurred. ' + xhr.statusText + ' - ' +
+                      xhr.responseText);
+                }
+            });
+        }
+    });
 });
-</script>''' % (name, url))
+</script>""" % (name, url))
 
--- a/gpp/settings.py	Sun Mar 28 23:25:10 2010 +0000
+++ b/gpp/settings.py	Tue Mar 30 01:30:32 2010 +0000
@@ -219,11 +219,6 @@
     'jquery': (
         'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js',
     ),
-    'jquery-autocomplete': (
-        'js/jquery-autocomplete/lib/jquery.bgiframe.min.js',
-        'js/jquery-autocomplete/lib/jquery.ajaxQueue.js',
-        'js/jquery-autocomplete/jquery.autocomplete.js',
-    ),
     'jquery-jeditable': (
         'js/jquery.jeditable.mini.js',
     ),
@@ -243,9 +238,6 @@
     'jquery-ui': (
         'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/themes/redmond/jquery-ui.css',
     ),
-    'jquery-autocomplete': (
-        'js/jquery-autocomplete/jquery.autocomplete.css',
-    ),
     'markitup': (
         'js/markitup/skins/markitup/style.css',
         'js/markitup/sets/markdown/style.css',