diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/static/media/style.css | 9 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 116 |
2 files changed, 86 insertions, 39 deletions
diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css index adaf94200..fc840526e 100644 --- a/ishtar_common/static/media/style.css +++ b/ishtar_common/static/media/style.css @@ -92,6 +92,15 @@ div.form { border-bottom:1px solid #D14; } +.form .select2-container--default .select2-selection--multiple { + border: 1px solid #FFF; +} + +.form .select2-container--default.select2-container--focus +.select2-selection--multiple { + border:1px solid #D14; +} + hr.spacer{ clear:both; border:0; diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index ffa09e7b4..f0e1dc775 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -45,6 +45,12 @@ reverse_lazy = lazy(reverse, unicode) class Select2Multiple(forms.SelectMultiple): + 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): @@ -59,20 +65,66 @@ class Select2Multiple(forms.SelectMultiple): 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 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 = [] + for v in value: + try: + choices.append((v, self.model.objects.get(pk=v))) + except self.model.DoesNotExist: + # 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(); + $("#id_{}").select2({}); }});</script> - """.format(name) + """.format(name, options) return mark_safe(html) @@ -91,49 +143,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): |