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] |