From 3a28b9d8c03c7cce0016425e6e47afdea7f2d774 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Wed, 15 Jul 2020 19:10:48 +0200
Subject: [PATCH] misc: add inputmode=number attribute on zipcode/etc. widgets
 (#45152)

---
 tests/test_widgets.py |  5 +++++
 wcs/qommon/form.py    | 51 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/tests/test_widgets.py b/tests/test_widgets.py
index 9d088830d..9ca3a8e6f 100644
--- a/tests/test_widgets.py
+++ b/tests/test_widgets.py
@@ -687,6 +687,11 @@ def test_wcsextrastringwidget_builtin_validation():
     mock_form_submission(req, widget, {'test': '12345'})
     assert not widget.has_error()
 
+    # and check it gets a special HTML inputmode
+    widget = WcsExtraStringWidget('test', value='foo', required=False)
+    widget.field = fakefield
+    assert 'inputmode="number"' in str(widget.render())
+
     widget = WcsExtraStringWidget('test', value='foo', required=False)
     widget.field = fakefield
     mock_form_submission(req, widget, {'test': '1234'})
diff --git a/wcs/qommon/form.py b/wcs/qommon/form.py
index f329b742e..a0b75077f 100644
--- a/wcs/qommon/form.py
+++ b/wcs/qommon/form.py
@@ -201,6 +201,8 @@ def string_render_content(self):
         attrs['autocomplete'] = self.prefill_attributes['autocomplete']
     if self.attrs:
         attrs.update(self.attrs)
+    if getattr(self, 'inputmode', None):
+        attrs['inputmode'] = self.inputmode
     return htmltag("input", xml_end=True, type=self.HTML_TYPE, name=self.name,
                    value=self.value, **attrs)
 StringWidget.render_content = string_render_content
@@ -951,13 +953,41 @@ class ValidationCondition(Condition):
 class ValidationWidget(CompositeWidget):
     validation_methods = collections.OrderedDict([
         ('digits', {'title': N_('Digits'), 'regex': '\d+'}),
-        ('phone', {'title': N_('Phone Number'), 'regex': r'\+?[-\(\)\d\.\s/]+', 'html_input_type': 'tel'}),
-        ('phone-fr', {'title': N_('Phone Number (France)'), 'function': 'validate_phone_fr', 'html_input_type': 'tel'}),
-        ('zipcode-fr', {'title': N_('Zip Code (France)'), 'regex': '\d{5}'}),
-        ('siren-fr', {'title': N_('SIREN Code (France)'), 'function': 'validate_siren'}),
-        ('siret-fr', {'title': N_('SIRET Code (France)'), 'function': 'validate_siret'}),
-        ('nir-fr', {'title': N_('NIR (France)'), 'function': 'validate_nir'}),
-        ('iban', {'title': N_('IBAN'), 'function': 'validate_iban'}),
+        ('phone', {
+            'title': N_('Phone Number'),
+            'regex': r'\+?[-\(\)\d\.\s/]+',
+            'html_input_type': 'tel'}
+        ),
+        ('phone-fr', {
+            'title': N_('Phone Number (France)'),
+            'function': 'validate_phone_fr',
+            'html_input_type': 'tel'}
+        ),
+        ('zipcode-fr', {
+            'title': N_('Zip Code (France)'),
+            'regex': r'\d{5}',
+            'html_inputmode': 'number'}
+        ),
+        ('siren-fr', {
+            'title': N_('SIREN Code (France)'),
+            'function': 'validate_siren',
+            'html_inputmode': 'number'}
+        ),
+        ('siret-fr', {
+            'title': N_('SIRET Code (France)'),
+            'function': 'validate_siret',
+            'html_inputmode': 'number'}
+        ),
+        ('nir-fr', {
+            'title': N_('NIR (France)'),
+            'function': 'validate_nir',
+            'html_inputmode': 'number'}
+        ),
+        ('iban', {
+            'title': N_('IBAN'),
+            'function': 'validate_iban',
+            'html_inputmode': 'number'}
+        ),
         ('regex', {'title': N_('Regular Expression')}),
         ('django', {'title': N_('Django Condition')}),
     ])
@@ -1036,6 +1066,12 @@ class ValidationWidget(CompositeWidget):
             return validation_method.get('html_input_type')
         return 'text'
 
+    @classmethod
+    def get_html_inputmode(cls, validation):
+        validation_method = cls.validation_methods.get(validation['type'])
+        if validation_method and validation_method.get('html_inputmode'):
+            return validation_method.get('html_inputmode')
+
 
 class WcsExtraStringWidget(StringWidget):
     field = None
@@ -1049,6 +1085,7 @@ class WcsExtraStringWidget(StringWidget):
     def render_content(self):
         if self.field and self.field.validation:
             self.HTML_TYPE = ValidationWidget.get_html_input_type(self.field.validation)
+            self.inputmode = ValidationWidget.get_html_inputmode(self.field.validation)
         return super(WcsExtraStringWidget, self).render_content()
 
     def _parse(self, request):
-- 
2.28.0.rc0

