From 0d61a4c63cb35da91d7a71aebf2bd4bbb54aa23c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Sun, 30 Sep 2018 15:39:55 +0200
Subject: [PATCH] forms: mark string fields with html5 autocomplete attributes
 (#26827)

---
 tests/test_form_pages.py | 40 ++++++++++++++++++++++++++++++++++++++++
 wcs/ctl/check_hobos.py   | 14 ++++++++++++++
 wcs/fields.py            | 14 ++++++++++++++
 wcs/qommon/form.py       |  2 ++
 4 files changed, 70 insertions(+)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index 59a54bde..9eab6b5f 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -2111,6 +2111,46 @@ def test_form_page_profile_prefill(pub):
     resp = login(get_app(pub), username='foo', password='foo').get('/test/')
     assert resp.forms[0]['f0'].value == 'foo@localhost'
 
+def test_form_page_profile_first_name_prefill(pub):
+    user = create_user(pub)
+
+    from wcs.admin.settings import UserFieldsFormDef
+    user_formdef = UserFieldsFormDef(pub)
+    user_formdef.fields = [
+        fields.StringField(
+            id='_first_name', label='first name',
+            type='string', extra_css_class='autocomplete-given-name'),
+        fields.StringField(
+            id='_city', label='city',
+            type='string', extra_css_class='autocomplete-address-level2')
+    ]
+    user_formdef.store()
+    user.form_data = {'_first_name': 'plop', '_city': 'mytown'}
+    user.set_attributes_from_formdata(user.form_data)
+    user.store()
+
+    formdef = create_formdef()
+    formdef.data_class().wipe()
+    formdef.fields = [
+        fields.StringField(
+            id='0', label='string',
+            prefill={'type': 'user', 'value': '_first_name'}),
+        fields.StringField(
+            id='1', label='string',
+            prefill={'type': 'user', 'value': '_city'})
+    ]
+    formdef.store()
+
+    resp = get_app(pub).get('/test/')
+    assert resp.forms[0]['f0'].value == ''
+    assert resp.forms[0]['f0'].attrs['autocomplete'] == 'given-name'  # html5
+    assert resp.forms[0]['f1'].value == ''
+    assert resp.forms[0]['f1'].attrs['autocomplete'] == 'address-level2'  # html5
+
+    resp = login(get_app(pub), username='foo', password='foo').get('/test/')
+    assert resp.forms[0]['f0'].value == 'plop'
+    assert resp.forms[0]['f1'].value == 'mytown'
+
 def test_form_page_formula_prefill(pub):
     user = create_user(pub)
     formdef = create_formdef()
diff --git a/wcs/ctl/check_hobos.py b/wcs/ctl/check_hobos.py
index d9a461df..880d43f1 100644
--- a/wcs/ctl/check_hobos.py
+++ b/wcs/ctl/check_hobos.py
@@ -217,6 +217,17 @@ class CmdCheckHobos(Command):
             if field.id in profile_field_ids:
                 profile_fields[field.id] = field
 
+        html5_autocomplete_map = {
+            'first_name': 'given-name',
+            'last_name': 'family-name',
+            'address': 'address-line1',
+            'zipcode': 'postal-code',
+            'city': 'address-level2',
+            'country': 'country',
+            'phone': 'tel',
+            'email': 'email',
+        }
+
         # create or update profile fields
         for attribute in profile.get('fields', []):
             field_id = '_' + attribute['name']
@@ -241,6 +252,9 @@ class CmdCheckHobos(Command):
 
             if attribute['disabled']:
                 profile_field_ids.remove('_' + attribute['name'])
+            if attribute['name'] in html5_autocomplete_map:
+                profile_fields[field_id].extra_css_class = (
+                        'autocomplete-%s' % html5_autocomplete_map[attribute['name']])
 
         # insert profile fields at the beginning
         formdef.fields = [profile_fields[x] for x in profile_field_ids] + formdef.fields
diff --git a/wcs/fields.py b/wcs/fields.py
index 196e5c62..ea3fd842 100644
--- a/wcs/fields.py
+++ b/wcs/fields.py
@@ -369,8 +369,22 @@ class Field(object):
 
     def get_prefill_attributes(self):
         t = self.prefill.get('type')
+
         if t == 'geolocation':
             return {'geolocation': self.prefill.get('value')}
+
+        if t == 'user':
+            formdef = get_publisher().user_class.get_formdef()
+            for user_field in formdef.fields or []:
+                if user_field.id != self.prefill.get('value'):
+                    continue
+                try:
+                    autocomplete_attribute = re.search(r'\bautocomplete-([a-z0-9-]+)',
+                            user_field.extra_css_class).groups()[0]
+                except (TypeError, IndexError):
+                    continue
+                return {'autocomplete': autocomplete_attribute}
+
         return None
 
     def feed_session(self, value, display_value):
diff --git a/wcs/qommon/form.py b/wcs/qommon/form.py
index 284ebaaa..d29f2715 100644
--- a/wcs/qommon/form.py
+++ b/wcs/qommon/form.py
@@ -150,6 +150,8 @@ def string_render_content(self):
     attrs = {'id': 'form_' + self.name}
     if self.required:
         attrs['aria-required'] = 'true'
+    if getattr(self, 'prefill_attributes', None) and 'autocomplete' in self.prefill_attributes:
+        attrs['autocomplete'] = self.prefill_attributes['autocomplete']
     if self.attrs:
         attrs.update(self.attrs)
     return htmltag("input", xml_end=True, type=self.HTML_TYPE, name=self.name,
-- 
2.19.2

