CKEditor 5 doesn't save updated value if form submitted right after the change

Created on 25 October 2023, about 1 year ago
Updated 25 April 2024, 7 months ago

Problem/Motivation

Discovered in https://www.drupal.org/project/drupal/issues/3382780#comment-15289366 ๐Ÿ› [drupalImage] When ckeditor5_arbitraryHtmlSupport is on, fails to update Postponed

In web/core/modules/ckeditor5/js/ckeditor5.js:443 callback that marks field as changed called with debounce(callback, 400)();

debounce() returns a function that should be called instead of callback itself, but in this case, on every change new debounce function is created, that way it is basically the same as using 400ms timeout.

Because of that if a form is submitted in 400ms after the first change, the field is saved without it. Can be reproduced manually, but mainly it is a problem for tests, where it is very likely to submit a form in this time window.

CKeditor updates the hidden textarea anyway, even before onChange is executed, but the Drupal.editorDetach function resets it to its original value.
It happens only when more than 2 text formats are present because web/core/modules/editor/src/Element.php:118 is the only place when data-editor-value-is-changed is set to false (otherwise before onChange fired this attribute is not set at all and the condition in Drupal.editorDetach is false)

So a bunch of small mistakes leads to this issue.

Steps to reproduce

1. Open the node edit page with the CKEditor widget.
2. Make the first change and submit in 400ms after it.
3. Field saved without changes.
or
1. Edit the web/core/modules/editor/js/editor.js:306 function to print something console.log()
2. Make changes to the CKEditor field.
3. Console.log called for every change with 400ms timeout, but it was supposed to be called not more often than once in 400ms.

Proposed resolution

Change Drupal.editors.ckeditor5.onChange to store debounce function instead of callback.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

None?

๐Ÿ› Bug report
Status

Fixed

Version

10.2 โœจ

Component
CKEditor 5ย  โ†’

Last updated 1 day ago

Created by

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

    Affects the content, performance, or handling of Javascript.

Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @reinfate
  • last update about 1 year ago
    30,438 pass
  • Issue was unassigned.
  • In MR!5127 debounce is changed to how it was before https://www.drupal.org/project/ckeditor5/issues/3229174 โ†’
    The only thing that changed is "immediate" set to true, so the first execution will be instant. With that changes made to WYSIWYG and source are always submitted.

    But I'm not sure if debounce is needed at all, callbacks (web/core/modules/ckeditor5/js/ckeditor5.js:19) store only one function for each CKeditor instance and it is used by Drupal.editorAttach. So callback is only worth executing once and it can be removed.

    There is also Drupal.editors.ckeditor5.attachInlineEditor that uses that callback but I don't see where that attach is used at all.

    Different behaviour in Drupal.editorDetach, when there are 1 or more text formats, seems weird, but I also don't understand why we need to "Restore the original value if the user didn't make any changes yet", like if there are no changes, that means field already contains original value?

    I believe we do not need a test for the debounce/submit issue since there are already failing tests because of that in https://www.drupal.org/project/drupal/issues/3382780#comment-15289456 ๐Ÿ› [drupalImage] When ckeditor5_arbitraryHtmlSupport is on, fails to update Postponed

  • Status changed to Needs review about 1 year ago
  • Status changed to Needs work about 1 year ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    Thanks for reporting, could we get a test case showing the issue.

  • Status changed to Needs review 12 months ago
  • Status changed to RTBC 12 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    tests have been added and test-only feature already ran

    There was 1 error:
    1) Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5Test::testSave
    Behat\Mink\Exception\ExpectationException: The string "Very important information" was not found anywhere in the HTML response of the current page.
    /builds/issue/drupal-3396742/vendor/behat/mink/src/WebAssert.php:794
    /builds/issue/drupal-3396742/vendor/behat/mink/src/WebAssert.php:324
    /builds/issue/drupal-3396742/core/tests/Drupal/Tests/WebAssert.php:540
    /builds/issue/drupal-3396742/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5Test.php:849
    /builds/issue/drupal-3396742/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
    ERRORS!
    Tests: 11, Assertions: 182, Errors: 1.
    

    Issue summary appears complete (thanks for that)

    LGTM

  • last update 12 months ago
    30,689 pass
  • last update 12 months ago
    30,682 pass, 2 fail
  • last update 12 months ago
    30,689 pass
  • Assigned to lauriii
  • Status changed to Needs review 12 months ago
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    I'm worried this reintroduces the bug that #3229174: Making changes directly in the source view drops the made changes on save โ†’ fixed.

    This needs a review from @lauriii, who worked on the original issue.

  • Was it verified that removing this does not cause that bug to return?

    The issue with source editing not being saved is basically the same as this one.
    The difference is when in "source editing" mode change:data event is called only when switching back or if the form is submitted.
    So if only the source was edited and the form was submitted without switching mode back, that 400ms delay mentioned in this issue has no chance of being executed.
    Fix from https://www.drupal.org/i/3229174 โ†’ were removing delay only for source editing.
    With a fix from that issue in either mode on:change has no delay on the first input and everything is good.

    I've confirmed manually that the bug from #3229174 has not been reintroduced.
    It is testable I believe, but it will be the same test as provided in this issue, only with the mode changed.

  • Status changed to Needs work 12 months ago
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    It is testable I believe, but it will be the same test as provided in this issue, only with the mode changed.

    Could you expand the test to cover that too? ๐Ÿ™ Then we'll never have to worry about this again! ๐Ÿ˜„

  • Status changed to Needs review 12 months ago
  • Expanded test to include only source editing changes.

    It shouldn't fail even without changes from this issue, the one way to make it fail is to bring back the code mentioned in #8 but skip calling callback()

  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia amietpatial

    Attempted to replicate the issue multiple times on Windows 11 Pro using the latest version of Chrome, but it appears that the issue cannot be manually reproduced.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    Rebased and verified test failure.

    Also was not able to verify manually but the test seems to cause it. Can we confirm though nothing has broken?

    Still needs submaintainer sign off as not familiar with that js file.

  • I still can manually reproduce the issue on the latest 11.x
    So for me, everything remains the same and nothing new is broken.

    If it helps, the exact way I reproduce is:
    open edit, focus CKEditor field. Place the cursor on the save button. Type something and click save right after. As described in the Issue summary there is only a 400ms window to do that (probably a bit less, including input lag, code execution order etc.)

    However, the functional test hits that window consistently, which is why this issue was reported.

  • Issue was unassigned.
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave

    Going to unassign it. Been 3 months and havenโ€™t been able to get ahold of laurii whoโ€™s probably busy, and hate to see the issue stale

    @Wim Leers do you see any issue in the MR as someone whoโ€™s done a lot with ckeditor?

  • Status changed to RTBC 9 months ago
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States smustgrave
    1) Drupal\Tests\ckeditor5\FunctionalJavascript\CKEditor5Test::testSave
    Behat\Mink\Exception\ExpectationException: The string "Very important information" was not found anywhere in the HTML response of the current page.
    /builds/issue/drupal-3396742/vendor/behat/mink/src/WebAssert.php:794
    /builds/issue/drupal-3396742/vendor/behat/mink/src/WebAssert.php:324
    /builds/issue/drupal-3396742/core/tests/Drupal/Tests/WebAssert.php:540
    /builds/issue/drupal-3396742/core/modules/ckeditor5/tests/src/FunctionalJavascript/CKEditor5Test.php:860
    /builds/issue/drupal-3396742/vendor/phpunit/phpunit/src/Framework/TestResult.php:728
    ERRORS!
    Tests: 11, Assertions: 182, Errors: 1.
    

    Test-only feature is still showing the coverage.

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance nod_ Lille
  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ

    I'm not very familiar with this area, but given

    1. the test-only CI job failing on the new test ๐Ÿ‘
    2. @nod_'s comment at https://git.drupalcode.org/project/drupal/-/merge_requests/5127/diffs#no...

    RTBC seems appropriate ๐Ÿ‘

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
  • Status changed to Fixed 9 months ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom longwave UK

    The issue summary and comments make this problem easier for me to understand, thanks! The fix looks to me like the correct thing to do also.

    Backported to 10.2.x as an eligible bug fix.

    Committed and pushed 5d5dde4357 to 11.x and 4548f1308c to 10.3.x and 5540b5f84a to 10.2.x. Thanks!

  • Automatically closed - issue fixed for 2 weeks with no activity.

  • ๐Ÿ‡ง๐Ÿ‡ชBelgium wim leers Ghent ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡บ
Production build 0.71.5 2024