diff options
| -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: | 
