From 154a6abdcc02415933b53c3cbb734235882ec2e5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Wed, 23 Feb 2022 21:36:30 +0100
Subject: [PATCH] forms: redo date widget for prefill/lock and display of
 readonly values (#58350)

---
 tests/form_pages/test_all.py                  |  6 +++-
 tests/form_pages/test_live.py                 |  6 +++-
 wcs/forms/common.py                           |  4 ++-
 wcs/qommon/static/js/qommon.forms.js          |  7 +++++
 .../templates/qommon/forms/widgets/date.html  | 31 +++++++++++--------
 5 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/tests/form_pages/test_all.py b/tests/form_pages/test_all.py
index 64136500a..07ac5c3a5 100644
--- a/tests/form_pages/test_all.py
+++ b/tests/form_pages/test_all.py
@@ -5423,6 +5423,7 @@ def test_form_page_profile_verified_date_prefill(pub):
     resp = login(get_app(pub), username='foo', password='foo').get('/test/')
     assert resp.form['f0'].value == '2018-09-27'
     assert 'readonly' not in resp.form['f0'].attrs
+    assert resp.form['f0'].attrs['type'] == 'date'
     resp.form['f0'].value = '2018-09-27'
     resp = resp.form.submit('submit')
     assert 'Check values then click submit.' in resp.text
@@ -5433,7 +5434,10 @@ def test_form_page_profile_verified_date_prefill(pub):
 
     resp = login(get_app(pub), username='foo', password='foo').get('/test/')
     assert resp.form['f0'].value == '2018-09-27'
-    assert 'readonly' in resp.form['f0'].attrs
+    # for readonly values there is a <input type=hidden> with the real value
+    # then an unnamed <input type=text> with the formatted value.
+    assert resp.form['f0'].attrs['type'] == 'hidden'
+    assert resp.pyquery('input#form_f0[type=text][readonly=readonly]')
 
     resp.form['f0'].value = '2018-09-24'  # try changing the value
     resp = resp.form.submit('submit')
diff --git a/tests/form_pages/test_live.py b/tests/form_pages/test_live.py
index c5577f2ab..6c92ab6c8 100644
--- a/tests/form_pages/test_live.py
+++ b/tests/form_pages/test_live.py
@@ -918,7 +918,11 @@ def test_field_live_date_prefill(pub, http_requests):
     assert resp.form['f2'].value == ''
     resp.form['f1'] = str(carddata1.id)
     live_resp = app.post('/foo/live?modified_field_id=1&prefilled_2=on', params=resp.form.submit_fields())
-    assert live_resp.json['result']['2'] == {'visible': True, 'content': '2021-10-01'}
+    assert live_resp.json['result']['2'] == {
+        'visible': True,
+        'content': '2021-10-01',
+        'text_content': '01/10/2021',
+    }
 
     resp.form['f2'] = '2021-10-30'  # manually changed -> widget-prefilled class will be removed
     resp.form['f1'] = str(carddata2.id)
diff --git a/wcs/forms/common.py b/wcs/forms/common.py
index 003c2228e..edf9569cd 100644
--- a/wcs/forms/common.py
+++ b/wcs/forms/common.py
@@ -826,10 +826,12 @@ class FormStatusPage(Directory, FormTemplateMixin):
                     elif field.key == 'date' and value:
                         try:
                             value = field.convert_value_from_anything(value)
+                            text_content = field.convert_value_to_str(value)
                             # convert date to Y-m-d as expected by the <input type=date> field
                             value = field.get_json_value(value)
                         except ValueError:
-                            pass
+                            text_content = None
+                        entry['text_content'] = text_content
                     elif field.key == 'item':
                         for option in field.get_options():
                             # get raw value from display value
diff --git a/wcs/qommon/static/js/qommon.forms.js b/wcs/qommon/static/js/qommon.forms.js
index 21990823f..451ae58df 100644
--- a/wcs/qommon/static/js/qommon.forms.js
+++ b/wcs/qommon/static/js/qommon.forms.js
@@ -536,6 +536,13 @@ $(function() {
                 if ($(widget).is('.widget-prefilled') || $(widget).is('.widget-readonly') || data.modified_field == 'user') {
                   // replace text input value
                   $(widget).find('input[type=text], input[type=tel], input[type=numeric], input[type=email], input[type=date], textarea').val(value.content);
+                  if ($(widget).is('.DateWidget')) {
+                    // Set both hidden input for real value, and text input for
+                    // formatted date. This will also set the old date picker
+                    // to the formatted value, which is expected.
+                    $(widget).find('input[type=hidden]').val(value.content);
+                    $(widget).find('input[type=text]').val(value.text_content);
+                  }
                   if ($widget.hasClass('CheckboxWidget')) {
                     // replace checkbox input value
                     $widget.find('input[type=checkbox]').prop('checked', value.content);
diff --git a/wcs/qommon/templates/qommon/forms/widgets/date.html b/wcs/qommon/templates/qommon/forms/widgets/date.html
index f34bbfd63..f8452fafd 100644
--- a/wcs/qommon/templates/qommon/forms/widgets/date.html
+++ b/wcs/qommon/templates/qommon/forms/widgets/date.html
@@ -1,21 +1,23 @@
 {% extends "qommon/forms/widget.html" %}
 
 {% block widget-control %}
-<input id="form_{{widget.name}}" name="{{widget.name}}"
-  type="{% if "readonly" in widget.attrs %}text{% else %}date{% endif %}"
-  {% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}" {% endfor %}
-  {% if widget.required %}aria-required="true"{% endif %}
-  {% if "readonly" in widget.attrs %}
-    {% if widget.value %}value="{{ widget.value }}"{% endif %}
-  {% else %}
-
-  {% if widget.value %}value="{{ widget.value|date:"Y-m-d" }}" data-formatted-value="{{ widget.value|default:"" }}"{% endif %}
+{% if "readonly" in widget.attrs %}
+{# for readonly mode, add an hidden field with the correct value and a text #}
+{# input with the formated date value; this will avoid displaying the date in #}
+{# Y-m-d format, or including a date input with an ineffective reset × button. #}
+<input type="hidden" name="{{widget.name}}" {% if widget.value %}value="{{ widget.value|date:"Y-m-d" }}"{% endif %}>
+<input type="text" {% if widget.value %}value="{{ widget.value|date }}"{% endif %}
+{% else %}
+{# otherwise, use an <input type="date"> but also include js datetime picker #}
+{# attributes, in case it's not supported. #}
+<input name="{{widget.name}}" {% if widget.value %}value="{{ widget.value|date:"Y-m-d" }}"{% endif %}
+  type="date"
+  {% if widget.value %}data-formatted-value="{{ widget.value|default:"" }}"{% endif %}
   class="date-pick"
   data-date-format="{{widget.date_format}}"
 
-  {# if the date format does not contain the time, set widget not to go #}
-  {# into the time pages #}
-  data-min-view="{% if 'hh' in widget.date_format %}0{% else %}2{% endif %}"
+  {# set widget not to go into the time pages #}
+  data-min-view="2"
 
   {# if there is no value we set the initial view to be the view of decades, #}
   {# it is more appropriate to select a far away date. #}
@@ -29,6 +31,9 @@
   data-end-date="{{ widget.end_date }}"
   max="{{widget.maximum_date|date:"Y-m-d"}}"
   {% endif %}
-  {% endif %}
+{% endif %}
+  id="form_{{widget.name}}"
+  {% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}" {% endfor %}
+  {% if widget.required %}aria-required="true"{% endif %}
   >
 {% endblock %}
-- 
2.35.1

