All <tables> go through MarkdownTable

What does this MR do and why?

Closes Pass all `<table>`s through `MarkdownTable` to ... (#630465).

All <tables> go through MarkdownTable.

render_markdown_tables.js now puts all tables through MarkdownTable except for those that legitimately don't want any treatment at all (already-applied, detached, JSON (to be fixed!), nested). We work out if the table is to be sorted here, but even non-sortable tables still get put into MarkdownTable.

We also fix how we determine the sortable header row: it can be in the <thead>, or it can be a single leading row of <th>s in the <tbody>, thus catching RTE-emitted HTML-syntax tables.

Explainer

The principle is: all tables go through MarkdownTable, so everything gets enhanced by it, but we only make the table sortable if the following rules hold:

  • There's only one row which is "header eligible". This could be either a <thead> with a single <tr>, or if there's no <thead>, a single leading <tr> in the body (whether it's in an explicit <tbody> or not, we don't care) which contains only <th>s.
    • So if you have a <thead> with a <tr> and a leading <tr> in the body with all <th>s, we won't sort it.
    • Or if there's no <thead> nor a leading <tr> in the body with all <th>s, it's not sortable.
    • Or if there's two leading <tr>s in the body with all <th>s — not sortable.
    • There must be exactly one row that's obviously "meant" to be the header.
  • There's no non-1 colspans or rowspans.
  • There can't be more than one <tbody>.
  • The table isn't nested inside another table.

So if any of are true, we still enhance the table, we just don't make it sortable. Everything that we permit is carried across: whatever is in their <thead> (if anything), however many <tbody>s and their contents, if they have a <tfoot>; we don't change it or move anything around, but it still gets the nice wrapper.

If none of those are true, we make the table sortable too. If the sortable header row wasn't already in a <thead>, we move it there. (This is fine: it's the single header-like row in the table.)

Screenshots or screen recordings

What Before After
1. Pipe table syntax in the PTE case-1-pipe-table-before.png case-1-pipe-table-after.png
No change.
2. <table><thead><tr><th>...</th>...</tr></thead><tbody><tr>...</tr>... in the PTE (table has <thead> with one <tr> containing <th>s, and <tbody>) case-2-html-thead-tbody-before.png case-2-html-thead-tbody-after.png
No change.
3. <table><tr>...</tr><tr>...</tr>... (table has no <thead>, no <tbody>, no <th>s at all) in the PTE case-3-html-headerless-before.png case-3-html-headerless-after.png
Table gains wrapper (note top outline), but not sortable, as there is neither <thead> nor <th> in the source.
4. <table><tr><th>...</th>...</tr><tr>...</tr>... in the PTE (table has first <tr> containing only <th>s) case-4-html-leading-th-row-before.png case-4-html-leading-th-row-after.png
Table is now sortable!
5. Regular table created in the RTE case-5-rte-table-before.png case-5-rte-table-after.png
No change.
6. Table created in the RTE with block-level elements (when you receive the "HTML warning" while editing) case-6-rte-block-table-before.png case-6-rte-block-table-after.png
Table is now sortable!
7. AsciiDoc wiki page with striped header table, and striped headerless table case-7-asciidoc-wiki-before.png case-7-asciidoc-wiki-after.png
Striped headerless table gets wrapper.
8. <table><thead><tr>...</tr><tr>...</tr></thead><tbody>... (table has two <tr>s in <thead>) case-8-two-header-rows-before.png case-8-two-header-rows-after.png
Table doesn't lose its second header row (!); no longer sortable.
9. Case 4 in a Rapid Diffs MR diff comment case-9-rapid-diffs-comment-before.png case-9-rapid-diffs-comment-after.png
Table is now sortable!
10. Right-to-left pipe syntax table (per case 1) and headerless HTML table (per case 3) case-10-rtl-table-before.png case-10-rtl-table-after.png
Pipe syntax table is correctly laid out right-to-left, and the headerless HTML table gains wrapper.

How to set up and validate locally

  1. Check out master.
  2. Paste the Markdown that follows these steps into a work item or MR description.
  3. Observe the cases align with the "Before" column of the 10 cases in the table above.
  4. Check out this branch, and perhaps refresh the page.
  5. Observe the cases align with the "After" column now.
Markdown input for repro
Case 1: pipe table

| Name | Role | Joined |
| --- | --- | --- |
| Charlie | Maintainer | 2024-03 |
| Alice | Developer | 2023-11 |
| Bob | Reporter | 2025-01 |

Case 2: HTML table with thead and tbody

<table>
<thead>
<tr><th>Name</th><th>Role</th><th>Joined</th></tr>
</thead>
<tbody>
<tr><td>Charlie</td><td>Maintainer</td><td>2024-03</td></tr>
<tr><td>Alice</td><td>Developer</td><td>2023-11</td></tr>
<tr><td>Bob</td><td>Reporter</td><td>2025-01</td></tr>
</tbody>
</table>

Case 3: HTML table without a header

<table>
<tr><td>Name</td><td>Role</td><td>Joined</td></tr>
<tr><td>Charlie</td><td>Maintainer</td><td>2024-03</td></tr>
<tr><td>Alice</td><td>Developer</td><td>2023-11</td></tr>
<tr><td>Bob</td><td>Reporter</td><td>2025-01</td></tr>
</table>

Case 4: HTML table with a leading th row

<table>
<tr><th>Name</th><th>Role</th><th>Joined</th></tr>
<tr><td>Charlie</td><td>Maintainer</td><td>2024-03</td></tr>
<tr><td>Alice</td><td>Developer</td><td>2023-11</td></tr>
<tr><td>Bob</td><td>Reporter</td><td>2025-01</td></tr>
</table>

Case 5: table in the rich text editor (stored Markdown as the editor serialised it)

| Name | Role | Joined |
|------|------|--------|
| Charlie | Maintainer | 2024-03 |
| Alice | Developer | 2023-11 |
| Bob | Reporter | 2025-01 |

Case 6: table with block content in the rich text editor (stored Markdown as the editor serialised it; the Maintainer cell holds two paragraphs)

<table>
<tr>
<th>Name</th>
<th>Role</th>
<th>Joined</th>
</tr>
<tr>
<td>Charlie</td>
<td>

Maintainer

Reviews merge requests
</td>
<td>2024-03</td>
</tr>
<tr>
<td>Alice</td>
<td>Developer</td>
<td>2023-11</td>
</tr>
<tr>
<td>Bob</td>
<td>Reporter</td>
<td>2025-01</td>
</tr>
</table>

Case 7: AsciiDoc wiki page (format: AsciiDoc)

= Team

[options="header",stripes=even]
|===
|Name |Role |Joined
|Charlie |Maintainer |2024-03
|Alice |Developer |2023-11
|Bob |Reporter |2025-01
|===

[stripes=odd]
|===
|Charlie |Maintainer |2024-03
|Alice |Developer |2023-11
|Bob |Reporter |2025-01
|===

Case 8: HTML table with two header rows

<table>
<thead>
<tr><th>Name</th><th>Role</th><th>Joined</th></tr>
<tr><th>Who</th><th>What</th><th>When</th></tr>
</thead>
<tbody>
<tr><td>Charlie</td><td>Maintainer</td><td>2024-03</td></tr>
<tr><td>Alice</td><td>Developer</td><td>2023-11</td></tr>
<tr><td>Bob</td><td>Reporter</td><td>2025-01</td></tr>
</tbody>
</table>

Case 9: diff comment on a merge request (same source as case 4)

<table>
<tr><th>Name</th><th>Role</th><th>Joined</th></tr>
<tr><td>Charlie</td><td>Maintainer</td><td>2024-03</td></tr>
<tr><td>Alice</td><td>Developer</td><td>2023-11</td></tr>
<tr><td>Bob</td><td>Reporter</td><td>2025-01</td></tr>
</table>

Case 10: right-to-left table

| الاسم | المدينة | القسم | الدور | تاريخ الانضمام | البريد الإلكتروني | رقم الهاتف | الحالة |
| --- | --- | --- | --- | --- | --- | --- | --- |
| أحمد منصور | القاهرة | الهندسة | مطور برمجيات | 2021-03-14 | ahmed@example.com | +20 100 000 0001 | نشط |
| فاطمة الزهراء | الرياض | التصميم | مديرة المنتج | 2019-11-02 | fatima@example.com | +966 50 000 0002 | في إجازة |
| يوسف حداد | بيروت | المالية | محلل مالي | 2023-06-27 | youssef@example.com | +961 3 000 003 | نشط |

<table>
<tr><td>الاسم</td><td>المدينة</td><td>القسم</td></tr>
<tr><td>أحمد منصور</td><td>القاهرة</td><td>الهندسة</td></tr>
<tr><td>فاطمة الزهراء</td><td>الرياض</td><td>التصميم</td></tr>
<tr><td>يوسف حداد</td><td>بيروت</td><td>المالية</td></tr>
</table>

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Asherah Connor

Merge request reports

Loading
Loading