From 9d4ae7974cfa610cf3aa37915e813b6b3abab047 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 9 Aug 2022 14:26:11 +0200
Subject: [PATCH 3/5] wcs: add pagination for list of cards (#68037)

---
 combo/apps/wcs/forms.py                       |  1 +
 combo/apps/wcs/models.py                      |  2 +-
 combo/public/static/js/combo.public.js        | 79 ++++++++++++-------
 combo/public/templates/combo/pagination.html  |  3 +-
 combo/public/templates/combo/placeholder.html |  3 +
 combo/public/templatetags/combo.py            |  1 +
 tests/test_wcs.py                             |  9 +++
 7 files changed, 67 insertions(+), 31 deletions(-)

diff --git a/combo/apps/wcs/forms.py b/combo/apps/wcs/forms.py
index 408d1904..1813086a 100644
--- a/combo/apps/wcs/forms.py
+++ b/combo/apps/wcs/forms.py
@@ -86,6 +86,7 @@ class WcsCardInfoCellForm(forms.ModelForm):
             'carddef_reference',
             'related_card_path',
             'card_ids',
+            'limit',
             'only_for_user',
             'custom_schema',
         )
diff --git a/combo/apps/wcs/models.py b/combo/apps/wcs/models.py
index 43f054df..13d4ab8a 100644
--- a/combo/apps/wcs/models.py
+++ b/combo/apps/wcs/models.py
@@ -1384,7 +1384,7 @@ class WcsCardInfosCell(CardMixin, CellBase):
 
     @property
     def css_class_names(self):
-        return '%s card' % super().css_class_names
+        return '%s card %s' % (super().css_class_names, self.get_reference())
 
     def get_cell_extra_context(self, context):
         extra_context = super().get_cell_extra_context(context)
diff --git a/combo/public/static/js/combo.public.js b/combo/public/static/js/combo.public.js
index d489f379..0a4952db 100644
--- a/combo/public/static/js/combo.public.js
+++ b/combo/public/static/js/combo.public.js
@@ -355,48 +355,71 @@ $(function() {
     return false;
   });
 
-  // pagination in cells with list of items
-  $(document).on('combo:cell-loaded', function(ev, cell) {
-    var $pagination = $(cell).find('.cell-items-pagination');
-    if ($pagination.length == 0) return;
-    var page_index = 0;
+  function pagination_update_page(items, max_page_index, step, paginate_by, $pagination, focus_first_item) {
+    var page_index = $pagination.data('page_index') + step;
+    if (page_index == 0) {
+      $pagination.find('.cell-items-pagination-prev').prop('disabled', true);
+    } else {
+      $pagination.find('.cell-items-pagination-prev').prop('disabled', null);
+    }
+    if (page_index == max_page_index - 1) {
+      $pagination.find('.cell-items-pagination-next').prop('disabled', true);
+    } else {
+      $pagination.find('.cell-items-pagination-next').prop('disabled', null);
+    }
+    start_item = paginate_by * page_index;
+    items.hide();
+    items.slice(start_item, start_item + paginate_by).show();
+    $pagination.data('page_index', page_index);
+    if (focus_first_item) {
+      $pagination.parent().focus();
+    }
+  };
+
+  function paginate($pagination, items, must_focus) {
+    $pagination.data('page_index', 0);
     var paginate_by = parseInt($pagination.data('paginate-by'));
-    // Get all <li> inside the same div as us, ignoring whether they are part of
-    // different <ul>
-    var wrapper = $pagination.parent();
-    wrapper.attr('tabindex', -1)
-    var items = $pagination.parent().find('li');
     var max_page_index = Math.ceil(items.length / paginate_by);
     if (items.length <= paginate_by) {
       return;
     }
 
     function update_page(step, focus_first_item) {
-      page_index = page_index + step;
-      if (page_index == 0) {
-        $pagination.find('.cell-items-pagination-prev').prop('disabled', true);
-      } else {
-        $pagination.find('.cell-items-pagination-prev').prop('disabled', null);
-      }
-      if (page_index == max_page_index - 1) {
-        $pagination.find('.cell-items-pagination-next').prop('disabled', true);
-      } else {
-        $pagination.find('.cell-items-pagination-next').prop('disabled', null);
-      }
-      start_item = paginate_by * page_index;
-      items.hide();
-      items.slice(start_item, start_item + paginate_by).show();
-      if (focus_first_item) {
-        wrapper.focus()
+      if (! must_focus) {
+        focus_first_item = false;
       }
-    };
+      pagination_update_page(items, max_page_index, step, paginate_by, $pagination, focus_first_item);
+    }
 
     $pagination.find('.cell-items-pagination-prev').click(function() { update_page(-1, true); });
     $pagination.find('.cell-items-pagination-next').click(function() { update_page(1, true); });
     update_page(0, false);
     $pagination.prop('hidden', null);
+  };
+
+  function paginate_cards($pagination) {
+    var items = $pagination.parent().find('.card.' + $pagination.data('cell-reference'));
+    paginate($pagination, items, false);
+  };
+
+  // pagination for cells with list of items or for card cells
+  $(document).on('combo:cell-loaded', function(ev, cell) {
+    var $pagination = $(cell).find('.cell-items-pagination');
+    if ($pagination.length == 0) return;
+    // Get all <li> inside the same div as us, ignoring whether they are part of
+    // different <ul>
+    var wrapper = $pagination.parent();
+    wrapper.attr('tabindex', -1)
+    var items = $pagination.parent().find('li');
+    paginate($pagination, items, true);
   });
+
   $('.cell-items-pagination').each(function(idx, elem) {
-    $(document).trigger('combo:cell-loaded', $(elem).parents('.cell').first());
+    var $cells = $(elem).parents('.cell');
+    if ($cells.length) {
+      $(document).trigger('combo:cell-loaded', $cells.first());
+    } else if ($(elem).data('cell-reference')) {
+      paginate_cards($(elem));
+    }
   });
 });
diff --git a/combo/public/templates/combo/pagination.html b/combo/public/templates/combo/pagination.html
index 231c3391..7a4bdc2a 100644
--- a/combo/public/templates/combo/pagination.html
+++ b/combo/public/templates/combo/pagination.html
@@ -1,5 +1,4 @@
-{% load static %}
-<div class="cell-items-pagination" data-paginate-by="{{ paginate_by|default:10 }}" hidden>
+<div class="cell-items-pagination"{% if data_cell_reference %} data-cell-reference="{{ data_cell_reference }}"{% endif %} data-paginate-by="{{ paginate_by|default:10 }}" hidden>
   <button class="cell-items-pagination-prev" disabled>←</a>
   <button class="cell-items-pagination-next" disabled>→</a>
 </div>
diff --git a/combo/public/templates/combo/placeholder.html b/combo/public/templates/combo/placeholder.html
index 67e59f1f..b08b08e8 100644
--- a/combo/public/templates/combo/placeholder.html
+++ b/combo/public/templates/combo/placeholder.html
@@ -16,6 +16,9 @@
      {% if extra_context %}data-extra-context="{{ extra_context|signed|urlencode }}"{% endif %}
      {% endwith %}
      ><div>{% render_cell cell %}</div></div>
+{% if cell.include_pagination %}
+{% include "combo/pagination.html" with paginate_by=cell.limit data_cell_reference=cell.get_reference %}
+{% endif %}
 {% endfor %}
 {% if placeholder_options.fx_grid_layout %}</div>{% endif %}
 {% if outer_tag %}</{{outer_tag|default:"div"}}>{% endif %}
diff --git a/combo/public/templatetags/combo.py b/combo/public/templatetags/combo.py
index f9bfdae9..d8556903 100644
--- a/combo/public/templatetags/combo.py
+++ b/combo/public/templatetags/combo.py
@@ -127,6 +127,7 @@ def placeholder(context, placeholder_name, **options):
             for i in range(repeat):
                 new_cell = copy.copy(cell)
                 new_cell.repeat_index = i
+                new_cell.include_pagination = bool(i + 1 == repeat)
                 repeated_cells.append(new_cell)
             context['cells'][cell_idx:cell_idx] = repeated_cells
 
diff --git a/tests/test_wcs.py b/tests/test_wcs.py
index 465e869b..cc468da2 100644
--- a/tests/test_wcs.py
+++ b/tests/test_wcs.py
@@ -2696,6 +2696,15 @@ def test_card_cell_render(mock_send, context, app):
     assert len(resp.context['cells']) == 3
     for i in range(0, 3):
         assert '<h2>Foo bar X%sY</h2>' % i in resp
+    assert 'data-paginate-by="10"' in resp
+
+    cell.limit = 42
+    cell.save()
+    resp = app.get(page.get_online_url())
+    assert len(resp.context['cells']) == 3
+    for i in range(0, 3):
+        assert '<h2>Foo bar X%sY</h2>' % i in resp
+    assert 'data-paginate-by="42"' in resp
 
     # using custom view
     cell.carddef_reference = 'default:card_model_1:foo'
-- 
2.35.1

