From 6f1d578285f40b63bcffe4b61e1ee1a7cb720b1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Mon, 31 Jan 2022 11:13:09 +0100
Subject: [PATCH] cells: extra_css_class for links in link list cell (#61197)

---
 combo/apps/wcs/forms.py                       |  6 ++++++
 combo/apps/wcs/models.py                      |  5 +++++
 combo/data/forms.py                           |  6 ++++++
 combo/data/models.py                          |  5 +++++
 .../combo/manager/link-list-cell-form.html    |  3 +++
 combo/manager/static/css/combo.manager.css    |  3 ++-
 combo/manager/views.py                        |  4 ++--
 .../templates/combo/link-list-cell.html       |  2 +-
 tests/test_cells.py                           |  6 +++++-
 tests/test_manager.py                         |  7 +++++++
 tests/test_wcs.py                             | 19 ++++++++++++++++---
 11 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/combo/apps/wcs/forms.py b/combo/apps/wcs/forms.py
index 4751fd86..0ecf81dc 100644
--- a/combo/apps/wcs/forms.py
+++ b/combo/apps/wcs/forms.py
@@ -43,6 +43,12 @@ class WcsFormCellForm(forms.ModelForm):
         self.fields['formdef_reference'].widget = forms.Select(choices=formdef_references)
 
 
+class WcsFormForLinkListCellForm(WcsFormCellForm):
+    class Meta:
+        model = WcsFormCell
+        fields = ('formdef_reference', 'extra_css_class')
+
+
 class WcsCardsCellForm(forms.ModelForm):
     with_user = forms.BooleanField(label=_('Restrict to cards accessible to the user'), required=False)
 
diff --git a/combo/apps/wcs/models.py b/combo/apps/wcs/models.py
index 66c805ac..02b523ef 100644
--- a/combo/apps/wcs/models.py
+++ b/combo/apps/wcs/models.py
@@ -88,6 +88,11 @@ class WcsFormCell(CellBase):
 
         return WcsFormCellForm
 
+    def get_form_class_for_link_list_cell(self):
+        from .forms import WcsFormForLinkListCellForm
+
+        return WcsFormForLinkListCellForm
+
     def save(self, *args, **kwargs):
         if 'update_fields' in kwargs:
             # don't populate the cache
diff --git a/combo/data/forms.py b/combo/data/forms.py
index 833ffdd5..28ebb3de 100644
--- a/combo/data/forms.py
+++ b/combo/data/forms.py
@@ -49,6 +49,12 @@ class LinkCellForm(forms.ModelForm):
         self.fields['link_page'].widget = forms.Select(choices=[(None, '-----')] + get_page_choices())
 
 
+class LinkCellForLinkListCellForm(LinkCellForm):
+    class Meta:
+        model = LinkCell
+        fields = ('title', 'url', 'link_page', 'anchor', 'extra_css_class')
+
+
 class LinkListCellForm(forms.ModelForm):
     class Meta:
         model = LinkListCell
diff --git a/combo/data/models.py b/combo/data/models.py
index ef0c81b3..959bad59 100644
--- a/combo/data/models.py
+++ b/combo/data/models.py
@@ -1514,6 +1514,11 @@ class LinkCell(CellBase):
 
         return LinkCellForm
 
+    def get_form_class_for_link_list_cell(self):
+        from .forms import LinkCellForLinkListCellForm
+
+        return LinkCellForLinkListCellForm
+
     def render_for_search(self):
         return ''
 
diff --git a/combo/data/templates/combo/manager/link-list-cell-form.html b/combo/data/templates/combo/manager/link-list-cell-form.html
index b5634a01..700fae25 100644
--- a/combo/data/templates/combo/manager/link-list-cell-form.html
+++ b/combo/data/templates/combo/manager/link-list-cell-form.html
@@ -14,6 +14,9 @@
    <span title="{{ link }}">
      {{ link|truncatechars:100 }}
      {% with link.get_invalid_reason as invalid_reason %}
+     {% if link.extra_css_class %}
+     <span class="extra-css-class">[{{ link.extra_css_class }}]</span>
+     {% endif %}
      {% if invalid_reason %}
      <span class="invalid">{{ invalid_reason }} -
        {% if cell.get_validity_info.invalid_datetime|datetime_in_past %}
diff --git a/combo/manager/static/css/combo.manager.css b/combo/manager/static/css/combo.manager.css
index 16f67160..fa5bd53b 100644
--- a/combo/manager/static/css/combo.manager.css
+++ b/combo/manager/static/css/combo.manager.css
@@ -105,7 +105,8 @@ div.page .group1 small {
 	color: #3c3c33;
 }
 
-div.cell h3 span.extra-css-class {
+div.cell h3 span.extra-css-class,
+ul.list-of-links span.extra-css-class {
 	font-size: 70%;
 	opacity: 0.7;
 }
diff --git a/combo/manager/views.py b/combo/manager/views.py
index 629e3816..09d04bc0 100644
--- a/combo/manager/views.py
+++ b/combo/manager/views.py
@@ -874,7 +874,7 @@ class PageListCellAddLinkView(ManagedPageMixin, CreateView):
         return super().dispatch(request, *args, **kwargs)
 
     def get_form_class(self):
-        return self.model().get_default_form_class()
+        return self.model().get_form_class_for_link_list_cell()
 
     def get_form_kwargs(self):
         kwargs = super().get_form_kwargs()
@@ -923,7 +923,7 @@ class PageListCellEditLinkView(ManagedPageMixin, UpdateView):
         return self.object
 
     def get_form_class(self):
-        return self.model().get_default_form_class()
+        return self.model().get_form_class_for_link_list_cell()
 
     def form_valid(self, form):
         if self.request.is_ajax():
diff --git a/combo/public/templates/combo/link-list-cell.html b/combo/public/templates/combo/link-list-cell.html
index e11688cd..61012292 100644
--- a/combo/public/templates/combo/link-list-cell.html
+++ b/combo/public/templates/combo/link-list-cell.html
@@ -9,7 +9,7 @@
   {% block cell-top-content %}{% endblock cell-top-content %}
   <ul>
   {% for link in links %}
-  <li class="{{ link.css_classes|default:""|join:" " }}"><a href="{{ link.url }}">{{ link.title }}</a></li>
+  <li class="{{ link.css_classes|default:""|join:" " }}{% if link.cell.extra_css_class %} {{ link.cell.extra_css_class }}{% endif %}"><a href="{{ link.url }}">{{ link.title }}</a></li>
   {% endfor %}
   {% if more_links %}
   <li class="add-more-items">
diff --git a/tests/test_cells.py b/tests/test_cells.py
index a0cfe3fa..da2e1e32 100644
--- a/tests/test_cells.py
+++ b/tests/test_cells.py
@@ -258,12 +258,16 @@ def test_link_list_cell():
         title='Example Site',
         url='http://example.net/',
         order=0,
+        extra_css_class='foobar',
     )
 
     ctx = {'page_cells': [item]}
-    assert '<ul><li class=""><a href="http://example.net/">Example Site</a></li></ul>' in cell.render(ctx)
+    assert '<ul><li class=" foobar"><a href="http://example.net/">Example Site</a></li></ul>' in cell.render(
+        ctx
+    )
 
     item.title = ''
+    item.extra_css_class = ''
     assert '<ul><li class=""><a href="http://example.net/">http://example.net/</a></li></ul>' in cell.render(
         ctx
     )
diff --git a/tests/test_manager.py b/tests/test_manager.py
index 056e07f8..dae4b875 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -2467,6 +2467,11 @@ def test_json_cell_syntax_validation(app, admin_user):
     assert JsonCell.objects.first().template_string == '{{ ok }}'
 
 
+def test_link_cell_setup():
+    form = LinkCellForm()
+    assert 'extra_css_class' not in form.fields
+
+
 def test_link_cell_validation():
     form = LinkCellForm(data={'url': 'http://example.com'})
     assert form.is_valid() is True
@@ -2490,6 +2495,7 @@ def test_add_edit_delete_list_link_item(app, admin_user):
     resp = resp.click(href='.*/add-link/link$')
     resp.forms[0]['title'] = 'Hello world'
     resp.forms[0]['url'] = 'http://example.com'
+    resp.forms[0]['extra_css_class'] = 'foobar'
     resp = resp.forms[0].submit()
     assert resp.status_int == 302
     assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
@@ -2499,6 +2505,7 @@ def test_add_edit_delete_list_link_item(app, admin_user):
     assert item.url == 'http://example.com'
     assert item.page == page
     assert item.placeholder == cell.link_placeholder
+    assert item.extra_css_class == 'foobar'
     assert PageSnapshot.objects.count() == 1
 
     resp = resp.follow()
diff --git a/tests/test_wcs.py b/tests/test_wcs.py
index f1736f55..2e7103a2 100644
--- a/tests/test_wcs.py
+++ b/tests/test_wcs.py
@@ -468,6 +468,7 @@ def test_form_cell_setup(mock_send):
         ('other:form-title', 'test2 : form title'),
         ('other:third-form-title', 'test2 : Third form title'),
     ]
+    assert 'extra_css_class' not in form.fields
 
 
 @mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send)
@@ -3933,6 +3934,7 @@ def test_manager_add_edit_delete_list_link_item(mock_send, app, admin_user):
 
     resp = resp.click(href='.*/add-link/form-link$')
     resp.forms[0]['formdef_reference'] = 'default:form-title'
+    resp.forms[0]['extra_css_class'] = 'foobar'
     resp = resp.forms[0].submit()
     assert resp.status_int == 302
     assert resp.location.endswith('/manage/pages/%s/#cell-%s' % (page.pk, cell.get_reference()))
@@ -3941,6 +3943,7 @@ def test_manager_add_edit_delete_list_link_item(mock_send, app, admin_user):
     assert item.formdef_reference == 'default:form-title'
     assert item.page == page
     assert item.placeholder == cell.link_placeholder
+    assert item.extra_css_class == 'foobar'
 
     resp = resp.follow()
     resp = resp.click(href='.*/link/%s/$' % item.get_reference())
@@ -3993,23 +3996,33 @@ def test_list_of_links_with_form_render(app):
     page.save()
 
     cell = LinkListCell.objects.create(order=0, placeholder='content', page=page)
-    WcsFormCell.objects.create(
+    link = WcsFormCell.objects.create(
         page=page,
         placeholder=cell.link_placeholder,
         cached_title='A title',
         cached_url='http://example.com/',
-        cached_json={'keywords': ['bar']},
         order=0,
+        extra_css_class='foobar',
     )
 
     resp = app.get('/test_list_of_links_with_form_render/')
     assert PyQuery(resp.text).find('.links-list a').text() == 'A title'
-    assert PyQuery(resp.text).find('.links-list li').attr('class') == 'keyword-bar'
+    assert PyQuery(resp.text).find('.links-list li').attr('class') == ' foobar'
     assert (
         PyQuery(resp.text).find('.links-list a').attr('href')
         == 'http://example.com/tryauth?cancelurl=http%3A//testserver/test_list_of_links_with_form_render/'
     )
 
+    link.cached_json = {'keywords': ['bar']}
+    link.save()
+    resp = app.get('/test_list_of_links_with_form_render/')
+    assert PyQuery(resp.text).find('.links-list li').attr('class') == 'keyword-bar foobar'
+
+    link.extra_css_class = ''
+    link.save()
+    resp = app.get('/test_list_of_links_with_form_render/')
+    assert PyQuery(resp.text).find('.links-list li').attr('class') == 'keyword-bar'
+
 
 def test_view_page_with_wcs_cells_num_queries(app, admin_user):
     page = Page.objects.create(title='bar', slug='index', order=1)
-- 
2.34.1

