diff options
Diffstat (limited to 'ishtar_common/widgets.py')
-rw-r--r-- | ishtar_common/widgets.py | 138 |
1 files changed, 96 insertions, 42 deletions
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 3fbf24f29..94709406c 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2010-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # Copyright (C) 2007 skam <massimo dot scamarcia at gmail.com> # (http://djangosnippets.org/snippets/233/) @@ -45,21 +45,89 @@ reverse_lazy = lazy(reverse, unicode) class Select2Multiple(forms.SelectMultiple): - class Media: + def __init__(self, attrs=None, choices=(), remote=None, model=None, + available=None): + super(Select2Multiple, self).__init__(attrs, choices) + self.remote = remote + self.available = available + self.model = model + + @property + def media(self): + media = super(Select2Multiple, self).media css = { 'all': ('select2/css/select2.css',) } - js = ('select2/js/select2.min.js', - 'select2/js/init.js') + js = ['select2/js/select2.min.js'] + for lang_code, lang in settings.LANGUAGES: + js.append('select2/js/i18n/{}.js'.format(lang_code)) + media.add_css(css) + media.add_js(js) + return media + + def get_q(self): + q = self.model.objects + if self.available: + q = q.filter(available=True) + return q + + def get_choices(self): + for i in self.get_q().all(): + yield (i.pk, unicode(i)) def render(self, name, value, attrs=None, choices=()): + self.remote = unicode(self.remote) + if self.remote in ('None', 'false'): + # test on lazy object is buggy... so we have this ugly test + self.remote = None + if not choices and not self.remote and self.model: + choices = self.get_choices() klass = attrs and attrs.get('class') or '' klass += ' ' if klass else '' + 'js-select2' if not attrs: attrs = {} attrs['class'] = klass - return super(Select2Multiple, self).render(name, value, attrs, + attrs['style'] = "width: 370px" + options = "" + if self.remote: + options = """{ + ajax: { + url: '%s', + delay: 250, + dataType: 'json', + minimumInputLength: 2, + processResults: function (data) { + if(!data) return {results: []}; + var result = $.map(data, function (item) { + return { + text: item['value'], + id: item['id'] + } + }); + return { + results: result + } + } + } + }""" % self.remote + if value: + choices = [] + if type(value) not in (list, tuple): + value = value.split(',') + for v in value: + try: + choices.append((v, self.model.objects.get(pk=v))) + except (self.model.DoesNotExist, ValueError): + # an old reference ? it should not happen + pass + html = super(Select2Multiple, self).render(name, value, attrs, choices) + html += """<script type="text/javascript"> + $(document).ready(function() {{ + $("#id_{}").select2({}); + }});</script> + """.format(name, options) + return mark_safe(html) class CheckboxSelectMultiple(CheckboxSelectMultipleBase): @@ -77,49 +145,35 @@ class CheckboxSelectMultiple(CheckboxSelectMultipleBase): choices) -class MultipleAutocompleteField(forms.MultipleChoiceField): +class Select2MultipleField(forms.MultipleChoiceField): def __init__(self, *args, **kwargs): - self.model = None + remote = None + if 'remote' in kwargs: + remote = kwargs.pop('remote') + self.model, self.remote = None, None if 'model' in kwargs: self.model = kwargs.pop('model') - if 'choices' not in kwargs and self.model: - kwargs['choices'] = [] - new = kwargs.pop('new') if 'new' in kwargs else None - if 'widget' not in kwargs and self.model: - kwargs['widget'] = JQueryAutoComplete( - reverse_lazy('autocomplete-' + self.model.__name__.lower()), - associated_model=self.model, new=new, - multiple=True) - super(MultipleAutocompleteField, self).__init__(*args, **kwargs) - - def get_choices(self): - return [(i.pk, unicode(i)) for i in self.model.objects.all()] + if remote: + self.remote = reverse_lazy( + 'autocomplete-' + self.model.__name__.lower()) + self.available = False + if 'available' in kwargs: + self.available = kwargs.pop('available') + kwargs['widget'] = Select2Multiple(model=self.model, + available=self.available, + remote=self.remote) + super(Select2MultipleField, self).__init__(*args, **kwargs) + + def get_q(self): + q = self.model.objects + if self.available: + q = q.filter(available=True) + return q def valid_value(self, value): if not self.model: - return super(MultipleAutocompleteField, self).valid_value(value) - return bool(self.model.objects.filter(pk=value).count()) - - def clean(self, value): - if value: - # clean JS messup with values - try: - if type(value) not in (list, tuple): - value = [int(value)] - else: - val = value - value = [] - for v in val: - v = unicode(v).strip('[').strip(']')\ - .strip('u').strip("'").strip('"') - value += [int(va.strip()) - for va in list(set(v.split(','))) - if va.strip()] - except (TypeError, ValueError): - value = [] - else: - value = [] - return super(MultipleAutocompleteField, self).clean(value) + return super(Select2MultipleField, self).valid_value(value) + return bool(self.get_q().filter(pk=value).count()) class DeleteWidget(forms.CheckboxInput): |