Problem/Motivation

tfoot element is lost during the conversion

Steps to reproduce

  1. Go to
  2. Open the source editing.
  3. Paste the following markup:
<table>
    <thead>
        <tr>
            <th>Items</th>
            <th scope="col">Expenditure</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th scope="row">Donuts</th>
            <td>3,000</td>
        </tr>
        <tr>
            <th scope="row">Stationery</th>
            <td>18,000</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th scope="row">Totals</th>
            <td>21,000</td>
        </tr>
    </tfoot>
</table>
  • Switch back to the editing mode.
  • Switch back to the source editing mode.

Expected result

tfoot is preserved.

❌ Actual result

tfoot is lost and merged to tbody.

For Reference See Attached Issue :-

https://github.com/ckeditor/ckeditor5/issues/12952

Comments

sahil432 created an issue. See original summary.

sahil432’s picture

Issue summary: View changes
sahil432’s picture

Issue summary: View changes
wim leers’s picture

Title: Add table footer support » [upstream] Add <tfoot> (table footer) support
Status: Active » Postponed
Issue tags: +Needs upstream feature

Thanks for this issue! This is definitely blocked on https://github.com/ckeditor/ckeditor5/issues/12952.

smulvih2’s picture

+1 I am running into this issue as well. In my case, my table is driving a JS chart, and adding the contents of tfoot into tbody is causing the JS to fail.

joseph.olstad’s picture

Needing a fix for this.

joseph.olstad’s picture

We've created a new module called please_replace_ckeditor5_with_tinymce

we added a text filter plugin in src/Plugin/Filter/TableTfootFixFilter.php


namespace Drupal\please_replace_ckeditor5_with_tinymce\Plugin\Filter;

use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;

/**
 * Wraps orphan <tr> tags after </tbody> in a <tfoot> section.
 *
 * @Filter(
 *   id = "table_tfoot_fix_filter",
 *   title = @Translation("Fix orphan 'tr' after 'tbody' by wrapping in 'tfoot'"),
 *   description = @Translation("Wraps 'tr' elements that appear after 'tbody' with a 'tfoot' block."),
 *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE,
 *   weight = 101,
 *   provider = "please_replace_ckeditor5_with_tinymce",
 *   settings = {}
 * )
 */
class TableTfootFixFilter extends FilterBase {

  /**
   * {@inheritdoc}
   */
  public function process($text, $langcode) {

    // Match closing </tbody> followed by one or more <tr> elements not already wrapped.
    $pattern = '#</tbody>\s*((?:<tr\b.*?</tr>\s*)+)(?!\s*</tfoot>)#is';

    $text = preg_replace_callback($pattern, function ($matches) {
      return '</tbody><tfoot>' . $matches[1] . '</tfoot>';
    }, $text);

    // Process each <table> individually.
    return new FilterProcessResult(
      preg_replace_callback('#<table\b[^>]*>.*?</table>#is', function ($table_match) {
        $table = $table_match[0];

        // Match all <tbody> blocks inside the table.
        preg_match_all('#<tbody\b[^>]*>.*?</tbody>#is', $table, $matches);

        if (count($matches[0]) > 1) {
          $last = array_pop($matches[0]);

          // Replace last <tbody> with <tfoot>.
          $last_tfoot = preg_replace([
            '#^<tbody([^>]*)>#i',
            '#</tbody>$#i'
          ], [
            '<tfoot$1>',
            '</tfoot>'
          ], $last);

          // Replace the last occurrence in the table with <tfoot>.
          $pos = strrpos($table, $last);
          if ($pos !== false) {
            $table = substr_replace($table, $last_tfoot, $pos, strlen($last));
          }
        }

        return $table;
      }, $text)
    );
  }

}

Enable this filter on all text formats using ckeditor5. What it does is replace the incorrect markup with the expected tfoot when the page is rendered.

We also have a other text filter plugins in the please_replace_ckeditor5_with_tinymce module called VideoCleanupFilter.php and SpanLinkFixFilter.php . Perhaps we will have to turn the please_replace_ckeditor5_with_tinymce module into a full contrib project so that others can get our text filter plugins that put a bandaid on content that would otherwise be broken by ckeditor5.

joseph.olstad’s picture

Please smash the thumbs up on this pull request that fixes the issue at the root which is in ckeditor it'self.

https://github.com/ckeditor/ckeditor5/pull/14276

and also the issue description it'self needs a thumbs up, smash that like button

https://github.com/ckeditor/ckeditor5/issues/12952

joseph.olstad’s picture

joseph.olstad’s picture

Apparently there may be another way around this issue, from a message in slack drupal ckeditor5 channel.

joshuami
mercredi le 23 avril à 17 h 47
We've had pretty solid results from adding source plus the following to a custom module:

mymodule_ckeditor5_allowHTML:
  ckeditor5:
    plugins: [htmlSupport.GeneralHtmlSupport]
    config:
      htmlSupport:
        allow:
          - name: table
            classes: true
          - name: thead
            classes: true
          - name: tbody
            classes: true
          - name: ol
            classes: true
            attributes:
              - key: type
          - name: div
            classes: true
            attributes:
              - key: id
              - key: aria-labelledby
              - key: data-bs-parent
          - name: span
            classes: true
          - name: drupal-media
            attributes:
              - key: data-title
              - key: data-fullsize
              - key: data-description
              - key: data-hide-translations
              - key: title
          - name: p
            classes: true
          - name: h2
            classes: true
            attributes:
              - key: id
          - name: h3
            classes: true
            attributes:
              - key: id
          - name: h4
            classes: true
            attributes:
              - key: id
          - name: h5
            classes: true
            attributes:
              - key: id
          - name: h6
            classes: true
            attributes:
              - key: id
          - name: i
            classes: true
    drupal:
      label: Arbitrary HTML support
      library: mymodule/ckeditor5
      elements: 
        - <table class>
        - <thead class>
        - <tbody class>
        - <ol class type>
        - <div class id aria-labelledby data-bs-parent>
        - <span class>
        - <drupal-media data-title data-fullsize data-description data-hide-translations title>
        - <p class>
        - <h2 class id>
        - <h3 class id>
        - <h4 class id>
        - <h5 class id>
        - <h6 class id>
        - <i class>
joseph.olstad’s picture

We've published a contrib module that fixes ck5 tables . It is called CKEditor5 Table Fix

https://www.drupal.org/project/ckeditor5_table_fix

andrew.wang’s picture

It seems that someone from CKEditor team (finally) picked this up yesterday: https://github.com/ckeditor/ckeditor5/pull/19582

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

joseph.olstad’s picture

A fix was merged upstream
https://github.com/ckeditor/ckeditor5/issues/12952#issuecomment-3805179151

Here's what was merged:
https://github.com/ckeditor/ckeditor5/pull/19582

Haven't tested it, likely still need https://www.drupal.org/project/ckeditor5_table_fix until D11.4.0 or D11.5.0 and possibly beyond.

andrew.wang’s picture

Status: Postponed » Active

The upstream pull request is now merged and tfoot support is planned for v48!

joseph.olstad’s picture

While it was merged, I suspect people will still want to use the ckeditor5_table_fix since it allows various markup including media to be embedded into tables and tfoot.

https://github.com/ckeditor/ckeditor5/issues/12952

With that said, once 48 lands in core, we'll review.