diff options
-rw-r--r-- | archaeological_files/forms.py | 6 | ||||
-rw-r--r-- | archaeological_files_pdl/forms.py | 12 | ||||
-rw-r--r-- | archaeological_finds/forms.py | 12 | ||||
-rw-r--r-- | ishtar_common/static/media/style.css | 9 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 116 |
5 files changed, 102 insertions, 53 deletions
diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 45a05b9b1..99fe6e0db 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -336,10 +336,8 @@ class FileFormResearch(ManageOldType, forms.Form): 'requested_operation_type': OperationType, 'organization': Organization, 'department': Department} - department = widgets.MultipleAutocompleteField( - model=Department, - label=_("Departments"), - required=False) + department = widgets.Select2MultipleField( + model=Department, label=_("Departments"), required=False) scientist = forms.IntegerField( widget=widgets.JQueryAutoComplete( reverse_lazy( diff --git a/archaeological_files_pdl/forms.py b/archaeological_files_pdl/forms.py index 4890eb5d6..8bb1f9156 100644 --- a/archaeological_files_pdl/forms.py +++ b/archaeological_files_pdl/forms.py @@ -86,9 +86,9 @@ class FileFormPlanning(forms.Form): associated_models = {'town': Town, 'department': Department} name = forms.CharField(label=_(u"Planning name"), required=False, max_length=100) - town = widgets.MultipleAutocompleteField( - model=Town, label=_("Towns"), required=False) - department = widgets.MultipleAutocompleteField( + town = widgets.Select2MultipleField( + model=Town, label=_("Towns"), required=False, remote=True) + department = widgets.Select2MultipleField( model=Department, label=_("Departments"), required=False) locality = forms.CharField(label=_(u"Locality"), max_length=100, required=False) @@ -118,9 +118,9 @@ class FileFormResearchAddress(forms.Form): associated_models = {'town': Town, 'department': Department} name = forms.CharField(label=_(u"Project name"), required=False, max_length=100) - town = widgets.MultipleAutocompleteField( - model=Town, label=_("Towns"), required=False) - department = widgets.MultipleAutocompleteField( + town = widgets.Select2MultipleField( + model=Town, label=_("Towns"), required=False, remote=True) + department = widgets.Select2MultipleField( model=Department, label=_("Departments"), required=False) locality = forms.CharField(label=_(u"Locality"), max_length=100, required=False) diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index bbc8729d0..8fe945e88 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -147,15 +147,19 @@ class FindForm(ManageOldType, forms.Form): required=False) is_complete = forms.NullBooleanField(label=_(u"Is complete?"), required=False) - material_type = widgets.MultipleAutocompleteField( - model=models.MaterialType, label=_(u"Material type"), required=False) + material_type = widgets.Select2MultipleField( + model=models.MaterialType, label=_(u"Material type"), required=False, + available=True + ) conservatory_state = forms.ChoiceField(label=_(u"Conservatory state"), choices=[], required=False) conservatory_comment = forms.CharField( label=_(u"Conservatory comment"), required=False, widget=forms.Textarea) - object_type = widgets.MultipleAutocompleteField( - model=models.ObjectType, label=_(u"Object types"), required=False) + object_type = widgets.Select2MultipleField( + model=models.ObjectType, label=_(u"Object types"), required=False, + available=True + ) preservation_to_consider = forms.MultipleChoiceField( label=_(u"Preservation type"), choices=[], widget=widgets.Select2Multiple, required=False) 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): |