misc: generate <template> tags for live error display (#.....)
This commit is contained in:
parent
c9e9412944
commit
cc5ce2ffd4
|
@ -177,6 +177,24 @@ def widget_get_name_for_id(self):
|
|||
return self.name.replace('$', '__')
|
||||
|
||||
|
||||
class ErrorMessage:
|
||||
def __init__(self, code, label):
|
||||
self.code = code
|
||||
self.label = label
|
||||
|
||||
def camel_code(self):
|
||||
return ''.join(x.lower() if i == 0 else x.capitalize() for i, x in enumerate(self.code.split('_')))
|
||||
|
||||
|
||||
def widget_get_error_messages(self):
|
||||
for code in self.get_error_message_codes():
|
||||
yield ErrorMessage(code, getattr(self, 'get_%s_message' % code)())
|
||||
|
||||
|
||||
def widget_get_error_message_codes(self):
|
||||
yield 'value_missing'
|
||||
|
||||
|
||||
Widget.render = render
|
||||
Widget.cleanup = None
|
||||
Widget.render_error = render_error
|
||||
|
@ -185,6 +203,10 @@ Widget.render_title = render_title
|
|||
Widget.is_prefilled = is_prefilled
|
||||
Widget.render_widget_content = render_widget_content
|
||||
Widget.get_name_for_id = widget_get_name_for_id
|
||||
Widget.get_error_messages = widget_get_error_messages
|
||||
Widget.get_error_message_codes = widget_get_error_message_codes
|
||||
Widget.get_value_missing_message = lambda x: Widget.REQUIRED_ERROR
|
||||
Widget.get_invalid_value_message = lambda x: _('Invalid value')
|
||||
|
||||
|
||||
def file_render_content(self):
|
||||
|
@ -579,13 +601,21 @@ class StringWidget(QuixoteStringWidget):
|
|||
if self.value:
|
||||
self.value = self.value.strip()
|
||||
if self.maxlength and len(self.value) > self.maxlength:
|
||||
self.error = _('Too long, value must be at most %d characters.') % self.maxlength
|
||||
self.error = self.get_too_long_message()
|
||||
elif self.validation_function:
|
||||
try:
|
||||
self.validation_function(self.value)
|
||||
except ValueError as e:
|
||||
self.error = str(e)
|
||||
|
||||
def get_too_long_message(self):
|
||||
return _('Too long, value must be at most %d characters.') % self.maxlength
|
||||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
if self.maxlength:
|
||||
yield 'too_long'
|
||||
|
||||
def render_content(self):
|
||||
attrs = {'id': 'form_' + self.get_name_for_id()}
|
||||
if self.required:
|
||||
|
@ -629,19 +659,26 @@ class TextWidget(QuixoteTextWidget):
|
|||
def _parse(self, request, use_validation_function=True):
|
||||
QuixoteTextWidget._parse(self, request)
|
||||
if self.value is not None:
|
||||
try:
|
||||
maxlength = int(self.attrs.get('maxlength', 0))
|
||||
except (TypeError, ValueError):
|
||||
maxlength = 0
|
||||
if maxlength:
|
||||
if len(self.value) > maxlength:
|
||||
self.error = _('too many characters (limit is %d)') % maxlength
|
||||
self.error = self.get_too_long_message()
|
||||
if use_validation_function and self.validation_function:
|
||||
try:
|
||||
self.validation_function(self.value)
|
||||
except ValueError as e:
|
||||
self.error = str(e)
|
||||
|
||||
def get_too_long_message(self):
|
||||
try:
|
||||
maxlength = int(self.attrs.get('maxlength', 0))
|
||||
except (TypeError, ValueError):
|
||||
maxlength = 0
|
||||
return _('too many characters (limit is %d)') % maxlength
|
||||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
yield 'too-long'
|
||||
|
||||
def render_content(self):
|
||||
attrs = {'id': 'form_' + self.get_name_for_id()}
|
||||
if self.required:
|
||||
|
@ -1635,9 +1672,15 @@ class CheckboxesWidget(Widget):
|
|||
if self.required and not self.value:
|
||||
self.set_error(self.REQUIRED_ERROR)
|
||||
if self.value and self.min_choices and len(self.value) < self.min_choices:
|
||||
self.set_error(_('You must select at least %d answers.') % self.min_choices)
|
||||
self.set_error(self.get_too_short_message())
|
||||
if self.value and self.max_choices and len(self.value) > self.max_choices:
|
||||
self.set_error(_('You must select at most %d answers.') % self.max_choices)
|
||||
self.set_error(self.get_too_long_message())
|
||||
|
||||
def get_too_short_message(self):
|
||||
return _('You must select at least %d answers.') % self.min_choices
|
||||
|
||||
def get_too_long_message(self):
|
||||
return _('You must select at most %d answers.') % self.max_choices
|
||||
|
||||
def set_value(self, value):
|
||||
self.value = value
|
||||
|
@ -1893,7 +1936,14 @@ class WidgetList(quixote.form.widget.WidgetList):
|
|||
def _parse(self, request):
|
||||
super()._parse(request)
|
||||
if self.max_items and self.value and len(self.value) > self.max_items:
|
||||
self.set_error(_('Too many elements (maximum: %s)') % self.max_items)
|
||||
self.set_error(self.get_too_many_message())
|
||||
|
||||
def get_too_many_message(self):
|
||||
return _('Too many elements (maximum: %s)') % self.max_items
|
||||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
yield 'too_many'
|
||||
|
||||
def set_value(self, value):
|
||||
for dummy in range(len(value) - len(self.element_names)):
|
||||
|
@ -2631,9 +2681,20 @@ class MultiSelectWidget(MultipleSelectWidget):
|
|||
finally:
|
||||
self.name = orig_name
|
||||
if self.value and self.min_choices and len(self.value) < self.min_choices:
|
||||
self.set_error(_('You must select at least %d choices.') % self.min_choices)
|
||||
self.set_error(self.get_too_short_message())
|
||||
if self.value and self.max_choices and len(self.value) > self.max_choices:
|
||||
self.set_error(_('You must select at most %d choices.') % self.max_choices)
|
||||
self.set_error(self.get_too_long_message())
|
||||
|
||||
def get_too_short_message(self):
|
||||
return _('You must select at least %d choices.') % self.min_choices
|
||||
|
||||
def get_too_long_message(self):
|
||||
return _('You must select at most %d choices.') % self.max_choices
|
||||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
yield 'too_short'
|
||||
yield 'too_long'
|
||||
|
||||
|
||||
class WidgetListAsTable(WidgetList):
|
||||
|
@ -2831,9 +2892,16 @@ class RankedItemsWidget(CompositeWidget):
|
|||
if value is not None:
|
||||
values[val] = value
|
||||
if value is not None and not isinstance(value, int):
|
||||
self.get_widget(key).set_error(IntWidget.TYPE_ERROR)
|
||||
self.get_widget(key).set_error(self.get_type_mismatch_message())
|
||||
self.value = values or None
|
||||
|
||||
def get_type_mismatch_message(self):
|
||||
return _('must be a number')
|
||||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
yield 'type_mismatch'
|
||||
|
||||
def set_value(self, value):
|
||||
self.value = value
|
||||
if value:
|
||||
|
@ -3290,11 +3358,15 @@ class MapWidget(CompositeWidget):
|
|||
try:
|
||||
lat, lon = self.value.split(';')
|
||||
except ValueError:
|
||||
self.set_error(_('Invalid value'))
|
||||
self.set_error(self.get_invalid_value_message())
|
||||
else:
|
||||
lat_lon = misc.normalize_geolocation({'lat': lat, 'lon': lon})
|
||||
self.value = '%s;%s' % (lat_lon['lat'], lat_lon['lon']) if lat_lon else None
|
||||
|
||||
def get_error_message_codes(self):
|
||||
yield from super().get_error_message_codes()
|
||||
yield 'invalid_value'
|
||||
|
||||
def set_value(self, value):
|
||||
super().set_value(value)
|
||||
self.get_widget('latlng').set_value(value)
|
||||
|
|
|
@ -45,4 +45,11 @@
|
|||
{% if widget.render_br %}
|
||||
<br class="content {{widget.content.content_extra_css_class}}">
|
||||
{% endif %}
|
||||
{% block widget-error-templates %}
|
||||
{% if not widget.readonly %}
|
||||
{% for error_message in widget.get_error_messages %}
|
||||
<template id="error_{{ widget.get_name_for_id }}_{{ error_message.camel_code }}">{{ error_message.label }}</template>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue