--- a/src/pyams_form/widget/__init__.py Tue Oct 23 12:08:33 2018 +0200
+++ b/src/pyams_form/widget/__init__.py Thu Oct 25 15:33:24 2018 +0200
@@ -14,6 +14,7 @@
import inspect
import json
+import locale
import os
import venusian
@@ -26,7 +27,8 @@
from z3c.form.browser.text import TextWidget
from z3c.form.browser.textarea import TextAreaWidget
from z3c.form.button import ButtonAction
-from z3c.form.converter import BaseDataConverter, DatetimeDataConverter as BaseDatetimeDataConverter
+from z3c.form.converter import BaseDataConverter, DatetimeDataConverter as BaseDatetimeDataConverter, \
+ FormatterValidationError
from z3c.form.interfaces import DISPLAY_MODE, IButtonAction, IDataConverter, IFieldWidget, INPUT_MODE, ITextWidget, \
IWidgetLayoutTemplate, NO_VALUE
from z3c.form.widget import FieldWidget, WidgetLayoutFactory, WidgetTemplateFactory
@@ -37,7 +39,8 @@
from zope.schema.interfaces import IChoice, IDate, IDatetime, IFloat, IInt, IList, ISet, ITime, ITuple
from pyams_form.interfaces.form import IActionWidget, ICloseWidget, IColorWidget, IDateWidget, IDatetimeWidget, \
- IFormLayer, IHTMLWidget, IResetWidget, ISEOTextLineWidget, ISelect2Widget, ITextLineListWidget, ITimeWidget
+ IFormLayer, IHTMLWidget, IResetWidget, ISEOTextLineWidget, ISelect2Widget, ITextLineListWidget, ITimeWidget, \
+ IIntegerWidget, IFloatWidget
from pyams_form.schema import IActionButton, ICloseButton, IResetButton
from pyams_skin.interfaces.tinymce import ITinyMCEConfiguration
from pyams_utils.adapter import adapter_config
@@ -303,8 +306,28 @@
# Integer field widget
#
+@adapter_config(context=(IInt, IIntegerWidget), provides=IDataConverter)
+class IntegerFieldDataConverter(BaseDataConverter):
+ """Integer field data converter"""
+
+ error_message = _("Invalid integer value")
+
+ def toWidgetValue(self, value):
+ if value is self.field.missing_value:
+ return ''
+ return locale.format_string('%d', value, grouping=True)
+
+ def toFieldValue(self, value):
+ if not value:
+ return self.field.missing_value
+ try:
+ return locale.atoi(value)
+ except ValueError:
+ raise FormatterValidationError(self.errorMessage, value)
+
+
@widgettemplate_config(mode=INPUT_MODE, template='templates/integer-input.pt', layer=IFormLayer)
-@implementer_only(ITextWidget)
+@implementer_only(IIntegerWidget)
class IntegerWidget(TextWidget):
"""Integer widget"""
@@ -327,18 +350,39 @@
# Float field widget
#
+@adapter_config(context=(IFloat, IFloatWidget), provides=IDataConverter)
+class FloatFieldDataConverter(BaseDataConverter):
+ """Float field data converter"""
+
+ error_message = _("Invalid floating value")
+
+ def toWidgetValue(self, value):
+ if value is self.field.missing_value:
+ return ''
+ return locale.format_string('%.{0}f'.format(self.widget.precision), value, grouping=True)
+
+ def toFieldValue(self, value):
+ if not value:
+ return self.field.missing_value
+ try:
+ return locale.atof(value)
+ except ValueError:
+ raise FormatterValidationError(self.error_message, value)
+
+
@widgettemplate_config(mode=INPUT_MODE, template='templates/float-input.pt', layer=IFormLayer)
-@implementer_only(ITextWidget)
+@implementer_only(IFloatWidget)
class FloatWidget(TextWidget):
"""Float widget"""
+ precision = FieldProperty(IFloatWidget['precision'])
+
@property
def validate_rules(self):
- rules = {'number': True}
- if self.field.min is not None:
- rules['min'] = self.field.min
- if self.field.max is not None:
- rules['max'] = self.field.max
+ conv = locale.localeconv()
+ rules = {'pattern': '\{}?[\d{}]+{}?\d*'.format(conv.get('negative_sign', '-'),
+ conv.get('mon_thousands_sep', ''),
+ conv.get('decimal_point', '\.'))}
return json.dumps(rules)