[DrupalHtmlEngine] CKEditor 5 saves content as single line HTML making revision diffing impossible

Created on 1 April 2023, over 1 year ago
Updated 1 December 2023, about 1 year ago

Problem/Motivation

I used CKEditor 4 module of Core in the past. I switched to CKEditor 5. It works well, but leads to a major regression.

The HTML is now saved as a single line. This means that revision comparison (via Diff module) have become impossible. Every change you make leads to the single line HTML being different, and the entire line being highlighted as a difference. Good luck figuring out what has changed then.

I looked at CKEditor configuration, Diff configuration, but nothing seems to be there to solve this. Also, I checked the database, and the HTML is now really saved as a single line there, while before it was stored in multiple lines, matching what CKEditor shows when viewing the source of the content.

Steps to reproduce

Use CKEditor 5, create a node, then change the node, and compare the revisions with the Diff module. Or, just check the stored HTML of the node body and its revisions.

Proposed resolution

Store in the database the multiline HTML that is also shown by CKEditor in its Source view, as it did with CKEditor 4.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
CKEditor 5 

Last updated 2 days ago

Created by

🇳🇱Netherlands dhendriks

Live updates comments and jobs are added and updated live.
  • Regression

    It restores functionality that was present in earlier versions.

  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

  • Usability

    Makes Drupal easier to use. Preferred over UX, D7UX, etc.

  • JavaScript

    Affects the content, performance, or handling of Javascript.

Sign in to follow issues

Comments & Activities

  • Issue created by @dhendriks
  • 🇳🇱Netherlands dhendriks

    Almost two months later, no replies. Can somebody at least confirm that we consider this a bug?

  • 🇺🇸United States DamienMcKenna NH, USA

    I can confirm this happens, and that it is annoying.

  • 🇺🇸United States DamienMcKenna NH, USA

    I found the same question on StackOverflow, but no answer yet: https://stackoverflow.com/questions/71733317/ckeditor5-html-output-forma...

  • 🇺🇸United States DamienMcKenna NH, USA

    There's also an official feature request about this: https://github.com/ckeditor/ckeditor5/issues/8668

  • 🇺🇸United States DamienMcKenna NH, USA

    One of the suggestions in the github issue was to use a 3rd party formatter.

  • Status changed to Needs work about 1 year ago
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    I just realized that we could totally do this in our own DrupalHtmlEngine plugin 🤔

    This very simplistic patch already improves

    Clearly too naïve, more work needed. But this at least is a starting point :)

    Patch:

    diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js
    index 5e0321664c..136c369e91 100644
    --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js
    +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js
    @@ -64,6 +64,8 @@ export default class DrupalHtmlBuilder {
         } else if (node.nodeType === Node.COMMENT_NODE) {
           this._appendComment(node);
         }
    +    // Make the stored HTML diffable.
    +    this._append("\n");
       }
     
       /**
    

    (followed by yarn --cwd ./core run build:ckeditor5)

  • 🇺🇸United States DamienMcKenna NH, USA

    Thanks for putting that together.

    Might this be a better approach?

    diff --git a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js
    index 5e0321664c..9f8f909154 100644
    --- a/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js
    +++ b/core/modules/ckeditor5/js/ckeditor5_plugins/drupalHtmlEngine/src/drupalhtmlbuilder.js
    @@ -87,6 +87,9 @@ export default class DrupalHtmlBuilder {
           this._append(nodeName);
           this._append('>');
         }
    +
    +    // Make the stored HTML diffable.
    +    this._append("\n");
       }
     
       /**
    @@ -156,6 +159,9 @@ export default class DrupalHtmlBuilder {
         this._append('<!--');
         this._append(node.textContent);
         this._append('-->');
    +
    +    // Make the stored HTML diffable.
    +    this._append("\n");
       }
     
       /**
    
  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Sure! 😄

    Maybe better still: leading whitespace, to show the tag nesting level? OTOH, if something gets wrapped or unwrapped in some tag, that would then cause many lines to change, versus #7 and #8 which would show that indeed the text inside tags did not change 🤔

    I defer to all of you users of the Diff module! 😊

  • 🇺🇸United States quicksketch

    In Backdrop-land we ended up porting the code used by CKEditor's Source plugin.

    That port exists in Backdrop here: ckeditor5.formatter.js.

    When the content is saved to the field, we run the formatter, like this:

          let newData = editor.getData();
          newData = Backdrop.ckeditor5.formatHtml(newData);
          editor.destroy();
          element.value = newData;
    

    I also considered/tried building the formatting into the HTML engine (we ported DrupalHtmlEngine into our module as well). But I ran into a different problem in that when using CKEditor's "Source" button, the internal formatter expects all the HTML to be on one line. If you run the formatter on already-formatted HTML, you end up with lots of issues like double-indented lines and extra new lines added when viewing the source within CKEditor.

  • 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺

    Thanks so much for letting us know that, @quicksketch! 🙏😊

    I know this is a long stretch, but … any chance you'd be interested in creating a merge request against Drupal core, to port this wonderful logic from Backdrop? 😄 (It's so cool to have contributions flowing in both directions! I hope you like what you've found in CKEditor 5 — I definitely missed working with you this time around: you were so instrumental in getting CKEditor 4 in Drupal core!)

Production build 0.71.5 2024