kopia lustrzana https://github.com/wagtail/wagtail
				
				
				
			Add optional caption field to TypedTableBlock
- Closes #8507 - Make caption default to "" for tables that predate adding the caption field - Update the html generated in JS so the rendered form matches our new styles - Use a consistent period (full stop) at the end of the help text sentence (including table fields)pull/11327/head
							rodzic
							
								
									0ec50f0d82
								
							
						
					
					
						commit
						a4c18b4957
					
				| 
						 | 
				
			
			@ -37,6 +37,7 @@ Changelog
 | 
			
		|||
 * Show character counts on RichTextBlock with `max_length` (Elhussein Almasri)
 | 
			
		||||
 * Move locale selector in generic IndexView to a filter (Sage Abdullah)
 | 
			
		||||
 * Add ability to customise a page's copy form (Neeraj Yetheendran)
 | 
			
		||||
 * Add optional caption field to `TypedTableBlock` (Tommaso Amici, Cynthia Kiser)
 | 
			
		||||
 * Fix: Update system check for overwriting storage backends to recognise the `STORAGES` setting introduced in Django 4.2 (phijma-leukeleu)
 | 
			
		||||
 * Fix: Prevent password change form from raising a validation error when browser autocomplete fills in the "Old password" field (Chiemezuo Akujobi)
 | 
			
		||||
 * Fix: Ensure that the legacy dropdown options, when closed, do not get accidentally clicked by other interactions wide viewports (CheesyPhoenix, Christer Jensen)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -782,6 +782,7 @@
 | 
			
		|||
* Badr Fourane
 | 
			
		||||
* Vaishnav Dasari
 | 
			
		||||
* Aditya
 | 
			
		||||
* Tommaso Amici
 | 
			
		||||
 | 
			
		||||
## Translators
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ exports[`telepath: wagtail.widgets.TableInput it renders correctly 1`] = `
 | 
			
		|||
        <label class="w-field__label" for="the-id-handsontable-col-caption">Table caption</label>
 | 
			
		||||
        <div class="w-field w-field--char_field w-field--text_input" data-field="">
 | 
			
		||||
          <div class="w-field__help" id="the-id-handsontable-col-caption-helptext" data-field-help="">
 | 
			
		||||
            <div class="help">A heading that identifies the overall topic of the table, and is useful for screen reader users</div>
 | 
			
		||||
            <div class="help">A heading that identifies the overall topic of the table, and is useful for screen reader users.</div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="w-field__input" data-field-input="">
 | 
			
		||||
            <input type="text" id="the-id-handsontable-col-caption" name="handsontable-col-caption" aria-describedby="the-id-handsontable-col-caption-helptext">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -263,7 +263,7 @@ class TableInput {
 | 
			
		|||
        <label class="w-field__label" for="${id}-handsontable-col-caption">${this.strings['Table caption']}</label>
 | 
			
		||||
        <div class="w-field w-field--char_field w-field--text_input" data-field>
 | 
			
		||||
          <div class="w-field__help" id="${id}-handsontable-col-caption-helptext" data-field-help>
 | 
			
		||||
            <div class="help">${this.strings['A heading that identifies the overall topic of the table, and is useful for screen reader users']}</div>
 | 
			
		||||
            <div class="help">${this.strings['A heading that identifies the overall topic of the table, and is useful for screen reader users.']}</div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="w-field__input" data-field-input>
 | 
			
		||||
            <input type="text" id="${id}-handsontable-col-caption" name="handsontable-col-caption" aria-describedby="${id}-handsontable-col-caption-helptext" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,8 +40,8 @@ const TEST_STRINGS = {
 | 
			
		|||
    'Display the first column as a header.',
 | 
			
		||||
  'Table caption': 'Table caption',
 | 
			
		||||
 | 
			
		||||
  'A heading that identifies the overall topic of the table, and is useful for screen reader users':
 | 
			
		||||
    'A heading that identifies the overall topic of the table, and is useful for screen reader users',
 | 
			
		||||
  'A heading that identifies the overall topic of the table, and is useful for screen reader users.':
 | 
			
		||||
    'A heading that identifies the overall topic of the table, and is useful for screen reader users.',
 | 
			
		||||
  'Table': 'Table',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +163,7 @@ describe('telepath: wagtail.widgets.TableInput', () => {
 | 
			
		|||
        "Affichez la première colonne sous forme d'en-tête.",
 | 
			
		||||
      'Table caption': 'Légende du tableau',
 | 
			
		||||
 | 
			
		||||
      'A heading that identifies the overall topic of the table, and is useful for screen reader users':
 | 
			
		||||
      'A heading that identifies the overall topic of the table, and is useful for screen reader users.':
 | 
			
		||||
        "Un en-tête qui identifie le sujet général du tableau et qui est utile pour les utilisateurs de lecteurs d'écran",
 | 
			
		||||
      'Table': 'Tableau',
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,22 @@
 | 
			
		|||
 | 
			
		||||
exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock it renders correctly 1`] = `
 | 
			
		||||
"<div class="typed-table-block ">
 | 
			
		||||
        <div class="w-field__wrapper" data-field-wrapper="">
 | 
			
		||||
          <label class="w-field__label" for="mytable-caption">
 | 
			
		||||
            Caption
 | 
			
		||||
          </label>
 | 
			
		||||
          <div class="w-field w-field--char_field w-field--text_input" data-field="">
 | 
			
		||||
            <div class="w-field__help" data-field-help="">
 | 
			
		||||
              <div class="help">
 | 
			
		||||
                A heading that identifies the overall topic of the table, and is useful for screen reader users.
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="w-field__input" data-field-input="">
 | 
			
		||||
              <input type="text" id="mytable-caption" name="mytable-caption" value="">
 | 
			
		||||
              <span></span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <input type="hidden" name="mytable-column-count" data-column-count="" value="2">
 | 
			
		||||
        <input type="hidden" name="mytable-row-count" data-row-count="" value="2">
 | 
			
		||||
        <div data-deleted-fields=""><input type="hidden" name="mytable-column-0-deleted" value=""><input type="hidden" name="mytable-column-1-deleted" value=""><input type="hidden" name="mytable-row-0-deleted" value=""><input type="hidden" name="mytable-row-1-deleted" value=""></div>
 | 
			
		||||
| 
						 | 
				
			
			@ -92,6 +108,22 @@ exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock it renders cor
 | 
			
		|||
 | 
			
		||||
exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock setError passes error messages to children 1`] = `
 | 
			
		||||
"<div class="typed-table-block ">
 | 
			
		||||
        <div class="w-field__wrapper" data-field-wrapper="">
 | 
			
		||||
          <label class="w-field__label" for="mytable-caption">
 | 
			
		||||
            Caption
 | 
			
		||||
          </label>
 | 
			
		||||
          <div class="w-field w-field--char_field w-field--text_input" data-field="">
 | 
			
		||||
            <div class="w-field__help" data-field-help="">
 | 
			
		||||
              <div class="help">
 | 
			
		||||
                A heading that identifies the overall topic of the table, and is useful for screen reader users.
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="w-field__input" data-field-input="">
 | 
			
		||||
              <input type="text" id="mytable-caption" name="mytable-caption" value="">
 | 
			
		||||
              <span></span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <input type="hidden" name="mytable-column-count" data-column-count="" value="2">
 | 
			
		||||
        <input type="hidden" name="mytable-row-count" data-row-count="" value="2">
 | 
			
		||||
        <div data-deleted-fields=""><input type="hidden" name="mytable-column-0-deleted" value=""><input type="hidden" name="mytable-column-1-deleted" value=""><input type="hidden" name="mytable-row-0-deleted" value=""><input type="hidden" name="mytable-row-1-deleted" value=""></div>
 | 
			
		||||
| 
						 | 
				
			
			@ -182,6 +214,22 @@ exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock setError passe
 | 
			
		|||
 | 
			
		||||
exports[`wagtail.contrib.typed_table_block.blocks.TypedTableBlock setError shows non-block errors 1`] = `
 | 
			
		||||
"<div class="typed-table-block "><p class="help-block help-critical">This is just generally wrong</p>
 | 
			
		||||
        <div class="w-field__wrapper" data-field-wrapper="">
 | 
			
		||||
          <label class="w-field__label" for="mytable-caption">
 | 
			
		||||
            Caption
 | 
			
		||||
          </label>
 | 
			
		||||
          <div class="w-field w-field--char_field w-field--text_input" data-field="">
 | 
			
		||||
            <div class="w-field__help" data-field-help="">
 | 
			
		||||
              <div class="help">
 | 
			
		||||
                A heading that identifies the overall topic of the table, and is useful for screen reader users.
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="w-field__input" data-field-input="">
 | 
			
		||||
              <input type="text" id="mytable-caption" name="mytable-caption" value="">
 | 
			
		||||
              <span></span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <input type="hidden" name="mytable-column-count" data-column-count="" value="2">
 | 
			
		||||
        <input type="hidden" name="mytable-row-count" data-row-count="" value="2">
 | 
			
		||||
        <div data-deleted-fields=""><input type="hidden" name="mytable-column-0-deleted" value=""><input type="hidden" name="mytable-column-1-deleted" value=""><input type="hidden" name="mytable-row-0-deleted" value=""><input type="hidden" name="mytable-row-1-deleted" value=""></div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,8 @@ export class TypedTableBlock {
 | 
			
		|||
    this.blockDef = blockDef;
 | 
			
		||||
    this.type = blockDef.name;
 | 
			
		||||
 | 
			
		||||
    this.caption = '';
 | 
			
		||||
 | 
			
		||||
    // list of column definition objects, each consisting of fields:
 | 
			
		||||
    // * blockDef: the block definition object
 | 
			
		||||
    // * position: the 0-indexed position of this column within the list of columns
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +46,25 @@ export class TypedTableBlock {
 | 
			
		|||
    });
 | 
			
		||||
 | 
			
		||||
    const strings = this.blockDef.meta.strings;
 | 
			
		||||
    const captionID = `${h(prefix)}-caption`;
 | 
			
		||||
    const dom = $(`
 | 
			
		||||
      <div class="typed-table-block ${h(this.blockDef.meta.classname || '')}">
 | 
			
		||||
        <div class="w-field__wrapper" data-field-wrapper>
 | 
			
		||||
          <label class="w-field__label" for="${captionID}">
 | 
			
		||||
            ${strings.CAPTION}
 | 
			
		||||
          </label>
 | 
			
		||||
          <div class="w-field w-field--char_field w-field--text_input" data-field>
 | 
			
		||||
            <div class="w-field__help" data-field-help>
 | 
			
		||||
              <div class="help">
 | 
			
		||||
                ${strings.CAPTION_HELP_TEXT}
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="w-field__input" data-field-input>
 | 
			
		||||
              <input type="text" id="${captionID}" name="${captionID}" value="" />
 | 
			
		||||
              <span></span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <input type="hidden" name="${h(
 | 
			
		||||
          prefix,
 | 
			
		||||
        )}-column-count" data-column-count value="0">
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +108,7 @@ export class TypedTableBlock {
 | 
			
		|||
    `);
 | 
			
		||||
    $(placeholder).replaceWith(dom);
 | 
			
		||||
    this.container = dom;
 | 
			
		||||
    this.captionInput = dom.find(`#${captionID}`).get(0);
 | 
			
		||||
    this.thead = dom.find('table > thead').get(0);
 | 
			
		||||
    this.tbody = dom.find('table > tbody').get(0);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -175,6 +195,7 @@ export class TypedTableBlock {
 | 
			
		|||
 | 
			
		||||
  clear() {
 | 
			
		||||
    // reset to initial empty state with no rows or columns
 | 
			
		||||
    this.setCaption('');
 | 
			
		||||
    this.columns = [];
 | 
			
		||||
    this.rows = [];
 | 
			
		||||
    this.columnCountIncludingDeleted = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +223,11 @@ export class TypedTableBlock {
 | 
			
		|||
    this.addRowButton.hide();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCaption(caption) {
 | 
			
		||||
    this.caption = caption;
 | 
			
		||||
    this.captionInput.value = caption;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  insertColumn(index, blockDef, opts) {
 | 
			
		||||
    const column = {
 | 
			
		||||
      blockDef,
 | 
			
		||||
| 
						 | 
				
			
			@ -454,6 +480,7 @@ export class TypedTableBlock {
 | 
			
		|||
      state.rows.forEach((row, index) => {
 | 
			
		||||
        this.insertRow(index, row.values);
 | 
			
		||||
      });
 | 
			
		||||
      this.setCaption(state.caption);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -483,6 +510,7 @@ export class TypedTableBlock {
 | 
			
		|||
      rows: this.rows.map((row) => ({
 | 
			
		||||
        values: row.blocks.map((block) => block.getState()),
 | 
			
		||||
      })),
 | 
			
		||||
      caption: this.caption,
 | 
			
		||||
    };
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -506,6 +534,7 @@ export class TypedTableBlock {
 | 
			
		|||
      rows: this.rows.map((row) => ({
 | 
			
		||||
        values: row.blocks.map((block) => block.getValue()),
 | 
			
		||||
      })),
 | 
			
		||||
      caption: this.caption,
 | 
			
		||||
    };
 | 
			
		||||
    return value;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,6 +101,9 @@ describe('wagtail.contrib.typed_table_block.blocks.TypedTableBlock', () => {
 | 
			
		|||
        helpText: 'use <strong>plenty</strong> of these',
 | 
			
		||||
        helpIcon: '<svg></svg>',
 | 
			
		||||
        strings: {
 | 
			
		||||
          CAPTION: 'Caption',
 | 
			
		||||
          CAPTION_HELP_TEXT:
 | 
			
		||||
            'A heading that identifies the overall topic of the table, and is useful for screen reader users.',
 | 
			
		||||
          ADD_COLUMN: 'Add column',
 | 
			
		||||
          ADD_ROW: 'Add row',
 | 
			
		||||
          COLUMN_HEADING: 'Column heading',
 | 
			
		||||
| 
						 | 
				
			
			@ -123,6 +126,7 @@ describe('wagtail.contrib.typed_table_block.blocks.TypedTableBlock', () => {
 | 
			
		|||
          { type: 'test_block_b', heading: 'Quantity' },
 | 
			
		||||
        ],
 | 
			
		||||
        rows: [{ values: ['Cheese', 3] }, { values: ['Peas', 5] }],
 | 
			
		||||
        caption: 'A shopping list',
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +135,9 @@ describe('wagtail.contrib.typed_table_block.blocks.TypedTableBlock', () => {
 | 
			
		|||
    expect(document.body.innerHTML).toMatchSnapshot();
 | 
			
		||||
    expect(boundBlock.columns.length).toBe(2);
 | 
			
		||||
    expect(boundBlock.rows.length).toBe(2);
 | 
			
		||||
    expect(document.getElementsByName('mytable-caption')[0].value).toBe(
 | 
			
		||||
      'A shopping list',
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('can be cleared', () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -141,6 +148,14 @@ describe('wagtail.contrib.typed_table_block.blocks.TypedTableBlock', () => {
 | 
			
		|||
      '0',
 | 
			
		||||
    );
 | 
			
		||||
    expect(document.getElementsByName('mytable-row-count')[0].value).toBe('0');
 | 
			
		||||
    expect(document.getElementsByName('mytable-caption')[0].value).toBe('');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('supports adding a caption', () => {
 | 
			
		||||
    boundBlock.setCaption('A shopping list');
 | 
			
		||||
    expect(document.getElementsByName('mytable-caption')[0].value).toBe(
 | 
			
		||||
      'A shopping list',
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  test('supports inserting columns', () => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ Thank you to Thibaud Colas and Badr Fourane for their work on this feature.
 | 
			
		|||
 * Use SlugInput on all SlugFields by default (LB (Ben) Johnston)
 | 
			
		||||
 * Show character counts on RichTextBlock with `max_length` (Elhussein Almasri)
 | 
			
		||||
 * Move locale selector in generic IndexView to a filter (Sage Abdullah)
 | 
			
		||||
 * Add optional caption field to `TypedTableBlock` (Tommaso Amici, Cynthia Kiser)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Bug fixes
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,8 +76,8 @@ class TableInputAdapter(WidgetAdapter):
 | 
			
		|||
                "Display the first column as a header."
 | 
			
		||||
            ),
 | 
			
		||||
            "Table caption": _("Table caption"),
 | 
			
		||||
            "A heading that identifies the overall topic of the table, and is useful for screen reader users": _(
 | 
			
		||||
                "A heading that identifies the overall topic of the table, and is useful for screen reader users"
 | 
			
		||||
            "A heading that identifies the overall topic of the table, and is useful for screen reader users.": _(
 | 
			
		||||
                "A heading that identifies the overall topic of the table, and is useful for screen reader users."
 | 
			
		||||
            ),
 | 
			
		||||
            "Table": _("Table"),
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,13 +40,15 @@ class TypedTableBlockValidationError(ValidationError):
 | 
			
		|||
class TypedTable:
 | 
			
		||||
    template = "typed_table_block/typed_table_block.html"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, columns, row_data):
 | 
			
		||||
    def __init__(self, columns, row_data, caption: str):
 | 
			
		||||
        # a list of dicts, each with items 'block' (the block instance) and 'heading'
 | 
			
		||||
        self.columns = columns
 | 
			
		||||
 | 
			
		||||
        # a list of dicts, each with an item 'values' (the list of block values)
 | 
			
		||||
        self.row_data = row_data
 | 
			
		||||
 | 
			
		||||
        self.caption = caption
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rows(self):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +88,8 @@ class BaseTypedTableBlock(Block):
 | 
			
		|||
                self.child_blocks[name] = block
 | 
			
		||||
 | 
			
		||||
    def value_from_datadict(self, data, files, prefix):
 | 
			
		||||
        caption = data["%s-caption" % prefix]
 | 
			
		||||
 | 
			
		||||
        column_count = int(data["%s-column-count" % prefix])
 | 
			
		||||
        columns = [
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -123,6 +127,7 @@ class BaseTypedTableBlock(Block):
 | 
			
		|||
                {"block": col["block"], "heading": col["heading"]} for col in columns
 | 
			
		||||
            ],
 | 
			
		||||
            row_data=[{"values": row["values"]} for row in rows],
 | 
			
		||||
            caption=caption,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def get_prep_value(self, table):
 | 
			
		||||
| 
						 | 
				
			
			@ -141,11 +146,13 @@ class BaseTypedTableBlock(Block):
 | 
			
		|||
                    }
 | 
			
		||||
                    for row in table.row_data
 | 
			
		||||
                ],
 | 
			
		||||
                "caption": table.caption,
 | 
			
		||||
            }
 | 
			
		||||
        else:
 | 
			
		||||
            return {
 | 
			
		||||
                "columns": [],
 | 
			
		||||
                "rows": [],
 | 
			
		||||
                "caption": "",
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    def to_python(self, value):
 | 
			
		||||
| 
						 | 
				
			
			@ -170,11 +177,13 @@ class BaseTypedTableBlock(Block):
 | 
			
		|||
                    {"values": [column_data[row_index] for column_data in columns_data]}
 | 
			
		||||
                    for row_index in range(0, len(value["rows"]))
 | 
			
		||||
                ],
 | 
			
		||||
                caption=value.get("caption", ""),
 | 
			
		||||
            )
 | 
			
		||||
        else:
 | 
			
		||||
            return TypedTable(
 | 
			
		||||
                columns=[],
 | 
			
		||||
                row_data=[],
 | 
			
		||||
                caption="",
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def get_form_state(self, table):
 | 
			
		||||
| 
						 | 
				
			
			@ -193,11 +202,13 @@ class BaseTypedTableBlock(Block):
 | 
			
		|||
                    }
 | 
			
		||||
                    for row in table.row_data
 | 
			
		||||
                ],
 | 
			
		||||
                "caption": table.caption,
 | 
			
		||||
            }
 | 
			
		||||
        else:
 | 
			
		||||
            return {
 | 
			
		||||
                "columns": [],
 | 
			
		||||
                "rows": [],
 | 
			
		||||
                "caption": "",
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    def clean(self, table):
 | 
			
		||||
| 
						 | 
				
			
			@ -223,10 +234,16 @@ class BaseTypedTableBlock(Block):
 | 
			
		|||
            if cell_errors:
 | 
			
		||||
                raise TypedTableBlockValidationError(cell_errors=cell_errors)
 | 
			
		||||
            else:
 | 
			
		||||
                return TypedTable(columns=table.columns, row_data=cleaned_rows)
 | 
			
		||||
                return TypedTable(
 | 
			
		||||
                    columns=table.columns, row_data=cleaned_rows, caption=table.caption
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            return TypedTable(columns=[], row_data=[])
 | 
			
		||||
            return TypedTable(
 | 
			
		||||
                columns=[],
 | 
			
		||||
                row_data=[],
 | 
			
		||||
                caption="",
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def deconstruct(self):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -274,6 +291,10 @@ class TypedTableBlockAdapter(Adapter):
 | 
			
		|||
            "required": block.required,
 | 
			
		||||
            "icon": block.meta.icon,
 | 
			
		||||
            "strings": {
 | 
			
		||||
                "CAPTION": _("Caption"),
 | 
			
		||||
                "CAPTION_HELP_TEXT": _(
 | 
			
		||||
                    "A heading that identifies the overall topic of the table, and is useful for screen reader users."
 | 
			
		||||
                ),
 | 
			
		||||
                "ADD_COLUMN": _("Add column"),
 | 
			
		||||
                "ADD_ROW": _("Add row"),
 | 
			
		||||
                "COLUMN_HEADING": _("Column heading"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,8 @@
 | 
			
		|||
{% load wagtailcore_tags %}
 | 
			
		||||
<table>
 | 
			
		||||
    {% if value.caption %}
 | 
			
		||||
        <caption>{{ value.caption }}</caption>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
            {% for col in value.columns %}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
        )
 | 
			
		||||
 | 
			
		||||
        self.form_data = {
 | 
			
		||||
            "table-caption": "Countries and their food",
 | 
			
		||||
            "table-column-count": "2",
 | 
			
		||||
            "table-row-count": "3",
 | 
			
		||||
            "table-column-0-type": "country",
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +72,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
                {"values": ["nl", "A small country with stroopwafels"]},
 | 
			
		||||
                {"values": ["fr", "A large country with baguettes"]},
 | 
			
		||||
            ],
 | 
			
		||||
            "caption": "Countries and their food",
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def test_value_from_datadict(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +83,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
        table = self.block.value_from_datadict(self.form_data, {}, "table")
 | 
			
		||||
 | 
			
		||||
        self.assertIsInstance(table, TypedTable)
 | 
			
		||||
        self.assertEqual(table.caption, "Countries and their food")
 | 
			
		||||
        self.assertEqual(len(table.columns), 2)
 | 
			
		||||
        self.assertEqual(table.columns[0]["heading"], "Country")
 | 
			
		||||
        self.assertEqual(table.columns[1]["heading"], "Description")
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +106,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
        # Column id 1 is a population column that was deleted before being replaced by the
 | 
			
		||||
        # current one with id 3.
 | 
			
		||||
        form_data = {
 | 
			
		||||
            "table-caption": "Countries and their food",
 | 
			
		||||
            # table-column-count includes deleted columns, as it's telling the server code
 | 
			
		||||
            # the maximum column ID number it should consider
 | 
			
		||||
            "table-column-count": "4",
 | 
			
		||||
| 
						 | 
				
			
			@ -129,6 +133,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
        table = self.block.value_from_datadict(form_data, {}, "table")
 | 
			
		||||
 | 
			
		||||
        self.assertIsInstance(table, TypedTable)
 | 
			
		||||
        self.assertEqual(table.caption, "Countries and their food")
 | 
			
		||||
        self.assertEqual(len(table.columns), 3)
 | 
			
		||||
        self.assertEqual(table.columns[0]["heading"], "Country")
 | 
			
		||||
        self.assertEqual(table.columns[1]["heading"], "Population")
 | 
			
		||||
| 
						 | 
				
			
			@ -145,6 +150,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
        Test that we can turn JSONish data from the database into a TypedTable instance
 | 
			
		||||
        """
 | 
			
		||||
        table = self.block.to_python(self.db_data)
 | 
			
		||||
        self.assertEqual(table.caption, "Countries and their food")
 | 
			
		||||
        self.assertIsInstance(table, TypedTable)
 | 
			
		||||
        self.assertEqual(len(table.columns), 2)
 | 
			
		||||
        self.assertEqual(table.columns[0]["heading"], "Country")
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +194,7 @@ class TestTableBlock(TestCase):
 | 
			
		|||
        table = self.block.value_from_datadict(self.form_data, {}, "table")
 | 
			
		||||
        html = self.block.render(table)
 | 
			
		||||
 | 
			
		||||
        self.assertIn("<caption>Countries and their food</caption>", html)
 | 
			
		||||
        self.assertIn('<th scope="col">Country</th>', html)
 | 
			
		||||
        # rendering should use the block renderings of the child blocks ('FR' not 'fr')
 | 
			
		||||
        self.assertIn("<td>FR</td>", html)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue