Projet

Général

Profil

0001-blocks-min_items-configuration-58450.patch

Lauréline Guérin, 12 novembre 2021 10:07

Télécharger (10,3 ko)

Voir les différences:

Subject: [PATCH] blocks: min_items configuration (#58450)

 tests/form_pages/test_block.py                | 91 +++++++++++++++++++
 wcs/blocks.py                                 | 15 ++-
 wcs/fields.py                                 | 12 ++-
 wcs/qommon/form.py                            |  6 +-
 wcs/qommon/static/js/qommon.forms.js          |  4 +-
 wcs/qommon/templates/qommon/forms/widget.html |  1 +
 .../templates/qommon/forms/widgets/block.html |  1 +
 7 files changed, 122 insertions(+), 8 deletions(-)
tests/form_pages/test_block.py
895 895
    assert '>bar2<' in resp
896 896

  
897 897

  
898
def test_block_repeated_with_min(pub):
899
    FormDef.wipe()
900
    BlockDef.wipe()
901

  
902
    block = BlockDef()
903
    block.name = 'foobar'
904
    block.fields = [
905
        fields.StringField(id='123', required=True, label='Test', type='string'),
906
        fields.StringField(id='234', required=True, label='Test2', type='string'),
907
    ]
908
    block.store()
909

  
910
    formdef = FormDef()
911
    formdef.name = 'form title'
912
    formdef.fields = [
913
        fields.PageField(id='0', label='1st page', type='page'),
914
        fields.BlockField(
915
            id='1', label='test', type='block:foobar', min_items=2, max_items=3, hint='hintblock'
916
        ),
917
        fields.PageField(id='2', label='2nd page', type='page'),
918
    ]
919
    formdef.store()
920

  
921
    app = get_app(pub)
922
    resp = app.get(formdef.get_url())
923
    assert resp.text.count('>Test<') == 2
924
    assert resp.text.count('>hintblock<') == 1
925
    assert 'wcs-block-add-clicked' not in resp
926
    assert 'Add another' in resp
927
    assert resp.html.find('div', {'class': 'list-add'})
928
    resp = resp.form.submit('f1$add_element')
929
    assert resp.text.count('>Test<') == 3
930
    assert resp.text.count('>hintblock<') == 1
931
    assert resp.pyquery('.list-add').attr['style'] == 'display: none'
932

  
933
    formdef.fields[1].min_items = 3
934
    formdef.store()
935

  
936
    app = get_app(pub)
937
    resp = app.get(formdef.get_url())
938
    assert resp.text.count('>Test<') == 3
939
    assert resp.text.count('>hintblock<') == 1
940
    assert resp.pyquery('.list-add').attr['style'] == 'display: none'
941

  
942
    formdef.fields[1].min_items = 4
943
    formdef.store()
944
    app = get_app(pub)
945
    resp = app.get(formdef.get_url())
946
    assert resp.text.count('>Test<') == 3
947

  
948

  
898 949
def test_block_repeated_over_limit(pub):
899 950
    FormDef.wipe()
900 951
    BlockDef.wipe()
......
943 994
    assert 'Too many elements (maximum: 2)' in resp
944 995

  
945 996

  
997
def test_block_repeated_under_limit(pub):
998
    FormDef.wipe()
999
    BlockDef.wipe()
1000

  
1001
    block = BlockDef()
1002
    block.name = 'foobar'
1003
    block.fields = [
1004
        fields.StringField(id='123', required=True, label='Test', type='string'),
1005
        fields.StringField(id='234', required=True, label='Test2', type='string'),
1006
    ]
1007
    block.store()
1008

  
1009
    formdef = FormDef()
1010
    formdef.name = 'form title'
1011
    formdef.fields = [
1012
        fields.PageField(id='0', label='1st page', type='page'),
1013
        fields.BlockField(id='1', label='test', type='block:foobar', min_items=2, max_items=3),
1014
        fields.PageField(id='2', label='2nd page', type='page'),
1015
    ]
1016
    formdef.store()
1017

  
1018
    app = get_app(pub)
1019
    resp = app.get(formdef.get_url())
1020
    assert resp.text.count('>Test<') == 2
1021

  
1022
    # fill items
1023
    resp.form['f1$element0$f123'] = 'foo'
1024
    resp.form['f1$element0$f234'] = 'bar'
1025

  
1026
    # submit form - it's ok to have empty block items if block fields are not required
1027
    resp = resp.form.submit('submit')
1028
    resp = resp.form.submit('submit')  # -> validation page
1029
    resp = resp.form.submit('submit')  # -> submit
1030
    resp = resp.follow()
1031
    assert '>foo<' in resp
1032
    assert '>bar<' in resp
1033
    formdata = formdef.data_class().select()[0]
1034
    assert len(formdata.data['1']['data']) == 1
1035

  
1036

  
946 1037
def test_block_repeated_files(pub):
947 1038
    FormDef.wipe()
948 1039
    BlockDef.wipe()
wcs/blocks.py
245 245
    always_include_add_button = True
246 246

  
247 247
    def __init__(
248
        self, name, value=None, title=None, block=None, max_items=None, add_element_label=None, **kwargs
248
        self,
249
        name,
250
        value=None,
251
        title=None,
252
        block=None,
253
        min_items=None,
254
        max_items=None,
255
        add_element_label=None,
256
        **kwargs,
249 257
    ):
250 258
        self.block = block
251 259
        self.readonly = kwargs.get('readonly')
......
254 262
        element_values = None
255 263
        if value:
256 264
            element_values = value.get('data')
257
        if not max_items:
258
            max_items = 1
265
        max_items = max_items or 1
266
        min_items = min(min_items or 1, max_items)
259 267
        hint = kwargs.pop('hint', None)
260 268
        element_kwargs = {'block': self.block, 'render_br': False, 'remove_button': self.remove_button}
261 269
        element_kwargs.update(kwargs)
......
263 271
            name,
264 272
            value=element_values,
265 273
            title=title,
274
            min_items=min_items,
266 275
            max_items=max_items,
267 276
            element_type=BlockSubWidget,
268 277
            element_kwargs=element_kwargs,
wcs/fields.py
3323 3323
    allow_complex = True
3324 3324

  
3325 3325
    widget_class = BlockWidget
3326
    min_items = 1
3326 3327
    max_items = 1
3327
    extra_attributes = ['block', 'max_items', 'add_element_label', 'label_display', 'remove_button']
3328
    extra_attributes = [
3329
        'block',
3330
        'min_items',
3331
        'max_items',
3332
        'add_element_label',
3333
        'label_display',
3334
        'remove_button',
3335
    ]
3328 3336
    add_element_label = ''
3329 3337
    label_display = 'normal'
3330 3338
    remove_button = False
......
3346 3354
        super().fill_admin_form(form)
3347 3355
        if form.get_widget('prefill'):
3348 3356
            form.remove('prefill')
3357
        form.add(IntWidget, 'min_items', title=_('Minimum number of items'), value=self.min_items)
3349 3358
        form.add(IntWidget, 'max_items', title=_('Maximum number of items'), value=self.max_items)
3350 3359
        form.add(
3351 3360
            StringWidget, 'add_element_label', title=_('Label of "Add" button'), value=self.add_element_label
......
3366 3375

  
3367 3376
    def get_admin_attributes(self):
3368 3377
        return super().get_admin_attributes() + [
3378
            'min_items',
3369 3379
            'max_items',
3370 3380
            'add_element_label',
3371 3381
            'label_display',
wcs/qommon/form.py
1682 1682
        element_type=StringWidget,
1683 1683
        element_kwargs=None,
1684 1684
        add_element_label="Add row",
1685
        min_items=None,
1685 1686
        max_items=None,
1686 1687
        **kwargs,
1687 1688
    ):
......
1695 1696
        self.element_type = element_type
1696 1697
        self.element_kwargs = element_kwargs or {}
1697 1698
        self.element_names = []
1699
        self.min_items = min_items or 1
1698 1700
        self.max_items = max_items
1699 1701

  
1700 1702
        # Add element widgets for initial value
1701 1703
        if value is not None:
1702 1704
            for element_value in value:
1703 1705
                self.add_element(value=element_value)
1704
        if not self.element_names:
1705
            # Add at least an element widget
1706
        while len(self.element_names) < self.min_items:
1707
            # Add elements until min_items
1706 1708
            self.add_element()
1707 1709

  
1708 1710
        if not kwargs.get('readonly'):
wcs/qommon/static/js/qommon.forms.js
516 516

  
517 517
  function disable_single_block_remove_button() {
518 518
    $('.BlockSubWidget button.remove-button').each(function(i, elem) {
519
      if ($(this).parents('.BlockWidget').find('.BlockSubWidget').length == 1) {
519
      if ($(this).parents('.BlockWidget').find('.BlockSubWidget').length == parseInt($(this).parents('.BlockWidget').data('min-items'), 10)) {
520 520
        $(this).prop('disabled', true);
521 521
      }
522 522
    });
......
525 525
  if ($('.BlockWidget').length) {
526 526
    disable_single_block_remove_button();
527 527
    $('form').on('click', '.BlockSubWidget button.remove-button', function() {
528
      if ($(this).parents('.BlockWidget').find('.BlockSubWidget').length > 1) {
528
      if ($(this).parents('.BlockWidget').find('.BlockSubWidget').length > parseInt($(this).parents('.BlockWidget').data('min-items'), 10)) {
529 529
        $(this).parents('.BlockWidget').find('.list-add').show();
530 530
        $(this).parents('.BlockSubWidget').remove();
531 531
        disable_single_block_remove_button();
wcs/qommon/templates/qommon/forms/widget.html
20 20
     data-dynamic-display-value-in="{{widget.attrs|get:"data-dynamic-display-value-in"}}"
21 21
     {% endif %}
22 22
     {% if widget.live_condition_source %}data-live-source="true"{% endif %}
23
     {% block widget-extra-data %}{% endblock %}
23 24
     >
24 25
  {% block widget-title %}
25 26
  {{widget.rendered_title}}
wcs/qommon/templates/qommon/forms/widgets/block.html
1 1
{% extends "qommon/forms/widget.html" %}
2 2

  
3 3
{% block widget-css-classes %}{{ block.super }} {% if widget.had_add_clicked %}wcs-block-add-clicked{% endif %} {% if widget.remove_button %}wcs-block-with-remove-button{% endif %}{% endblock %}
4
{% block widget-extra-data %}data-min-items={{ widget.min_items }}{% endblock %}
4
-