diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2017-03-27 20:14:25 +0200 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2017-03-27 20:14:25 +0200 | 
| commit | 600ca391dfc97cf3c3f49c759e6c91cdb02cb779 (patch) | |
| tree | 1a28c206916c0329db1f898d828226d6cd10e63a | |
| parent | 04bb7042fada207d17e24214cb5a32177ba10c50 (diff) | |
| download | Ishtar-600ca391dfc97cf3c3f49c759e6c91cdb02cb779.tar.bz2 Ishtar-600ca391dfc97cf3c3f49c759e6c91cdb02cb779.zip | |
Replace MultipleAutocompleteField with Select2MultipleField (refs #3575)
| -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): | 
