Problem/Motivation

On a layout builder page I am seeing data loss when saving an existing block with source mode enabled in ckeditor. At least the data loss is quite obvious ;)

Steps to reproduce:

  • Add block to section
  • Create custom block
  • Edit text in body field
  • Save block
  • Edit block
  • Switch body field to ckeditor source mode
  • Edit text
  • Save
  • Changes are NOT saved!

Workaround: Once I change back to non-source mode and do some change(!) the changes are saved properly.

Variation

This is a bit more severe with ckeditor_config (on a core 8.7.8 install with a lot modules installed) module enabled.

Steps to reproduce:

  • Add startupMode = source to ckeditor_config settings in basic_html
  • Edit block
  • Switch body field to source mode
  • Edit text
  • Switch to non-source mode (this makes it work in the first example)
  • Save
  • Changes are NOT saved!

(Disclaimer: In the variation I am not 100% sure if it is because of the mentioned ckeditor_config settings, at least I haven't verified on a vanilla drupal install)

Proposed resolution

Allow textarea fields to be saved when edited in CKEditor 4's Source mode.

Remaining tasks

  1. Valid and remediate issue between patches in #26 and #29.
  2. Write valid tests confirming issue has been resolved.

Issue fork drupal-3095304

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Issue fork ckeditor-3095304

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

anruether created an issue. See original summary.

anruether’s picture

Title: Changes to text fields not saved when ckeditor source mode is active » Changes to a block's text field not saved when ckeditor source mode is active
anruether’s picture

Issue summary: View changes
anruether’s picture

Issue summary: View changes
dave reid’s picture

I'm seeing this also regardless if you using the source mode or not. Any filtered text field in a layout builder block with CKEditor doesn't seem to be updating even though I change the contents.

matt_paz’s picture

Confirmed that I'm seeing this when editing and then switching to source mode and then saving (w/out switching back to wysiwyg mode).

If I switch back to non-source, WYSIWYG mode before saving, I don't loose the changes.

matt_paz’s picture

Version: 8.8.0-beta1 » 8.9.x-dev
poindexterous’s picture

I'm experiencing this also, switching back to WYSIWYG after finishing my edits in source mode as matt_paz mentioned is the only workaround I've found at the moment.

tim.plunkett’s picture

Is this also reproducible in the standard Block UI, or only within LB?

anruether’s picture

I can only reproduce this in /node/1/layout

But not when editing a block directly: /block/1

komlenic’s picture

In testing, as others have indicated, this issue seems to only affect Layout Builder blocks.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

u_tiwari’s picture

I was able to reproduce this issue inside a modal when saving a block content and sourcedialog is open no changes made to textarea sourcedialog go through if we save directly . Are there any suggested workarounds or even possibly a related fix as yet ?

nod_’s picture

Issue tags: +JavaScript
anruether’s picture

Version: 9.1.x-dev » 8.9.x-dev

I think this qualifies as a non-disruptive (hopefully!) bug fix, so switching to 8.9

Are there any suggested workarounds or even possibly a related fix as yet ?

@u_tiwari The workaround is to switch back from source mode to normal mode before saving.

u_tiwari’s picture

If it helps anyone this is my workaround for this which is more intuitive to end-user as we do not have to click on Source first and then save.:

var origBeforeSubmit = Drupal.Ajax.prototype.beforeSubmit;

  Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {
    if (typeof(CKEDITOR) !== 'undefined' && CKEDITOR.instances) {
      const instances = Object.values(CKEDITOR.instances);
      instances.forEach(editor => {
        formValues.forEach(formField => {
          // Get field name from the id in the editor so that it covers all
          // fields using ckeditor.
          let fieldName = document.querySelector(`#${editor.name}`).getAttribute('name');
          if (formField.name === fieldName && editor.mode === 'source') {
            formField.value = editor.getData();
          }
        });
      });
    }
    origBeforeSubmit.call(formValues, element, options);
  };
seanb’s picture

Workaround in #16 almost solved the issue. When opening a block in layout builder a second time I got the following error:

An error occurred while attempting to process /layout_builder/update/block/overrides/...... Cannot read property 'getAttribute' of null

Fixed by a minor change that checks if the element exists first.

  var origBeforeSubmit = Drupal.Ajax.prototype.beforeSubmit;
  Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {
    if (typeof(CKEDITOR) !== 'undefined' && CKEDITOR.instances) {
      const instances = Object.values(CKEDITOR.instances);
      instances.forEach(editor => {
        formValues.forEach(formField => {
          // Get field name from the id in the editor so that it covers all
          // fields using ckeditor.
          let element = document.querySelector(`#${editor.name}`)
          if (element) {
            let fieldName = element.getAttribute('name');
            if (formField.name === fieldName && editor.mode === 'source') {
              formField.value = editor.getData();
            }
          }
        });
      });
    }
    origBeforeSubmit.call(formValues, element, options);
  };
ndf’s picture

Tested this with #17 in the website's global javascript file. And this works like a charm!

I don't know where the script belongs. I expect somewhere in the CkEditor module javascript.
In core/modules/ckeditor/js/ckeditor.es6.js there are comments like 'dialogs that are saved, sending data back to CKEditor'. But the ckeditor.es6.js // ckeditor.js is not loaded when editing a layout-builder block.
On a different project that uses paragraphs+ckeditor and not layout-builder I do see that ckeditor.js is loaded. That could be something to look further into 🤷‍♂️

someshver’s picture

#17 works perfect to resolve the issue. Thanks

someshver’s picture

Status: Active » Fixed
nod_’s picture

Version: 8.9.x-dev » 9.1.x-dev
Status: Fixed » Active

Is this fixed for everyone? It is not because a fix exists that the issue is fixed. It's when the fix has been committed

DominykasM’s picture

#17 works! Just not clear where to put it. If put to theme's js, it only works on frontpage theme, and not on admin pages.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

staceroni’s picture

I currently have #17 in a custom module JS behavior, as well as #3108085 for entity_embed, and #3102249 for core's Media library embed.

These 2 patches and JS behavior (for this current issue) all solve similar bugs related to retaining changes made in Ckeditor, either within an inline entity form, or layout builder. The behavior does not happen for an exposed textarea field that is not in a nested form, for example, a node's body field on the standard node edit form, or a paragraph textarea field. We are not currently using layout_builder, yet!, but intend to add it to the project soon.

I guess we are covered by having #17 in a custom module, but I just wanted to mention this ongoing side effect of CKeditor not retaining changes is present across core and contrib projects.

dennis_meuwissen’s picture

After using this fix for a while we ran into an issue where Ajax uploads through webforms would not work. The call to the original submit handler will not have this set correctly. This can be fixed to replacing that with return origBeforeSubmit.apply(this, arguments);

Together with #17 that looks like this now:

  var origBeforeSubmit = Drupal.Ajax.prototype.beforeSubmit;
  Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {
    if (typeof(CKEDITOR) !== 'undefined' && CKEDITOR.instances) {
      const instances = Object.values(CKEDITOR.instances);
      instances.forEach(editor => {
        formValues.forEach(formField => {
          // Get field name from the id in the editor so that it covers all
          // fields using ckeditor.
          let element = document.querySelector(`#${editor.name}`)
          if (element) {
            let fieldName = element.getAttribute('name');
            if (formField.name === fieldName && editor.mode === 'source') {
              formField.value = editor.getData();
            }
          }
        });
      });
    }
    return origBeforeSubmit.apply(this, arguments);
  };

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

anruether’s picture

Issue summary: View changes
rembrandx’s picture

I'm having the issue that the html tags appear in text regardless of source mode.
I made a related ticket for it: drupal.org/project/drupal/issues/3211961

The solution from #17 (and extended one from #26) just keep giving me javascript errors about formValues being undefined or the method 'option' not being available prior to initialization of the dialog at the moment, so this needs some more work I think.

rembrandx’s picture

To be more exact, when editing the inline block with 'preview content' turned on, in wysiwyg mode, you get a JS error if applying the suggested solution. (and I need the fix in wysiwyg mode)

Uncaught Error: cannot call methods on dialog prior to initialization; attempted to call method 'option'
    at Function.error (jquery.min.js?v=3.5.1:2)
    at HTMLDivElement.<anonymous> (widget-min.js?v=1.12.1:9)
    at Function.each (jquery.min.js?v=3.5.1:2)
    at S.fn.init.each (jquery.min.js?v=3.5.1:2)
    at S.fn.init.t.fn.<computed> [as dialog] (widget-min.js?v=1.12.1:9)
    at resetSize (dialog.position.js?v=9.1.7:57)
    at later (debounce.js?v=9.1.7:22)
liam morland’s picture

The patch in #26 is a good work-around, but we need to get this into core. Where should this go in core?

tim.plunkett’s picture

Status: Active » Needs work
Issue tags: +Needs tests

Maybe here? Might not be the best place but it's a start. Also this will need test coverage written.

tim.plunkett’s picture

Component: layout_builder.module » ckeditor.module

Moving this to CKEditor's queue for now, since from what I can see, the fix has nothing to do with Layout Builder (even if the steps to reproduce do include it).

JoseFran’s picture

This solutions #26 work for me but as #29 give me javascript errors about formValues so i get formValues object values as array and add one condition in case formValues be 'undefined'. I am testing but works for me. Thanks for your help.

var origBeforeSubmit = Drupal.Ajax.prototype.beforeSubmit;
      Drupal.Ajax.prototype.beforeSubmit = function (formValues, element, options) {
        if (typeof(CKEDITOR) !== 'undefined' && CKEDITOR.instances) {
          const instances = Object.values(CKEDITOR.instances);
          if (typeof(formValues) != "undefined") {
            instances.forEach(editor => {
              Object.values(formValues).forEach(formField => {
                // Get field name from the id in the editor so that it covers all
                // fields using ckeditor.
                let element = document.querySelector(`#${editor.name}`)
                if (element) {
                  let fieldName = element.getAttribute('name');
                  if (formField.name === fieldName && editor.mode === 'source') {
                    formField.value = editor.getData();
                  }
                }
              });
            });
          }
        }
        origBeforeSubmit.call(formValues, element, options);
      };
Webbeh’s picture

Issue summary: View changes

Per #33, adjusting the original issue summary to include remaining tasks.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

bingol@ciandt.com’s picture

Version 9.2 modifies the bug that cannot be saved in ckeditor source state

liam morland’s picture

This is failing automated tests with this:

/var/www/html/core/modules/ckeditor/js/ckeditor.es6.js
404:41 error Use the rest parameters instead of 'arguments' prefer-rest-params

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

Project: Drupal core » CKEditor 4 - WYSIWYG HTML editor
Version: 9.5.x-dev » 1.0.x-dev
Component: ckeditor.module » Code

CKEditor has been removed from core, CKEditor 4 is removed from Drupal Core in 10.0.0

dave reid’s picture

I hope the plan will be still to backport bug fixes to D9 however.

mariacha1 made their first commit to this issue’s fork.

mariacha1’s picture

I've rerolled the patch from #38 to work with ckeditor the module, since previously it was for ckeditor within core. Merge request is at https://git.drupalcode.org/project/ckeditor/-/merge_requests/10 and The patch is available at https://git.drupalcode.org/project/ckeditor/-/merge_requests/10.diff for composer users.

leo liao’s picture

When editing a block containing ckeditor in Layout Build, if you just click "Edit Media" to edit and then click the Save button, the edit will not take effect, and the edited data will be lost.

juanpablomitriatti’s picture

Hi
I tested the patch at the comment #45, however it's a .diff extension and we work with .patch. That's why I'm uploading the same file in .patch extension :

Webbeh’s picture

RE #46 and #47, please do not continue to post patch updates when we have open MRs and forks that effectively do the same thing. We're splitting up the development across two mediums, and that is unhelpful to getting this issue resolved.

Based on #43-#45, please use the correct fork and MR to update and collaboration on code.

leo liao’s picture

So sorry, this problem still bugs me after I upgraded to 9.5.
Is there something wrong with my operation?
Allow me to update the documentation for #46 before doing so.

anish.a’s picture

These patches no longer applies