Commits

xiaq  committed ecd902b

factor out common code for building Select and MultiSelect widgets

A new MoinMoin.forms.Enum class is introduced which extends flatland.Enum with
a convenience class method out_of.

  • Participants
  • Parent commits 7ae56d3

Comments (0)

Files changed (3)

File MoinMoin/apps/frontend/views.py

 from flask.ext.babel import format_date
 from flask.ext.themes import get_themes_list
 
-from flatland import Form, Enum, List
+from flatland import Form, List
 from flatland.validation import Validator
 
 from jinja2 import Markup
 from MoinMoin.themes import render_template, contenttype_to_class
 from MoinMoin.apps.frontend import frontend
 from MoinMoin.forms import (OptionalText, RequiredText, URL, YourOpenID, YourEmail, RequiredPassword, Checkbox,
-                            InlineCheckbox, Select, Names, Tags, Natural, Hidden, MultiSelect)
+                            InlineCheckbox, Select, Names, Tags, Natural, Hidden, MultiSelect, Enum)
 from MoinMoin.items import BaseChangeForm, Item, NonExistent
 from MoinMoin.items.content import content_registry
 from MoinMoin import user, util
         abort(403)
 
 
-contenttype_groups = content_registry.group_names[:]
-contenttype_group_descriptions = {}
-for g in contenttype_groups:
-    contenttype_group_descriptions[g] = ', '.join([e.display_name for e in content_registry.groups[g]])
-contenttype_groups.append('unknown items')
+def contenttype_selects_gen():
+    for g in content_registry.group_names:
+        description = u', '.join([e.display_name for e in content_registry.groups[g]])
+        yield g, None, description
+    yield u'unknown items', None, u'Items of contenttype unknown to MoinMoin'
 
-ContenttypeGroup = MultiSelect.of(Enum.using(valid_values=contenttype_groups).with_properties(
-                                  descriptions=contenttype_group_descriptions)).using(optional=True)
+ContenttypeGroup = MultiSelect.of(Enum.out_of(contenttype_selects_gen())).using(optional=True)
 
 
 class IndexForm(Form):
     # more.
     form = IndexForm.from_flat(request.args.items(multi=True))
     if not form['contenttype']:
-        form['contenttype'].set(contenttype_groups)
+        form['contenttype'].set(ContenttypeGroup.member_schema.valid_values)
 
     selected_groups = form['contenttype'].value
     startswith = request.values.get("startswith")
         display_name = OptionalText.using(label=L_('Display-Name')).with_properties(
             placeholder=L_("Your display name (informational)"))
         openid = YourOpenID.using(optional=True)
-        #timezones_keys = sorted(Locale('en').time_zones.keys())
-        timezones_keys = [unicode(tz) for tz in pytz.common_timezones]
-        timezone = Select.using(label=L_('Timezone')).valued(*timezones_keys)
-        supported_locales = [Locale('en')] + app.babel_instance.list_translations()
-        locales_available = sorted([(unicode(l), l.display_name) for l in supported_locales],
-                                   key=lambda x: x[1])
-        locales_keys = [l[0] for l in locales_available]
-        locale = Select.using(label=L_('Locale')).with_properties(labels=dict(locales_available)).valued(*locales_keys)
+        #_timezones_keys = sorted(Locale('en').time_zones.keys())
+        _timezones_keys = [unicode(tz) for tz in pytz.common_timezones]
+        timezone = Select.using(label=L_('Timezone')).out_of((e, e) for e in _timezones_keys)
+        _supported_locales = [Locale('en')] + app.babel_instance.list_translations()
+        locale = Select.using(label=L_('Locale')).out_of(
+            ((unicode(l), l.display_name) for l in _supported_locales), sort_by=1)
         submit_label = L_('Save')
 
     class UserSettingsUIForm(Form):
         name = 'usersettings_ui'
-        themes_available = sorted([(unicode(t.identifier), t.name) for t in get_themes_list()],
-                                  key=lambda x: x[1])
-        themes_keys = [t[0] for t in themes_available]
-        theme_name = Select.using(label=L_('Theme name')).with_properties(
-            labels=dict(themes_available)).valued(*themes_keys)
+        theme_name = Select.using(label=L_('Theme name')).out_of(
+            ((unicode(t.identifier), t.name) for t in get_themes_list()), sort_by=1)
         css_url = URL.using(label=L_('User CSS URL'), optional=True).with_properties(
             placeholder=L_("Give the URL of your custom CSS (optional)"))
         edit_rows = Natural.using(label=L_('Editor size')).with_properties(

File MoinMoin/forms.py

 import re
 import datetime
 import json
+from operator import itemgetter
 
-from flatland import (Element, Form, String, Integer, Boolean, Enum, Dict, JoinedString, List, Array,
+from flatland import (Element, Form, String, Integer, Boolean, Enum as BaseEnum, Dict, JoinedString, List, Array,
                       DateTime as _DateTime)
 from flatland.util import class_cloner, Unspecified
 from flatland.validation import Validator, Present, IsEmail, ValueBetween, URLValidator, Converted, ValueAtLeast
 from MoinMoin.util.forms import FileStorage
 
 
+class Enum(BaseEnum):
+    """
+    An Enum with a convenience class method out_of.
+    """
+    @classmethod
+    def out_of(cls, choice_specs, sort_by=None):
+        """
+        A convenience class method to build Enum with extra data attached to
+        each valid value.
+
+        :param choice_specs: An iterable of tuples. The elements are collected
+                             into the choice_specs property; the tuples' first
+                             elements become the valid values of the Enum. e.g.
+                             for choice_specs = [(v1, ...), (v2, ...), ... ],
+                             the valid values are v1, v2, ...
+
+        :param sort_by: If not None, sort choice_specs by the sort_by'th
+                        element.
+        """
+        if sort_by is not None:
+            choice_specs = sorted(choice_specs, key=itemgetter(sort_by))
+        else:
+            choice_specs = list(choice_specs)
+        return cls.valued(*[e[0] for e in choice_specs]).with_properties(choice_specs=choice_specs)
+
+
 Text = String.with_properties(widget=WIDGET_TEXT)
 
 MultilineText = String.with_properties(widget=WIDGET_MULTILINE_TEXT)

File MoinMoin/templates/forms.html

   </dt>
   <dd>
     {{ gen.select.open(field) }}
-    {% set labels = field.properties.get('labels', {}) %}
-    {% for value in field.valid_values %}
-      {{ gen.option(field, value=value, contents=labels.get(value, value)) }}
+    {% for value, label in field.properties['choice_specs'] %}
+      {{ gen.option(field, value=value, contents=label or value) }}
     {% endfor %}
     {{ gen.select.close() }}
     {{ render_errors(field) }}
 {% endmacro %}
 
 {% macro multi_select(field) %}
-  {% set valid_values = field.member_schema.valid_values %}
-  {% set labels = field.member_schema.properties.get('labels', {}) %}
-  {% set descriptions = field.member_schema.properties.get('descriptions', {}) %}
-  {% for value in valid_values %}
+  {% for value, label, description in field.member_schema.properties['choice_specs'] %}
     <li>
       {{ raw_input(field, 'checkbox', value=value) }}
-      {{ _valued_label(field, value, labels.get(value, value), class='moin-inline-label') }}
-      {% if descriptions[value] is defined %}
+      {{ _valued_label(field, value, label or value, class='moin-inline-label') }}
+      {% if description %}
         <span class="helper-text">
-          {{ descriptions[value] }}
+          {{ description }}
         </span>
       {% endif %}
     </li>