Browse Source

Settings forms builder improved.

Rafał Pitoń 11 years ago
parent
commit
979a0abf2a
3 changed files with 53 additions and 17 deletions
  1. 1 1
      docs/developers/settings.rst
  2. 51 15
      misago/conf/forms.py
  3. 1 1
      misago/core/migrations/0002_db_settings.py

+ 1 - 1
docs/developers/settings.rst

@@ -51,7 +51,7 @@ Each dict in ``settings`` tuple should define following keys:
 * **default_value** - if your setting should always have value, specify there fallabck value used if no user-defined value is available.
 * **is_lazy** - if setting value may too large to be always loaded into memory, you may make setting lazily loaded by defining this key with ``True`` value assigned.
 * **form_field** - What form field should be used to change this setting. Can be either "text", "textarea", "select", "radio", "yesno" or "checkbox". If not defined, "text" is used. "checkbox" should be used exclusively for multiple choices list.
-* **field_extra** - dict that defines extra attributes of form field. For "select", "radio" and "checkbox" fields this dict should contain "choices" key with tuple of tuples that will be used for choices in input. For "string" settings you can define "min_length" and "max_length" extra specifying minmal and maximal lenght of entered text. For integer settings you can specify minimal and maximal range in which value should fall by "min_value" and "max_value". "textarea" field supports extra "rows" setting that controls generated textarea rows attribute.
+* **field_extra** - dict that defines extra attributes of form field. For "select", "radio" and "checkbox" fields this dict should contain "choices" key with tuple of tuples that will be used for choices in input. For "string" settings you can define "min_length" and "max_length" extra specifying minmal and maximal lenght of entered text. For integer settings you can specify minimal and maximal range in which value should fall by "min_value" and "max_value". "textarea" field supports extra "rows" setting that controls generated textarea rows attribute. "checkbox" field supports "min" and "max" values that control minimum and maximum required choices.
 
 
 .. note::

+ 51 - 15
misago/conf/forms.py

@@ -1,26 +1,65 @@
-from django.utils.translation import ugettext_lazy as _
-from misago.core import forms
+from django.utils.translation import ugettext_lazy as _, ungettext_lazy
+from misago.core import forms, timezones
 
 
 __ALL__ = ['ChangeSettingsForm']
 
 
-def basic_kwargs(setting):
+class ValidateChoicesNum(object):
+    def __init__(self, min_choices=0, max_choices=0):
+        self.min_choices = min_choices,
+        self.max_choices = max_choices
+
+    def __call__(self, data):
+        data_len = len(data)
+
+        if self.min_choices and self.min_choices > data_len:
+            message = ungettext_lazy(
+                'You have to select at least one option.',
+                'You have to select at least %(min_choices)d options.',
+                self.min_choices)
+            message = message % {'min_choices': self.min_choices}
+            raise forms.ValidationError(message)
+
+        if self.max_choices and self.max_choices < data_len:
+            message = ungettext_lazy(
+                'You cannot select more than one option.',
+                'You cannot select more than %(max_choices)d options.',
+                self.max_choices)
+            message = message % {'max_choices': self.max_choices}
+            raise forms.ValidationError(message)
+
+        return data
+
+
+def basic_kwargs(setting, extra):
     kwargs = {
         'label': _(setting.name),
-        'initial': setting.value
+        'initial': setting.value,
+        'required': extra.get('min_length') or extra.get('min'),
     }
+
     if setting.description:
         kwargs['help_text'] = _(setting.description)
 
+    if kwargs['required']:
+        if kwargs.get('help_text'):
+            format = {'help_text': kwargs['help_text']}
+            kwargs['help_text'] = _('Required. %(help_text)s') % format
+        else:
+            kwargs['help_text'] = _('This field is required.')
+
     return kwargs
 
 
 def create_checkbox(setting, kwargs, extra):
-    kwargs = basic_kwargs(setting)
     kwargs['widget'] = forms.CheckboxSelectMultiple()
     kwargs['choices'] = extra.get('choices', [])
 
+    if extra.get('min') or extra.get('max'):
+        kwargs['validators'] = [ValidateChoicesNum(extra.get('min', 0),
+                                                   extra.get('max', 0))]
+
     if setting.python_type == 'int':
         return forms.TypedMultipleChoiceField(coerce='int', **kwargs)
     else:
@@ -28,15 +67,14 @@ def create_checkbox(setting, kwargs, extra):
 
 
 def create_choice(setting, kwargs, extra):
-    kwargs = basic_kwargs(setting)
     if setting.form_field == 'choice':
         kwargs['widget'] = forms.RadioSelect()
     else:
         kwargs['widget'] = forms.Select()
-    kwargs['choices'] = extra.get('choices', [])
 
-    if kwargs['choices'] == '#tz#':
-        pass
+    kwargs['choices'] = extra.get('choices', [])
+    if kwargs['choices'] == '#TZ#':
+        kwargs['choices'] = timezones.choices()
 
     if setting.python_type == 'int':
         return forms.TypedChoiceField(coerce='int', **kwargs)
@@ -49,13 +87,10 @@ def create_text(setting, kwargs, extra):
     if setting.python_type == 'int':
         return forms.IntegerField(**kwargs)
     else:
-        if extra.get('min_length', 0) == 0:
-            kwargs['required'] = False
         return forms.CharField(**kwargs)
 
 
 def create_textarea(setting, kwargs, extra):
-    kwargs = basic_kwargs(setting)
     widget_kwargs = {}
     if extra.get('min_length', 0) == 0:
         kwargs['required'] = False
@@ -67,7 +102,6 @@ def create_textarea(setting, kwargs, extra):
 
 
 def create_yesno(setting, kwargs, extra):
-    kwargs = basic_kwargs(setting)
     kwargs['widget'] = forms.RadioSelect()
     kwargs['choices'] = ((0, _('No')), (1, _('Yes')))
     return forms.TypedChoiceField(coerce='int', **kwargs)
@@ -85,9 +119,11 @@ FIELD_STYPES = {
 
 def setting_field(FormType, setting):
     field_factory = FIELD_STYPES[setting.form_field]
+
+    field_extra = setting.field_extra
     form_field = field_factory(setting,
-                               basic_kwargs(setting),
-                               setting.field_extra)
+                               basic_kwargs(setting, field_extra),
+                               field_extra)
 
     if setting.legend:
         form_field.legend = _(setting.legend)

+ 1 - 1
misago/core/migrations/0002_db_settings.py

@@ -17,7 +17,7 @@ class Migration(DataMigration):
                 'key': 'basic',
                 'name': _("Basic forum settings"),
                 'description': _("Those settings control most basic properties "
-                                 "of your forum like it's name or description."),
+                                 "of your forum like its name or description."),
                 'settings': (
                     {
                         'setting': 'forum_name',