summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
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
commit9beb58d4d65f06ac8f14ec4371c9dee31332dd48 (patch)
tree1a28c206916c0329db1f898d828226d6cd10e63a /ishtar_common
parentf19a8dfbd0763a4b994ff77e4105ca54faeff648 (diff)
downloadIshtar-9beb58d4d65f06ac8f14ec4371c9dee31332dd48.tar.bz2
Ishtar-9beb58d4d65f06ac8f14ec4371c9dee31332dd48.zip
Replace MultipleAutocompleteField with Select2MultipleField (refs #3575)
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/static/media/style.css9
-rw-r--r--ishtar_common/widgets.py116
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):