#----------------------- widgets.py------------------------
# -*- coding: utf-8 -*-
# 
# In order to use this widget you need:
# 1. download YUI library and put it in 
#    your MEDIA folder (http://developer.yahoo.com/yui/)
# 2. Include necessary js and css imports at your page
#    Check for necessary imports at 'YUI autocomplete' page
#    My imports are visible at test_ajax.html
# 3. Assign a widget to field (with schema and lookup_url parameters)
# 4. Define view to do a data lookup for ajax queries
#
from django import newforms as forms
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode 

#AUTOCOMPLETE
AC_SNIPPET = """
<div class="ac_container">
    <input %s />
    <div id="%s_container" class="yui-skin-sam"></div>

    <script type="text/javascript">
        // An XHR DataSource
        var acServer_%s = "%s";
        var acSchema_%s = %s;
        var acDataSource_%s = new YAHOO.widget.DS_XHR(acServer_%s, acSchema_%s);
        var acAutoComp_%s = new YAHOO.widget.AutoComplete("%s","%s_container", acDataSource_%s);
        acAutoComp_%s.useIFrame = true;
        acAutoComp_%s.animSpeed = 0;
        %s
        %s
    </script>
</div>
"""

def_format_result = 'acAutoComp_%s.formatResult = %s;'
def_item_select_handler = 'acAutoComp_%s.itemSelectEvent.subscribe(%s);'

class AutoCompleteWidget(forms.widgets.TextInput):
    """ widget autocomplete for text fields
    """
    
    def __init__(self, 
                 schema=None, 
                 lookup_url=None, 
                 format_result_fname='', 
                 item_select_handler_fname='', 
                 *args, **kw):
        super(AutoCompleteWidget, self).__init__(*args, **kw)
        # YUI schema
        self.schema = schema
        # url for YUI XHR Datasource
        self.lookup_url = lookup_url
        # optional name of javascript function that formats results (YUI)
        self.format_result_fname = format_result_fname 
        # optional name of javascript function that handles item select event (YUI)
        self.item_select_handler_fname = item_select_handler_fname

    def render(self, name, value, attrs=None):
        html_id = attrs.get('id', name)
        # url for YUI XHR Datasource
        lookup_url = self.lookup_url
        # YUI schema
        schema = self.schema
        # optional name of javascript function that handles item select event (YUI)
        item_select_handler_fname = getattr(self, 'item_select_handler_fname', '')
        # optional name of javascript function that formats results (YUI)
        format_result_fname = getattr(self, 'format_result_fname', '')        

        if value is None: value = ''
        final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
        if value != '': final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
        final_attrs['class'] = 'autocomplete_widget'

        fr = '' # format result
        sh = '' # select handler
        if self.format_result_fname:
            fr = def_format_result % (html_id, self.format_result_fname)
        if self.item_select_handler_fname:
            sh = def_item_select_handler % (html_id,
                                            self.item_select_handler_fname)

        return mark_safe(AC_SNIPPET % (forms.util.flatatt(final_attrs), html_id, html_id,
                             lookup_url,html_id, schema, html_id, html_id,
                             html_id, html_id, html_id, html_id,
                             html_id,html_id, html_id, fr, sh))
#/AUTOCOMPLETE
#/----------------------- widgets.py------------------------




#
#EXAMPLE APPLICATION: ---------------------------------------
#
# code below is a listing of files from example application 
# that uses AutocompleteWidget, you don't have to create these
# files! Only thing you need to put into your application 
# is code from above: widgets.py


#----------------------- test_ajax.html -------------------
<html>
<head>
  <!-- yui -->
  <link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}base/js/yui/assets/skins/sam/autocomplete.css" />
  <script type="text/javascript" src="{{ MEDIA_URL }}base/js/yui/utilities/utilities.js"></script>
  <script type="text/javascript" src="{{ MEDIA_URL }}base/js/yui/autocomplete/autocomplete-min.js"></script>
  <script type="text/javascript" src="{{ MEDIA_URL }}base/js/yui/datasource/datasource-beta-min.js"></script>
<!-- /yui-->  
</head>
<body>
  <div class="yui-skin-sam">
    <form>
    {{ user_form.as_p }}
    </form>
  </div>
</body>
</html>
#/----------------------- test_ajax.html -------------------


#----------------------- views.py------------------------
# -*- coding: utf-8 -*-
from <SOMEWHERE: http://www.djangosnippets.org/snippets/154/> import JsonResponse

from django.contrib.auth.models import User
from django.template import RequestContext
import django.db.models
from django.shortcuts import render_to_response
from django import newforms as forms
from widgets import AutoCompleteWidget

def test_ajax_ac(request):
    """ returns data displayed at autocomplete list - this function is accessed by AJAX calls
    """
    limit = 10
    query = request.GET.get('query', None)
    qargs = []
    # it is up to you how query looks
    if query:
        qargs = [django.db.models.Q(first_name__startswith=query) | \
                 django.db.models.Q(last_name__startswith=query) | \
                 django.db.models.Q(email__startswith=query)]
    users = User.objects.filter(django.db.models.Q(*qargs)).order_by('first_name')[:limit]
    results = []
    for user in users:
        results.append({'id':user.pk,
                        'name':user.get_full_name(),
                        'email':user.email})
    ret_dict = {'resultset':{'totalResultsReturned':len(results),
                             'results':results}}
    return JsonResponse(ret_dict)


class UserForm(forms.Form):
    username = forms.CharField(max_length=100)
    
    def __init__(self, *args, **kwargs):
        super(UserForm, self).__init__(*args, **kwargs)
        
        n_lookup_url = reverse('test_ajax_ac')  
        n_schema = '["resultset.results", "name", "email"]'
        self.fields['username'].widget = \
                      AutoCompleteWidget(lookup_url = n_lookup_url,
                                         schema = n_schema)
        

def test_ajax(request):
    """ Displays user form
    """
    user_form = UserForm()
    return render_to_response('test_ajax.html',
                              {'user_form':user_form},
                              context_instance=RequestContext(request))
#/----------------------- views.py------------------------

#------------------------ urls.py-------------------------
from django.conf.urls.defaults import *
from django.conf import settings

urlpatterns = patterns('views',
    url(r'^test_ajax/$', 'test_ajax', name='test_ajax'),
    url(r'^test_ajax_ac/$', 'test_ajax_ac', name='test_ajax_ac'),
)
#/------------------------ urls.py-------------------------