Added grouping support to all forms, converted role as example
Any field that has the 'group' property set be placed in the
specified group. If no such proprty is set, the 'General' group will
be used instead.
Patch by: Sverre Rabbelier
--- a/app/soc/models/role.py Sun Feb 15 20:27:56 2009 +0000
+++ b/app/soc/models/role.py Sun Feb 15 22:29:22 2009 +0000
@@ -174,6 +174,7 @@
verbose_name=ugettext('Street address'))
res_street.help_text = ugettext(
'street number and name, lower ASCII characters only')
+ res_street.group=ugettext("Contact Info")
#: Required field containing residence address city; kept private.
#: Residence city can only be lower ASCII, not UTF-8 text, because it
@@ -181,6 +182,7 @@
res_city = db.StringProperty(required=True,
verbose_name=ugettext('City'))
res_city.help_text = ugettext('lower ASCII characters only')
+ res_city.group=ugettext("Contact Info")
#: Optional field containing residence address state or province; kept
#: private. Residence state/province can only be lower ASCII, not UTF-8
@@ -190,12 +192,14 @@
res_state.help_text = ugettext(
'optional if country/territory does not have states or provinces, '
'lower ASCII characters only')
+ res_state.group=ugettext("Contact Info")
#: Required field containing residence address country or territory; kept
#: private.
res_country = db.StringProperty(required=True,
verbose_name=ugettext('Country/Territory'),
choices=countries.COUNTRIES_AND_TERRITORIES)
+ res_country.group=ugettext("Contact Info")
#: Required field containing residence address postal code (ZIP code in
#: the United States); kept private. Residence postal code can only be
@@ -203,6 +207,7 @@
res_postalcode = db.StringProperty(required=True,
verbose_name=ugettext('ZIP/Postal Code'))
res_postalcode.help_text = ugettext('lower ASCII characters only')
+ res_postalcode.group=ugettext("Contact Info")
#: Optional field containing a separate shipping street address; kept
#: private. If shipping address is not present in its entirety, the
@@ -213,6 +218,7 @@
verbose_name=ugettext('Shipping Street address'))
ship_street.help_text = ugettext(
'street number and name, lower ASCII characters only')
+ ship_street.group=ugettext("Shipping Info")
#: Optional field containing shipping address city; kept private.
#: Shipping city can only be lower ASCII, not UTF-8 text, because, if
@@ -220,6 +226,7 @@
ship_city = db.StringProperty(
verbose_name=ugettext('Shipping City'))
ship_city.help_text = ugettext('lower ASCII characters only')
+ ship_city.group=ugettext("Shipping Info")
#: Optional field containing shipping address state or province; kept
#: private. Shipping state/province can only be lower ASCII, not UTF-8
@@ -229,12 +236,14 @@
ship_state.help_text = ugettext(
'optional if country/territory does not have states or provinces, '
'lower ASCII characters only')
+ ship_state.group=ugettext("Shipping Info")
#: Optional field containing shipping address country or territory; kept
#: private.
ship_country = db.StringProperty(
verbose_name=ugettext('Shipping Country/Territory'),
choices=countries.COUNTRIES_AND_TERRITORIES)
+ ship_country.group=ugettext("Shipping Info")
#: Optional field containing shipping address postal code (ZIP code in
#: the United States); kept private. Shipping postal code can only be
@@ -243,6 +252,7 @@
ship_postalcode = db.StringProperty(
verbose_name=ugettext('Shipping ZIP/Postal Code'))
ship_postalcode.help_text = ugettext('lower ASCII characters only')
+ ship_postalcode.group=ugettext("Shipping Info")
#: Required field containing a phone number that will be supplied
#: to shippers; kept private.
@@ -251,6 +261,8 @@
verbose_name=ugettext('Phone Number'))
phone.help_text = ugettext(
'include complete international calling number with country code')
+ phone.group=ugettext("Shipping Info")
+
#====================================================================
# (private) personal information
@@ -263,17 +275,20 @@
verbose_name=ugettext('Birth Date'))
birth_date.help_text = ugettext(
'required for determining program eligibility')
+ birth_date.group=ugettext("Private Info")
#: Optional field indicating choice of t-shirt, from XXS to XXXL;
#: kept private.
tshirt_size = db.StringProperty(
verbose_name=ugettext('T-shirt Size'),
choices=('XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'))
+ tshirt_size.group=ugettext("Private Info")
#: Optional field indicating choice of t-shirt fit; kept private.
tshirt_style = db.StringProperty(
verbose_name=ugettext('T-shirt Style'),
choices=('male', 'female'))
+ tshirt_style.group=ugettext("Private Info")
#: field storing wheter the User has agreed to the site-wide Terms of Service.
#: (Not a required field because the Terms of Service might not be present
@@ -282,6 +297,7 @@
verbose_name=ugettext('I Agree to the Terms of Service'))
agreed_to_tos.help_text = ugettext(
'Indicates whether the user agreed to this role Terms of Service.')
+ agreed_to_tos.group=ugettext("Terms of Service")
#: field storing when the User has agreed to the site-wide Terms of Service.
#: (Not a required field because the Terms of Service might not be present
@@ -290,6 +306,7 @@
verbose_name=ugettext('Has agreed to the Terms of Service on'))
agreed_to_tos_on.help_text = ugettext(
'Indicates when the user agreed to this role Terms of Service.')
+ agreed_to_tos.group=ugettext("Terms of Service")
#: field storing the status of this role
#: Active means that this role can exercise all it's privileges.
@@ -303,7 +320,7 @@
verbose_name=ugettext('Status of this Role'))
status.help_text = ugettext(
'Indicates the status of the role concerning which privileges may be used.')
-
+
#: field storing whether the User has agreed to publish his location
publish_location = db.BooleanProperty(required=False, default=False,
verbose_name=ugettext('Publish my location'))
--- a/app/soc/templates/soc/templatetags/_as_table.html Sun Feb 15 20:27:56 2009 +0000
+++ b/app/soc/templates/soc/templatetags/_as_table.html Sun Feb 15 22:29:22 2009 +0000
@@ -26,10 +26,29 @@
</ul>
{% endif %}
-{% for field, required, example_text, reference in fields %}
- {% block fields_loop %}
- {% as_table_row field required example_text reference %}
- {% endblock %}
+{% regroup fields by group as grouped_fields %}
+
+{% for grouped_field in grouped_fields %}
+ {% ifequal grouped_field.grouper 'main' %}
+ <tr><td class="grouptitle">General</td></tr>
+ {% for item in grouped_field.list %}
+ {% block main_fields_loop %}
+ {% as_table_row item %}
+ {% endblock %}
+ {% endfor %}
+ {% endifequal %}
+{% endfor %}
+
+{% for grouped_field in grouped_fields %}
+ {% ifnotequal grouped_field.grouper 'main' %}
+ <tr><td> </td></tr>
+ <tr><td class="grouptitle">{{ grouped_field.grouper }}</td></tr>
+ {% for item in grouped_field.list %}
+ {% block grouped_fields_loop %}
+ {% as_table_row item %}
+ {% endblock %}
+ {% endfor %}
+ {% endifnotequal %}
{% endfor %}
{% for field in hidden_fields %}
--- a/app/soc/templates/soc/templatetags/_as_twoline_table.html Sun Feb 15 20:27:56 2009 +0000
+++ b/app/soc/templates/soc/templatetags/_as_twoline_table.html Sun Feb 15 22:29:22 2009 +0000
@@ -14,6 +14,10 @@
{% endcomment %}
{% load forms_helpers %}
-{% block fields_loop %}
- {% as_twoline_table_row field required example_text reference %}
+{% block main_fields_loop %}
+ {% as_twoline_table_row item %}
{% endblock %}
+
+{% block grouped_fields_loop %}
+ {% as_twoline_table_row item %}
+{% endblock %}
--- a/app/soc/views/helper/forms.py Sun Feb 15 20:27:56 2009 +0000
+++ b/app/soc/views/helper/forms.py Sun Feb 15 22:29:22 2009 +0000
@@ -65,21 +65,18 @@
if hasattr(self.Meta.model, field_name):
model_prop = getattr(self.Meta.model, field_name)
- # Check if the Model property defined verbose_name, and copy that
- # verbatim to the corresponding field label.
if hasattr(model_prop, 'verbose_name'):
self.fields[field_name].label = model_prop.verbose_name
- # Check if the Model property added help_text, and copy that verbatim
- # to the corresponding field help_text.
if hasattr(model_prop, 'help_text'):
self.fields[field_name].help_text = model_prop.help_text
- # Check if the Model property added example_text, and copy that verbatim
- # to the corresponding field help_text.
if hasattr(model_prop, 'example_text'):
self.fields[field_name].example_text = model_prop.example_text
+ if hasattr(model_prop, 'group'):
+ self.fields[field_name].group = model_prop.group
+
class SelectQueryArgForm(forms.Form):
"""URL query argument change control implemented as a Django form.
--- a/app/soc/views/helper/templatetags/forms_helpers.py Sun Feb 15 20:27:56 2009 +0000
+++ b/app/soc/views/helper/templatetags/forms_helpers.py Sun Feb 15 22:29:22 2009 +0000
@@ -154,31 +154,6 @@
return as_table_helper(context, form)
-def get_reference_url(form, name):
- """Retrieves the reference url from a field.
-
- Args:
- form: the form the field is defined in
- name: the name of the field
- """
-
- if not hasattr(form, 'Meta'):
- return None
-
- if not hasattr(form.Meta, 'model'):
- return None
-
- if not hasattr(form.Meta.model, name):
- return None
-
- field = getattr(form.Meta.model, name)
-
- if not isinstance(field, db.ReferenceProperty):
- return None
-
- return getattr(field, 'redirect_url', None)
-
-
def as_table_helper(context, form):
fields = []
hidden_fields = []
@@ -199,10 +174,22 @@
# If the field is hidden we display it elsewhere
if not bf.is_hidden:
example_text = ''
+ group = 'main'
+
+ if hasattr(field, 'group'):
+ group = field.group
+
if hasattr(field, 'example_text'):
example_text = force_unicode(field.example_text)
- item = (bf, field.required, example_text, attrs)
+ item = {
+ 'field': bf,
+ 'required': field.required,
+ 'example_text': example_text,
+ 'group': group,
+ }
+
+ item.update(attrs)
fields.append(item)
else:
hidden_fields.append(unicode(bf))
@@ -214,7 +201,7 @@
context.update({
'top_errors': form.non_field_errors() or '',
'hidden_field_errors': hidden_fields_errors or '',
- 'fields': fields or '',
+ 'fields': sorted(fields, key=lambda x: x.get('group')) or '',
'hidden_fields': hidden_fields or '',
})
@@ -223,42 +210,43 @@
@register.inclusion_tag('soc/templatetags/_as_table_row.html',
takes_context=True)
-def as_table_row(context, field, required, example_text, reference):
+def as_table_row(context, item):
"""Outputs a field as a properly formatted html row.
Args:
- form: the form that the row belongs to
- field: the field that should be converted to a row
- required: whether the field is required
- example_text: the example_text for this row
- reference: the entity_suffix if the field is a reference
+ item: the item that is being rendered
"""
- return as_table_row_helper(context, field, required, example_text, reference)
+ return as_table_row_helper(context, item)
@register.inclusion_tag('soc/templatetags/_as_twoline_table_row.html',
takes_context=True)
-def as_twoline_table_row(context, field, required, example_text, reference):
+def as_twoline_table_row(context, item):
+ """See as_table_row().
+ """
+
+ return as_table_row_helper(context, item)
+
+
+def as_table_row_helper(context, item):
"""See as_table_row().
"""
- return as_table_row_helper(context, field, required, example_text, reference)
-
+ field = item['field']
+ required = item['required']
+ example_text = item['example_text']
-def as_table_row_helper(context, field, required, example_text, attrs):
- """See as_table_row().
- """
+ form = context['form']
+ entity = context['entity']
+
+ reference = item.get('reference_url')
+ filter = item.get('filter')
+ filter_fields = item.get('filter_fields')
# Escape and cache in local variable.
errors = [force_unicode(escape(error)) for error in field.errors]
- form = context['form']
- entity = context['entity']
-
- reference = attrs.get('reference_url')
- filter = attrs.get('filter')
- filter_fields = attrs.get('filter_fields')
if reference:
from soc.views.helper import redirects