blob: fe3c1d7b68c8fd5ec42586e3116c9773cbbd59e7 [file] [log] [blame]
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A Django template tag library containing forms helpers.
"""
import re
from django import template
from django.forms import forms as forms_in
from django.template import defaultfilters as djangofilter
from django.utils import simplejson
from django.utils.encoding import force_unicode
from django.utils.html import escape
from soc.logic import accounts
from soc.logic import dicts
from soc.views.helper import widgets
register = template.Library()
@register.inclusion_tag('soc/templatetags/_as_user.html')
def as_user(user):
"""Prints a user as a hyperlinked link_id.
"""
return {'user': user}
@register.inclusion_tag('soc/templatetags/_as_email.html')
def as_email(account):
"""Prints a user as a hyperlinked link_id.
"""
denormalized = accounts.denormalizeAccount(account)
return {'email': denormalized.email()}
@register.inclusion_tag('soc/templatetags/_as_upload_form.html')
def as_upload_form(form, form_name, submit_button_text):
"""Prints an upload form.
"""
return {
'form': form,
'form_name': form_name,
'submit_button_text': submit_button_text,
}
@register.inclusion_tag('soc/templatetags/_field_as_table_row.html')
def field_as_table_row(field):
"""Prints a newforms field as a table row.
This function actually does very little, simply passing the supplied
form field instance in a simple context used by the _field_as_table_row.html
template (which is actually doing all of the work).
See soc/templates/soc/templatetags/_field_as_table_row.html for the CSS
styles used by this template tag.
Usage:
{% load forms_helpers %}
...
<table>
{% field_as_table_row form.fieldname %}
...
</table>
Args:
field: a Django newforms field instance
Returns:
a simple context containing the supplied newforms field instance:
{ 'field': field }
"""
return {'field': field}
@register.inclusion_tag('soc/templatetags/_readonly_field_as_table_row.html')
def readonly_field_as_table_row(label, value):
"""Prints a field value and it's verbose name as a table row.
This function actually does very little, simply passing the
supplied field_label and field_value in a simple context used by the
_readonly_field_as_table_row.html template (which is actually
doing all of the work).
See soc/templates/soc/templatetags/_readonly_field_as_table_row.html for
the CSS styles used by this template tag.
Usage:
{% load forms_helpers %}
...
<table>
{% readonly_field_as_table_row field_label field_value %}
...
</table>
Args:
field_label: label of the field to render
field_value: value of the field to render
Returns:
a simple context containing the supplied newforms field instance:
{ 'field_label': field_label',
'field_value': field_value'}
"""
value = value.strip() if isinstance(value, basestring) else value
return {'field_label': label,
'field_value': value}
@register.inclusion_tag(
'soc/templatetags/_readonly_field_as_twoline_table_row.html')
def readonly_field_as_twoline_table_row(label, value):
"""See readonly_field_as_table_row().
"""
value = value.strip() if isinstance(value, basestring) else value
return {'field_label': label,
'field_value': value}
@register.inclusion_tag('soc/templatetags/_readonly_field_as_table_row.html')
def readonly_date_field_as_table_row(label, value):
"""Prints a field value formatted as the given format string.
"""
import datetime
if isinstance(value, datetime.datetime):
if value.day % 10 == 1 and value.day != 11:
ord_suf = 'st'
elif value.day % 10 == 2 and value.day != 12:
ord_suf = 'nd'
elif value.day % 10 == 3 and value.day != 13:
ord_suf = 'rd'
else:
ord_suf = 'th'
fmt = "%d" + ord_suf + " %B %Y, %H:%M"
value = value.strftime(fmt)
return {'field_label': label,
'field_value': value}
@register.inclusion_tag(
'soc/templatetags/_readonly_url_field_as_table_row.html')
def readonly_url_field_as_table_row(field_label, field_value):
"""See readonly_field_as_table_row().
"""
return {'field_label': field_label,
'field_value': field_value}
@register.inclusion_tag(
'soc/templatetags/_readonly_url_field_as_twoline_table_row.html')
def readonly_url_field_as_twoline_table_row(field_label, field_value):
"""See readonly_field_as_table_row().
"""
return {'field_label': field_label,
'field_value': field_value}
@register.inclusion_tag(
'soc/templatetags/_readonly_email_field_as_table_row.html')
def readonly_email_field_as_table_row(field_label, field_value):
"""See readonly_field_as_table_row().
"""
return {'field_label': field_label,
'field_value': field_value}
@register.inclusion_tag(
'soc/templatetags/_readonly_safe_field_as_table_row.html')
def readonly_safe_field_as_table_row(field_label, field_value):
"""See readonly_field_as_table_row().
"""
return {'field_label': field_label,
'field_value': field_value}
@register.inclusion_tag(
'soc/templatetags/_readonly_safe_field_as_twoline_table_row.html')
def readonly_safe_field_as_twoline_table_row(field_label, field_value):
"""See readonly_field_as_table_row().
"""
return {'field_label': field_label,
'field_value': field_value}
@register.inclusion_tag('soc/templatetags/_as_readonly_table.html',
takes_context=True)
def as_readonly_table(context, form):
"""Outputs a form as a properly formatted html table.
Args:
form: the form that should be converted to a table
"""
# create the bound fields
fields = [forms_in.BoundField(form, field, name) for name, field in
form.fields.items() if field]
return {'fields': fields}
@register.inclusion_tag('soc/templatetags/_as_table.html', takes_context=True)
def as_table(context, form):
"""Outputs a form as a properly formatted html table.
Args:
form: the form that should be converted to a table
"""
return as_table_helper(context, form)
@register.inclusion_tag('soc/templatetags/_as_twoline_table.html',
takes_context=True)
def as_twoline_table(context, form):
"""Outputs a form as a properly formatted html table.
Args:
form: the form that should be converted to a table
"""
return as_table_helper(context, form)
def as_table_helper(context, form):
"""See as_table().
"""
fields = []
hidden_fields = []
hidden_fields_errors = []
errors = False
# entity = context['entity']
# support defining output order like in Django
a = form.Meta
if hasattr(form, 'Meta') and form.Meta.fields:
items = [(i, form.fields[i]) for i in form.Meta.fields]
else:
items = form.fields.items()
# Iterate over all fields and prepare it for adding
for name, field in items:
if not field:
continue
bf = forms_in.BoundField(form, field, name)
attrs = {}
if isinstance(field, widgets.ReferenceField):
attrs = field.rf
# If the field is hidden we display it elsewhere
if not bf.is_hidden:
if bf.errors:
errors = True
group = '0. '
if hasattr(field, 'group'):
group = field.group
item = {
'field': bf,
'required': field.required,
'group': group,
}
item.update(attrs)
fields.append(item)
else:
hidden_fields.append(unicode(bf))
for error in bf.errors:
item = (name, force_unicode(error))
hidden_fields_errors.append(item)
grouped = dicts.groupby(fields, 'group')
rexp = re.compile(r"\d+. ")
fields = [(rexp.sub('', key), grouped[key]) for key in sorted(grouped)]
context.update({
'top_errors': form.non_field_errors() or '',
'hidden_field_errors': hidden_fields_errors or '',
'errors': errors,
'groups': fields if fields else '',
'hidden_fields': hidden_fields or '',
'form': form,
'json_for_js': {},
})
return context
@register.inclusion_tag('soc/templatetags/_as_table_row.html',
takes_context=True)
def as_table_row(context, item):
"""Outputs a field as a properly formatted html row.
Args:
item: the item that is being rendered
"""
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, item):
"""See as_table_row().
"""
return as_table_row_helper(context, item)
def as_table_row_helper(context, item):
"""See as_table_row().
"""
field = item['field']
required = item['required']
form = context['form']
entity = context.get('entity', None)
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]
if reference:
from soc.views.helper import redirects
params = {
'url_name': reference,
}
args = {}
if entity:
for filter_field, filter_value in filter_fields.iteritems():
args[filter_field] = filter_value
for filter_field in (i for i in filter if hasattr(entity, i)):
args[filter_field] = getattr(entity, filter_field)
if '__scoped__' in filter:
args['scope_path'] = entity.key().id_or_name()
# TODO: replace this hack needed to get org-scoped mentor
# autocompletion on student proposals
if '__org__' in filter:
args['scope_path'] = entity.org.key().id_or_name()
# even if the entity is not available, it can still be necessary
# to access its potential scope path
elif 'scope_path' in filter and 'scope_path' in context:
args['scope_path'] = context['scope_path']
params['args'] = '&'.join(['%s=%s' % item for item in args.iteritems()])
select_url = redirects.getSelectRedirect(params)
if field.label:
label = escape(force_unicode(field.label))
# Only add the suffix if the label does not end in punctuation.
if form.label_suffix and (label[-1] not in ':?.!'):
label += form.label_suffix
label = field.label_tag(label) or ''
field_class_type = 'formfield%slabel' % ('error' if errors else '')
help_text = field.help_text
context['json_for_js'][field.auto_id] = {
'autocomplete':
djangofilter.safe(select_url) if reference else None,
'tooltip':
djangofilter.linebreaksbr(
force_unicode(help_text)
) if help_text else '',
}
context.update({
'help_text': force_unicode(help_text) if help_text else '',
'field_class_type': field_class_type,
'label': force_unicode(label) if field.label else '',
'field': field,
'field_id': field.auto_id,
'required': required,
'select_url': select_url if reference else None,
'errors': errors,
})
return context
@register.simple_tag
def tojson(json_dictionary):
json_string = simplejson.dumps(json_dictionary, ensure_ascii=False)
return json_string.replace('\"','&quot;')