Allow specifying a format for the label of a collapsed StructBlock

Currently, the label shown for a StructBlock's collapsed representation takes its content from the first sub-block of the StructBlock, which isn't always what you want. Add a new `label_format` meta option to StructBlock to allow customising this - e.g. `label_format = "Profile for {first_name} {surname}"`
pull/7486/head
Matt Westcott 2021-09-09 22:58:10 +01:00
rodzic 27c3e7921a
commit 0380f01b24
6 zmienionych plików z 37 dodań i 1 usunięć

Wyświetl plik

@ -25,6 +25,7 @@ Changelog
* Open Preview and Live page links in the same tab, except where it would interrupt editing a Page (Sagar Agarwal)
* Added `ExcelDateFormatter` to `wagtail.admin.views.mixins` so that dates in Excel exports will appear in the locale's `SHORT_DATETIME_FORMAT` (Andrew Stone)
* Add TIDAL support to the list of oEmbed providers (Wout De Puysseleir)
* Add `label_format` attribute to customise the label shown for a collapsed StructBlock (Matt Westcott)
* Fix: Delete button is now correct colour on snippets and modeladmin listings (Brandon Murch)
* Fix: Ensure that StreamBlock / ListBlock-level validation errors are counted towards error counts (Matt Westcott)
* Fix: InlinePanel add button is now keyboard navigatable (Jesse Menn)

Wyświetl plik

@ -114,7 +114,23 @@ export class StructBlock {
}
getTextLabel(opts) {
/* Use the text label of the first child block to return one */
if (this.blockDef.meta.labelFormat) {
/* use labelFormat - regexp replace any field references like '{first_name}'
with the text label of that sub-block */
return this.blockDef.meta.labelFormat.replace(/\{(\w+)\}/g, (tag, blockName) => {
const block = this.childBlocks[blockName];
if (block.getTextLabel) {
/* to be strictly correct, we should be adjusting opts.maxLength to account for the overheads
in the format string, and dividing the remainder across all the placeholders in the string,
rather than just passing opts on to the child. But that would get complicated, and this is
better than nothing... */
return block.getTextLabel(opts);
}
return '';
});
}
/* if no labelFormat specified, just try each child block in turn until we find one that provides a label */
for (const childDef of this.blockDef.childBlockDefs) {
const child = this.childBlocks[childDef.name];
if (child.getTextLabel) {

Wyświetl plik

@ -31,6 +31,7 @@ class DummyWidgetDefinition {
setState(state) { setState(widgetName, state); },
getState() { getState(widgetName); return `state: ${widgetName} - ${name}`; },
getValue() { getValue(widgetName); return `value: ${widgetName} - ${name}`; },
getTextLabel() { return `label: ${name}`; },
focus() { focus(widgetName); },
idForLabel: id,
};
@ -159,6 +160,10 @@ describe('telepath: wagtail.blocks.StructBlock', () => {
expect(focus.mock.calls[0][0]).toBe('Heading widget');
});
test('getTextLabel() returns text label of first widget', () => {
expect(boundBlock.getTextLabel()).toBe('label: the-prefix-heading_text');
});
test('setError passes error messages to children', () => {
boundBlock.setError([
new StructBlockValidationError({
@ -215,6 +220,7 @@ describe('telepath: wagtail.blocks.StructBlock with formTemplate', () => {
<p>and here is the second:</p>
<div data-structblock-child="size"></div>
</div>`,
labelFormat: '{heading_text} - {size}',
}
);
@ -287,4 +293,10 @@ describe('telepath: wagtail.blocks.StructBlock with formTemplate', () => {
expect(focus.mock.calls.length).toBe(1);
expect(focus.mock.calls[0][0]).toBe('Heading widget');
});
test('getTextLabel() returns text label according to labelFormat', () => {
expect(boundBlock.getTextLabel()).toBe(
'label: the-prefix-heading_text - label: the-prefix-size'
);
});
});

Wyświetl plik

@ -414,6 +414,8 @@ Structural block types
:param form_classname: An HTML ``class`` attribute to set on the root element of this block as displayed in the editing interface. Defaults to ``struct-block``; note that the admin interface has CSS styles defined on this class, so it is advised to include ``struct-block`` in this value when overriding. See :ref:`custom_editing_interfaces_for_structblock`.
:param form_template: Path to a Django template to use to render this block's form. See :ref:`custom_editing_interfaces_for_structblock`.
:param value_class: A subclass of ``wagtail.core.blocks.StructValue`` to use as the type of returned values for this block. See :ref:`custom_value_class_for_structblock`.
:param label_format:
Determines the label shown when the block is collapsed in the editing interface. By default, the value of the first sub-block in the StructBlock is shown, but this can be customised by setting a string here with block names contained in braces - e.g. ``label_format = "Profile for {first_name} {surname}"``
.. class:: wagtail.core.blocks.ListBlock

Wyświetl plik

@ -36,6 +36,7 @@ Other features
* Open Preview and Live page links in the same tab, except where it would interrupt editing a Page (Sagar Agarwal)
* Added ``ExcelDateFormatter`` to ``wagtail.admin.views.mixins`` so that dates in Excel exports will appear in the locale's ``SHORT_DATETIME_FORMAT`` (Andrew Stone)
* Add TIDAL support to the list of oEmbed providers (Wout De Puysseleir)
* Add ``label_format`` attribute to customise the label shown for a collapsed StructBlock (Matt Westcott)
Bug fixes
~~~~~~~~~

Wyświetl plik

@ -274,6 +274,7 @@ class BaseStructBlock(Block):
form_classname = 'struct-block'
form_template = None
value_class = StructValue
label_format = None
# No icon specified here, because that depends on the purpose that the
# block is being used for. Feel encouraged to specify an icon in your
# descendant block type
@ -301,6 +302,9 @@ class StructBlockAdapter(Adapter):
if block.meta.form_template:
meta['formTemplate'] = block.render_form_template()
if block.meta.label_format:
meta['labelFormat'] = block.meta.label_format
return [
block.name,
block.child_blocks.values(),