Commits

Germano Gabbianelli committed c189687

initial files

Comments (0)

Files changed (10)

ac_example/__init__.py

Empty file added.

ac_example/admin.py

+from django.contrib import admin
+from django.contrib.auth.models import Message
+from actest.acapp import forms
+
+class MessageAdmin(admin.ModelAdmin):
+    form = forms.InsertMessage
+    fields = ('user', 'message')
+
+admin.site.register(Message, MessageAdmin)

ac_example/forms.py

+from django import forms
+
+from django.contrib.auth.models import User, Message
+from autocomplete.widgets import ModelAutoComplete
+
+class InsertMessage(forms.ModelForm):
+    class Meta:
+        model = Message
+
+    user = forms.ModelChoiceField(User.objects.all(),
+            widget=ModelAutoComplete('user'))

ac_example/templates/autocomplete.html

+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+  <head>
+    <title>AutoComplete Test</title>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8">
+    {{ form.media }}
+    <style type="text/css">
+    .yui-ac {
+        display: block;
+        width:40em; /* set width here or else widget will expand to fit its container */
+        padding-bottom:2em;
+      }
+    </style>
+  </head>
+  <body class="yui-skin-sam">
+    <form method="POST">
+      <table>
+      {{ form.as_table }}
+      </table>
+      <input type="submit" />
+    </form>
+  </body>
+</html>

ac_example/urls.py

+from django.conf.urls.defaults import *
+
+from django.contrib.auth.models import User
+from autocomplete import ac
+
+info_dict = {
+    'settings': {
+        'user': ac(User.objects.all(), ('username', 'email'), 5),
+    },
+    'query_param': 'query',
+}
+
+urlpatterns = patterns('',
+    url('^autocomplete/(\w+)/$', 'autocomplete.views.autocomplete', info_dict,
+        name='autocomplete'),
+    url('^example/$', 'actest.acapp.views.example'),
+)

ac_example/views.py

+from django.http import HttpResponse
+from django.shortcuts import render_to_response
+
+from ac_example.forms import InsertMessage
+
+def example(request):
+    if request.method == 'POST':
+        form = InsertMessage(request.POST)
+        if form.is_valid():
+            return HttpResponse("yo!")
+    else:
+        form = InsertMessage()
+
+    return render_to_response("autocomplete.html", {'form':form})

autocomplete/__init__.py

+from django.utils.encoding import smart_unicode
+
+def ac(queryset, fields, limit=None, key='pk', label=lambda obj: smart_unicode(obj), auth=False):
+    return (queryset, fields, limit, key, label, auth)
+autocomplete = ac

autocomplete/media/js/autocomplete.js

+
+function yui_autocomplete(name, ac_url) {
+    YAHOO.util.Event.onDOMReady(function () {
+        var datasource = new YAHOO.util.XHRDataSource(ac_url);
+        datasource.responseType = YAHOO.util.XHRDataSource.TYPE_JSON;
+        datasource.responseSchema = {
+            resultsList: "result",
+            fields: ["label", "id"]
+        };
+
+        datasource.doBeforeParseData = function (request, original, callback) {
+            var parsed = {"result": []};
+            for (var i in original)
+                parsed.result.push({"id": original[i][0], "label": original[i][1]});
+            return parsed;
+        }
+        datasource.resultTypeList = false;
+
+        var select = document.getElementById("id_"+name);
+        var input = document.getElementById("id_ac_"+name);
+
+        YAHOO.util.Dom.addClass(input.parentNode, "yui-ac");
+
+        select.style.display = "none";
+        input.style.display = "block";
+
+        var container = document.createElement("div");
+        YAHOO.util.Dom.insertAfter(container, input);
+
+        var autocomplete = new YAHOO.widget.AutoComplete(input, container, datasource);
+        autocomplete.resultTypeList = false;
+        autocomplete.queryDelay = .5;
+
+        autocomplete.itemSelectEvent.subscribe(function (type, args) {
+            var item = args[2];
+            select.value = item.id;
+        });
+    });
+}
+
+autocomplete = yui_autocomplete;

autocomplete/views.py

+from django.http import HttpResponse
+from django.db.models import Q
+from django.utils import simplejson
+
+AUTOCOMPLETE_NOTFOUND = HttpResponse(status=404)
+AUTOCOMPLETE_FORBIDDEN = HttpResponse(status=403)
+
+def autocomplete(request, ac_name, settings={}, query_param='query'):
+    if not settings.get(ac_name):
+        return AUTOCOMPLETE_NOTFOUND
+
+    qs, fields, limit, key, label, auth = settings[ac_name]
+    if auth and not request.user.is_authenticated():
+        return AUTOCOMPLETE_FORBIDDEN
+    query = request.GET.get(query_param, '')
+    
+    filter = Q()
+    for field in fields:
+        if not '__' in field:
+            field = '%s__startswith' % field
+        filter |= Q(**{field: query})
+    
+    qs = qs.filter(filter)[:limit]
+    
+    if isinstance(label, basestring):
+        if key == 'pk':
+            key = qs.model._meta.pk.attname
+        result = list(qs.values_list(key, label))
+    else:
+        result = []
+        for obj in qs:
+            result.append((getattr(obj, key), label(obj)))
+    return HttpResponse(simplejson.dumps(result),
+            mimetype='application/json')

autocomplete/widgets.py

+from django import forms
+from django.utils.safestring import mark_safe
+from django.core.urlresolvers import reverse
+
+
+# FIXME not ready for admin edit page, need ac_id_%(name)s prefill (2 line of js).
+
+class ModelAutoComplete(forms.Select):
+
+    class Media:
+        css = {'all':
+            ("http://yui.yahooapis.com/2.6.0/build/autocomplete/assets/skins/sam/autocomplete.css",)
+        }
+        js = ('http://yui.yahooapis.com/combo'
+              '?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js'
+              '&2.6.0/build/animation/animation-min.js'
+              '&2.6.0/build/connection/connection-min.js'
+              '&2.6.0/build/datasource/datasource-min.js'
+              '&2.6.0/build/autocomplete/autocomplete-min.js',
+              'js/autocomplete.js')
+
+    def __init__(self, ac_name, attrs=None, view_name='autocomplete'):
+        super(ModelAutoComplete, self).__init__(attrs, ())
+        self.ac_name = ac_name
+        self.view_name = view_name
+    
+    def render(self, name, value, attrs=None, choices=()):
+        output = [super(ModelAutoComplete, self).render(name, value, attrs, choices)]
+        output.append(u'<input type="text" id="id_ac_%s" style="display:none" />\n' % (name))
+        output.append(u'<script type="text/javascript">autocomplete("%s", "%s");</script>\n' %
+            (name, reverse(self.view_name, args=[self.ac_name])))
+        return mark_safe(u''.join(output))
+