kopia lustrzana https://github.com/wagtail/wagtail
rodzic
bdfa3811d1
commit
8c97c254a7
|
@ -440,9 +440,11 @@ Structural block types
|
||||||
]))),
|
]))),
|
||||||
])
|
])
|
||||||
|
|
||||||
The following additional option is available as either a keyword argument or a Meta class attribute:
|
The following additional options are available as either keyword arguments or Meta class attributes:
|
||||||
|
|
||||||
:param form_classname: An HTML ``class`` attribute to set on the root element of this block as displayed in the editing interface.
|
:param form_classname: An HTML ``class`` attribute to set on the root element of this block as displayed in the editing interface.
|
||||||
|
:param min_num: Minimum number of sub-blocks that the list must have.
|
||||||
|
:param max_num: Maximum number of sub-blocks that the list may have.
|
||||||
|
|
||||||
|
|
||||||
.. class:: wagtail.core.blocks.StreamBlock
|
.. class:: wagtail.core.blocks.StreamBlock
|
||||||
|
|
|
@ -98,6 +98,16 @@ class ListBlock(Block):
|
||||||
else:
|
else:
|
||||||
errors.append(None)
|
errors.append(None)
|
||||||
|
|
||||||
|
if self.meta.min_num is not None and self.meta.min_num > len(value):
|
||||||
|
non_block_errors.append(ValidationError(
|
||||||
|
_('The minimum number of items is %d') % self.meta.min_num
|
||||||
|
))
|
||||||
|
|
||||||
|
if self.meta.max_num is not None and self.meta.max_num < len(value):
|
||||||
|
non_block_errors.append(ValidationError(
|
||||||
|
_('The maximum number of items is %d') % self.meta.max_num
|
||||||
|
))
|
||||||
|
|
||||||
if any(errors) or non_block_errors:
|
if any(errors) or non_block_errors:
|
||||||
raise ListBlockValidationError(block_errors=errors, non_block_errors=non_block_errors)
|
raise ListBlockValidationError(block_errors=errors, non_block_errors=non_block_errors)
|
||||||
|
|
||||||
|
@ -172,6 +182,10 @@ class ListBlock(Block):
|
||||||
# descendant block type
|
# descendant block type
|
||||||
icon = "placeholder"
|
icon = "placeholder"
|
||||||
form_classname = None
|
form_classname = None
|
||||||
|
min_num = None
|
||||||
|
max_num = None
|
||||||
|
|
||||||
|
MUTABLE_META_ATTRIBUTES = ['min_num', 'max_num']
|
||||||
|
|
||||||
|
|
||||||
class ListBlockAdapter(Adapter):
|
class ListBlockAdapter(Adapter):
|
||||||
|
@ -193,6 +207,12 @@ class ListBlockAdapter(Adapter):
|
||||||
meta['helpText'] = help_text
|
meta['helpText'] = help_text
|
||||||
meta['helpIcon'] = get_help_icon()
|
meta['helpIcon'] = get_help_icon()
|
||||||
|
|
||||||
|
if block.meta.min_num is not None:
|
||||||
|
meta['minNum'] = block.meta.min_num
|
||||||
|
|
||||||
|
if block.meta.max_num is not None:
|
||||||
|
meta['maxNum'] = block.meta.max_num
|
||||||
|
|
||||||
return [
|
return [
|
||||||
block.name,
|
block.name,
|
||||||
block.child_block,
|
block.child_block,
|
||||||
|
|
|
@ -2179,6 +2179,34 @@ class TestListBlock(WagtailTestUtils, SimpleTestCase):
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_adapt_with_min_num_max_num(self):
|
||||||
|
class LinkBlock(blocks.StructBlock):
|
||||||
|
title = blocks.CharBlock()
|
||||||
|
link = blocks.URLBlock()
|
||||||
|
|
||||||
|
block = blocks.ListBlock(LinkBlock, min_num=2, max_num=5)
|
||||||
|
|
||||||
|
block.set_name('test_listblock')
|
||||||
|
js_args = ListBlockAdapter().js_args(block)
|
||||||
|
|
||||||
|
self.assertEqual(js_args[0], 'test_listblock')
|
||||||
|
self.assertIsInstance(js_args[1], LinkBlock)
|
||||||
|
self.assertEqual(js_args[2], {'title': None, 'link': None})
|
||||||
|
self.assertEqual(js_args[3], {
|
||||||
|
'label': 'Test listblock',
|
||||||
|
'icon': 'placeholder',
|
||||||
|
'classname': None,
|
||||||
|
'minNum': 2,
|
||||||
|
'maxNum': 5,
|
||||||
|
'strings': {
|
||||||
|
'DELETE': 'Delete',
|
||||||
|
'DUPLICATE': 'Duplicate',
|
||||||
|
'MOVE_DOWN': 'Move down',
|
||||||
|
'MOVE_UP': 'Move up',
|
||||||
|
'ADD': 'Add',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
def test_searchable_content(self):
|
def test_searchable_content(self):
|
||||||
class LinkBlock(blocks.StructBlock):
|
class LinkBlock(blocks.StructBlock):
|
||||||
title = blocks.CharBlock()
|
title = blocks.CharBlock()
|
||||||
|
@ -2332,6 +2360,32 @@ class TestListBlock(WagtailTestUtils, SimpleTestCase):
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_min_num_validation_errors(self):
|
||||||
|
block = blocks.ListBlock(blocks.CharBlock(), min_num=2)
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError) as catcher:
|
||||||
|
block.clean(['foo'])
|
||||||
|
self.assertEqual(catcher.exception.params, {
|
||||||
|
'block_errors': [None],
|
||||||
|
'non_block_errors': ['The minimum number of items is 2']
|
||||||
|
})
|
||||||
|
|
||||||
|
# a value with >= 2 blocks should pass validation
|
||||||
|
self.assertTrue(block.clean(['foo', 'bar']))
|
||||||
|
|
||||||
|
def test_max_num_validation_errors(self):
|
||||||
|
block = blocks.ListBlock(blocks.CharBlock(), max_num=2)
|
||||||
|
|
||||||
|
with self.assertRaises(ValidationError) as catcher:
|
||||||
|
block.clean(['foo', 'bar', 'baz'])
|
||||||
|
self.assertEqual(catcher.exception.params, {
|
||||||
|
'block_errors': [None, None, None],
|
||||||
|
'non_block_errors': ['The maximum number of items is 2']
|
||||||
|
})
|
||||||
|
|
||||||
|
# a value with <= 2 blocks should pass validation
|
||||||
|
self.assertTrue(block.clean(['foo', 'bar']))
|
||||||
|
|
||||||
|
|
||||||
class TestListBlockWithFixtures(TestCase):
|
class TestListBlockWithFixtures(TestCase):
|
||||||
fixtures = ['test.json']
|
fixtures = ['test.json']
|
||||||
|
|
Ładowanie…
Reference in New Issue