From 64e59e1a549b6178762fa94cb2888a7940a752bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Fri, 24 Jul 2020 09:42:59 +0200
Subject: [PATCH] forms: put item display value in session for select2 use
 (#45438)

---
 tests/test_form_pages.py | 70 ++++++++++++++++++++++++++++++++++++++++
 wcs/fields.py            | 10 +++++-
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index 073a5a93f..c35c84450 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -2324,6 +2324,76 @@ def test_form_multi_page_post_edit(pub):
     assert logged_error.occurences_count == 2
 
 
+def test_form_edit_autocomplete_list(pub):
+    user = create_user(pub)
+
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'json', 'value': 'http://remote.example.net/json'}
+    data_source.query_parameter = 'q'
+    data_source.id_parameter = 'id'
+    data_source.store()
+
+    formdef = create_formdef()
+    formdef.data_class().wipe()
+
+    formdef.fields = [
+        fields.ItemField(id='0', label='string', type='item',
+            data_source={'type': 'foobar'},
+            display_mode='autocomplete',
+        ),
+    ]
+    formdef.store()
+
+    workflow = Workflow(name='test')
+    st1 = workflow.add_status('Status1', 'st1')
+    editable = EditableWorkflowStatusItem()
+    editable.id = '_editable'
+    editable.by = ['_submitter', '_receiver']
+    st1.items.append(editable)
+    editable.parent = st1
+    workflow.store()
+
+    formdef.workflow_id = workflow.id
+    formdef.store()
+
+    app = get_app(pub)
+    login(app, username='foo', password='foo')
+
+    with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
+        data = {'data': [{'id': '1', 'text': 'hello', 'extra': 'foo'},
+                         {'id': '2', 'text': 'world', 'extra': 'bar'}]}
+        urlopen.side_effect = lambda *args: StringIO(json.dumps(data))
+        resp = app.get('/test/')
+        assert 'data-select2-url=' in resp.text
+        # simulate select2 mode, with qommon.forms.js adding an extra hidden widget
+        resp.form.fields['f0_display'] = Hidden(form=resp.form, tag='input', name='f0_display', pos=10)
+        resp.form['f0'].force_value('1')
+        resp.form.fields['f0_display'].force_value('hello')
+        resp = resp.form.submit('submit')  # -> validation page
+        resp = resp.form.submit('submit')  # -> submit
+        assert formdef.data_class().select()[0].data['0'] == '1'
+        assert formdef.data_class().select()[0].data['0_display'] == 'hello'
+        assert formdef.data_class().select()[0].data['0_structured'] == data['data'][0]
+
+        resp = resp.follow()
+        url = resp.request.url
+        resp = resp.form.submit('button_editable')
+        assert 'wfedit' in resp.location
+        resp = resp.follow()
+        assert 'data-value="1"' in resp
+        assert 'data-initial-display-value="hello"' in resp
+
+        # relogin
+        app = get_app(pub)
+        login(app, username='foo', password='foo')
+        resp = app.get(url)
+        resp = resp.form.submit('button_editable')
+        resp = resp.follow()
+        assert 'data-value="1"' in resp
+        assert 'data-initial-display-value="hello"' in resp
+
+
 def test_form_count_dispatching(pub):
     user = create_user(pub)
 
diff --git a/wcs/fields.py b/wcs/fields.py
index 55cab6466..f190f27fc 100644
--- a/wcs/fields.py
+++ b/wcs/fields.py
@@ -1533,7 +1533,15 @@ class ItemField(WidgetField):
             return get_session().jsonp_display_values.get(
                             '%s_%s' % (data_source.get_jsonp_url(), value))
 
-        return data_source.get_display_value(value)
+        display_value = data_source.get_display_value(value)
+        if self.display_mode == 'autocomplete' and data_source and data_source.can_jsonp():
+            # store display value in session to be used by select2
+            url = data_source.get_jsonp_url()
+            if not get_session().jsonp_display_values:
+                get_session().jsonp_display_values = {}
+            get_session().jsonp_display_values['%s_%s' % (url, value)] = display_value
+
+        return display_value
 
     def get_view_value(self, value, value_id=None, **kwargs):
         value = super(ItemField, self).get_view_value(value)
-- 
2.28.0.rc2

