diff options
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/forms.py | 29 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 87 |
2 files changed, 105 insertions, 11 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 5de0db91d..59f3e141a 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -26,6 +26,7 @@ import re import types from django import forms +from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse from django.core import validators from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME @@ -114,7 +115,7 @@ JSON_VALUE_TYPES_FIELDS = { 'I': (forms.IntegerField, None), 'F': (forms.FloatField, None), 'D': (DateField, None), - 'C': (forms.CharField, None), + 'C': (widgets.Select2DynamicField, None), } @@ -171,6 +172,30 @@ class CustomForm(object): self.fields.pop(key) @classmethod + def _get_dynamic_choices(cls, key): + """ + Get choice from existing values + :param key: data key + :return: tuple of choices (id, value) + """ + app_name = cls.__module__.split('.')[0] + if app_name == "archaeological_files_pdl": + app_name = "archaeological_files" + model_name = cls.form_slug.split("-")[0].replace('_', "") + ct = ContentType.objects.get(app_label=app_name, model=model_name) + ct_class = ct.model_class() + choices = set() + splitted_key = key[len('data__'):].split('__') + for obj in ct_class.objects.filter( + data__has_key=key[len('data__'):]).all(): + value = obj.data + for k in splitted_key: + value = value[k] + choices.add(value) + choices = [('--', '')] + [(v, v) for v in sorted(list(choices))] + return choices + + @classmethod def _get_json_fields(cls, custom_form): fields = [] for field in custom_form.json_fields.order_by('order').all(): @@ -185,6 +210,8 @@ class CustomForm(object): attrs['help_text'] = field.help_text if widget: attrs['widget'] = widget(attrs={"class": "form-control"}) + if field_cls == widgets.Select2DynamicField: + attrs['choices'] = cls._get_dynamic_choices(key) f = field_cls(**attrs) fields.append((field.order or 1, key, f)) return fields diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 442f12b9a..a20d33fc3 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -23,6 +23,7 @@ import logging from django import forms from django.conf import settings +from django.core.exceptions import ValidationError from django.core.files import File from django.core.urlresolvers import reverse, NoReverseMatch from django.db.models import fields @@ -101,18 +102,10 @@ class SelectReadonlyField(forms.ChoiceField): return bool(self.get_q().filter(pk=value).count()) -class Select2Multiple(forms.SelectMultiple): - def __init__(self, attrs=None, choices=(), remote=None, model=None, - new=None, available=None): - super(Select2Multiple, self).__init__(attrs, choices) - self.remote = remote - self.available = available - self.model = model - self.new = new - +class Select2Media(object): @property def media(self): - media = super(Select2Multiple, self).media + media = super(Select2Media, self).media css = { 'all': ('select2/css/select2.css',) } @@ -123,6 +116,80 @@ class Select2Multiple(forms.SelectMultiple): media.add_js(js) return media + +class Select2Dynamic(Select2Media, forms.Select): + """ + Select input using select, allowing dynamic creation. + """ + + def render(self, name, value, attrs=None, choices=()): + choices = choices or getattr(self, 'choices', []) + if value and value not in [key for key, v in choices]: + choices.insert(1, (value, value)) + self.choices = choices + klass = attrs and attrs.get('class') or '' + klass += ' ' if klass else '' + 'js-select2' + if not attrs: + attrs = {} + attrs['class'] = klass + if 'style' not in attrs: + if attrs.get('full-width', None): + attrs['style'] = "width: calc(100% - 60px)" + else: + attrs['style'] = "width: 370px" + options = [ + u"tags: true", + ] + ''' + msg = unicode( + _(u"Are you sure you want to add this term? (the addition is " + u"effective after registration of the element)") + ) + options.append(u"""createTag: function (params) {{ + return confirm("{}"); + }}""".format(msg)) + ''' + if attrs.get('full-width', None): + options.append(u"containerCssClass: 'full-width'") + + html = super(Select2Dynamic, self).render(name, value, attrs) + html += """<script type="text/javascript"> + $(document).ready(function() {{ + $("#id_{}").select2({{ {} }}); + }});</script> + """.format(name, u", ".join(options)) + return mark_safe(html) + + +class Select2DynamicField(forms.ChoiceField): + widget = Select2Dynamic + + def validate(self, value): + """ + Key can be added dynamically. Only check that the character " is not + used. + """ + if value and u'"' in value: + raise ValidationError( + _(u"The character \" is not accepted.") + ) + + def to_python(self, value): + """ + Strip value + """ + return super(Select2DynamicField, self).to_python(value).strip() + + +class Select2Multiple(Select2Media, forms.SelectMultiple): + def __init__(self, attrs=None, choices=(), remote=None, model=None, + new=None, available=None): + super(Select2Multiple, self).__init__(attrs, choices) + self.remote = remote + self.available = available + self.model = model + self.new = new + def get_q(self): q = self.model.objects if self.available: |