diff options
| -rw-r--r-- | chimere/forms.py | 8 | ||||
| -rw-r--r-- | chimere/models.py | 5 | ||||
| -rw-r--r-- | chimere/templates/chimere/blocks/JQueryAutoComplete.html | 57 | ||||
| -rw-r--r-- | chimere/urls.py | 3 | ||||
| -rw-r--r-- | chimere/views.py | 22 | ||||
| -rw-r--r-- | chimere/widgets.py | 69 | 
6 files changed, 158 insertions, 6 deletions
diff --git a/chimere/forms.py b/chimere/forms.py index 599f88a..ae0092f 100644 --- a/chimere/forms.py +++ b/chimere/forms.py @@ -393,9 +393,15 @@ def get_properties(queryset):                  label=prop.name, choices=[('', '--')] +                  [(choice.pk, unicode(choice)) for choice in choices],                  required=False) +        elif prop.type == 'A': +            widget = PropertyModel.TYPE_WIDGET[prop.type] +            widget = widget(slug=prop.slug) +            fields[key] = forms.CharField(label=prop.name, widget=widget, +                                          required=False)          else: +            widget = PropertyModel.TYPE_WIDGET[prop.type]              fields[key] = forms.CharField( -                label=prop.name, widget=PropertyModel.TYPE_WIDGET[prop.type], +                label=prop.name, widget=widget,                  required=False)      return fields diff --git a/chimere/models.py b/chimere/models.py index d16d20a..9e7e52f 100644 --- a/chimere/models.py +++ b/chimere/models.py @@ -44,7 +44,8 @@ from django.template import defaultfilters  from django.utils.translation import ugettext_lazy as _  from chimere.widgets import HiddenPointChooserWidget, PointField, RouteField, \ -    SelectMultipleField, TextareaWidget, DatePickerWidget, PolygonField +    SelectMultipleField, TextareaWidget, DatePickerWidget, PolygonField, \ +    JQueryAutoComplete  from chimere.utils import KMLManager, OSMManager, ShapefileManager, \      GeoRSSManager, CSVManager, HtmlXsltManager, XMLXsltManager, JsonManager, \      IcalManager @@ -1954,6 +1955,7 @@ class PropertyModel(models.Model):              ('P', _('Password')),              ('D', _("Date")),              ('C', _("Choices")), +            ('A', _("Choices (autocomplete)")),              ('B', _("Boolean")),              )      TYPE_WIDGET = {'T': forms.TextInput, @@ -1961,6 +1963,7 @@ class PropertyModel(models.Model):                     'P': forms.PasswordInput,                     'D': DatePickerWidget,                     'C': forms.Select, +                   'A': JQueryAutoComplete,                     'B': forms.CheckboxInput,                     }      type = models.CharField(_(u"Type"), max_length=1, choices=TYPE) diff --git a/chimere/templates/chimere/blocks/JQueryAutoComplete.html b/chimere/templates/chimere/blocks/JQueryAutoComplete.html new file mode 100644 index 0000000..c316869 --- /dev/null +++ b/chimere/templates/chimere/blocks/JQueryAutoComplete.html @@ -0,0 +1,57 @@ +<input{{attrs_select|safe}}/> +<input type="hidden"{{attrs_hidden|safe}}/> +        <script type="text/javascript"><!--// + +$(function() { +    $('#id_select_{{field_id}}').autocomplete({ +        autoFocus: true, +        source:{{source|safe}}, +        select: function (event, ui){ +            if(ui.item){ +                $('#id_{{field_id}}').val(ui.item.id); +            } else { +                $('#id_{{field_id}}').val(null); +                $('#id_select_{{field_id}}').val(''); +            } +        }, +        minLength: 2, +        change: function (event, ui){ +            if(ui.item){ +                $('#id_{{field_id}}').val(ui.item.id); +            } else { +                $('#id_{{field_id}}').val(null); +                $('#id_select_{{field_id}}').val(''); +            } +        }, +        open: function(){ +            setTimeout(function () { +                $('.ui-autocomplete').css('z-index', 1000); +            }, 0); +        }{% if options %}, +        {{options}}{% endif %} +    }); + +    $('#id_select_{{field_id}}').on('click', function(){ +        $('#id_{{field_id}}').val(null); +        $('#id_select_{{field_id}}').val(null); +    }); + +    $('body').on('click', function(){ +        if (!$('#id_{{field_id}}').val()) { +            $('#id_select_{{field_id}}').val(null); +        } +    }); + +    $('#id_select_{{field_id}}').on( "autocompletefocus", +                    function( event, ui ){ +                        disable_enter = true; +                    } ); + +    $('#id_select_{{field_id}}').on( "autocompleteselect", +                    function( event, ui ){ +                        disable_enter = false; +                    } ); + +}); +//--></script> + diff --git a/chimere/urls.py b/chimere/urls.py index de7f3f5..966ef4f 100644 --- a/chimere/urls.py +++ b/chimere/urls.py @@ -147,6 +147,9 @@ urlpatterns += patterns(      url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?categories/'          r'(?P<category_slug>[a-zA-Z0-9_-]+)$',          CategoryView.as_view(), name='category-directory-detail'), +    url(r'^(?:(?P<area_name>[a-zA-Z0-9_-]*)/)?property-choices/' +        r'(?P<property_slug>[a-zA-Z0-9_-]+)/$', +        'property_choice_list', name='property-choices'),      # At the end, because it catches large      url(r'^(?P<area_name>[a-zA-Z0-9_-]+)?', 'index', name="index"),  ) diff --git a/chimere/views.py b/chimere/views.py index 7274bf0..40db95a 100644 --- a/chimere/views.py +++ b/chimere/views.py @@ -47,7 +47,7 @@ from django.views.generic import TemplateView, ListView  from chimere.actions import actions  from chimere.models import Category, SubCategory, PropertyModel, Page,\      Marker, Route, Polygon, SimpleArea, Area, Color, TinyUrl, RouteFile,\ -    AggregatedRoute, AggregatedPolygon +    AggregatedRoute, AggregatedPolygon, PropertyModelChoice  from chimere.widgets import PointChooserWidget, RouteChooserWidget, AreaWidget,\      PolygonChooserWidget @@ -1264,6 +1264,26 @@ def rss(request, area_name=''):  # from django.core.paginator import Paginator, InvalidPage + +def property_choice_list(request, area_name='', property_slug=''): +    data = {} +    try: +        pm = PropertyModel.objects.get(slug=property_slug, available=True) +    except PropertyModel.DoesNotExist: +        return HttpResponse(json.dumps(data), +                            content_type="application/json") +    if not request.GET or not request.GET.get('term') or \ +            pm.areas.count() and not pm.areas.filter(urn=area_name).count(): +        return HttpResponse(json.dumps(data), +                            content_type="application/json") +    fltr = {'propertymodel': pm, 'available': True, +            'value__icontains': request.GET.get('term')} +    q = PropertyModelChoice.objects.filter(**fltr).order_by('value') +    data = [{"id": p.pk, "value": p.value} for p in q.all()] +    return HttpResponse(json.dumps(data), +                        content_type="application/json") + +  SearchView = None  autocomplete = None  if hasattr(settings, 'CHIMERE_SEARCH_ENGINE') \ diff --git a/chimere/widgets.py b/chimere/widgets.py index 78d7508..2672ba0 100644 --- a/chimere/widgets.py +++ b/chimere/widgets.py @@ -20,15 +20,18 @@  """  Extra widgets and fields  """ + +from json import JSONEncoder +  from django import forms  from django.conf import settings  from django.contrib.gis.db import models  from django.contrib.gis.geos import fromstr  from django.core.exceptions import ObjectDoesNotExist  from django.core.urlresolvers import reverse -from django.forms.widgets import RadioInput, RadioFieldRenderer -from django.utils.encoding import force_unicode -from django.utils.html import conditional_escape +from django.forms.widgets import RadioInput, RadioFieldRenderer, flatatt +from django.utils.encoding import force_unicode, smart_unicode +from django.utils.html import conditional_escape, escape  from django.utils.safestring import mark_safe  from django.utils.translation import ugettext as _  from django.template.loader import render_to_string @@ -262,6 +265,66 @@ class DatePickerWidget(forms.TextInput):          return mark_safe(rendered) +class JQueryAutoComplete(forms.TextInput): +    TEMPLATE = "chimere/blocks/JQueryAutoComplete.html" + +    def __init__(self, slug, options={}, attrs={}): +        """ +        Source can be a list containing the autocomplete values or a +        string containing the url used for the request. +        """ +        self.options = None +        self.attrs = {} +        self.slug = slug +        if len(options) > 0: +            self.options = JSONEncoder().encode(options) +        self.attrs.update(attrs) + +    def get_source(self): +        # Strange... to be fixed +        source = reverse('chimere:property-choices', +                         kwargs={'property_slug': self.slug}) +        return "'{}'".format(source) + +    def render(self, name, value=None, attrs=None): +        attrs_hidden = self.build_attrs(attrs, name=name) +        attrs_select = self.build_attrs(attrs) +        selected_value, rendered_value = "", "" + +        if value: +            val = escape(smart_unicode(value)) +            attrs_hidden['value'] = val +            attrs_select['value'] = val +            selected_value = val +            if val: +                from chimere.models import PropertyModelChoice +                try: +                    attrs_select['value'] = unicode( +                        PropertyModelChoice.objects.get( +                            pk=value, propertymodel__slug=self.slug)) +                    rendered_value = attrs_select['value'] +                except: +                    attrs_select['value'] = "" +        if 'id' not in self.attrs: +            attrs_hidden['id'] = 'id_%s' % name +            attrs_select['id'] = 'id_select_%s' % name +        if 'class' not in attrs_select: +            attrs_select['class'] = 'autocomplete' +        dct = { +            'attrs_select': flatatt(attrs_select), +            'attrs_hidden': flatatt(attrs_hidden), +            'field_id': name, +            'min_field_id': name.replace('_', ''), +            'options': self.options, +            'source': self.get_source(), +            'selected_value': selected_value, +            'rendered_value': rendered_value +        } + +        return mark_safe( +            render_to_string(self.TEMPLATE, dct)) + +  class NominatimWidget(forms.TextInput):      class Media:          js = ["%schimere/js/nominatim-widget.js" % settings.STATIC_URL]  | 
