Problem/Motivation

#3261599: Use CKEditor 5's native <ol start> support (and also support <ol reversed>) should've introduced an update hook for replacing <ol start type> in the Basic HTML editor in Standard to just <ol type>.

But … it didn't.

Tests didn't fail. Because Source Editing didn't complain.

This means \Drupal\ckeditor5\Plugin\Validation\Constraint\SourceEditingRedundantTagsConstraintValidator is not working precisely enough.

Discovered this over at #3274635: [upstream] Use CKEditor 5's native <ol type> and <ul type> UX.

Steps to reproduce

Proposed resolution

  1. Add explicit test coverage
  2. Tighten validator
  3. Fix Standard's default config
  4. Write update path

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

None.

Release notes snippet

N/A

Issue fork drupal-3396628

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

Wim Leers created an issue. See original summary.

wim leers’s picture

Assigned: Unassigned » wim leers
Priority: Normal » Major
Issue tags: +Configuration schema, +validation

Tightening this validator should make \Drupal\Tests\standard\Functional\StandardTest fail.

Which in turn should require us to write the missing update path hook.

wim leers’s picture

wim leers’s picture

Turns out this is caused by:

        // If the entirety (so not just the tag but also the attributes, and not
        // just some of the attribute values, but all of them) of the HTML
        // elements being configured to be edited via the Source Editing plugin
        // is supported by a CKEditor 5 plugin, complain. But if some attribute
        // or some attribute value is still not yet supported, do not generate a
        // violation message.
        // If there is overlap, but some attribute/attribute value is still not
        // supported, exit this iteration without generating a violation
        // message. Essentially: when assessing a particular value
        // (for example `<foo bar baz>`), only CKEditor 5 plugins providing an
        // exact match (`<foo bar baz>`) or a superset (`<foo bar baz qux>`) can
        // trigger a violation, not subsets (`<foo bar>`).
        if ($is_attr_overlap && !$source_enabled_element->diff($overlap)->allowsNothing()) {
          continue;
        }

This was introduced by #3260857: Expand SourceEditingRedundantTagsConstraintValidator to also check attributes and attribute values.

It was done intentionally (see #3260857-42: Expand SourceEditingRedundantTagsConstraintValidator to also check attributes and attribute values), but … I think the example here in Drupal core for <ol start type> and <ol start> actually being natively supported is a pretty convincing reason to actually tighten this: it should complain about <ol start>.

If we'd done that, then #3261599: Use CKEditor 5's native <ol start> support (and also support <ol reversed>) could not have forgotten to write the appropriate update path!

wim leers’s picture

Title: Tighten SourceEditingRedundantTagsConstraintValidator to correctly handle partial intersections » Fix <ol start> → native CKEditor 5 functionality and fix bug in SourceEditingRedundantTagsConstraintValidator that allowed it to slip by
Assigned: wim leers » Unassigned
Status: Active » Needs review
wim leers’s picture

Issue summary: View changes
smustgrave’s picture

Running the test-only feature

But @wim leers left 1 question and 1 nitpicky.

LEaving in review.

wim leers’s picture

Assigned: Unassigned » wim leers
Status: Needs review » Needs work

Just realized something: \Drupal\ckeditor5\Plugin\CKEditor4To5Upgrade\Core::computeCKEditor5PluginSubsetConfiguration()'s case 'ckeditor5_list': should also be updated.

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Needs Review Queue Initiative

I was actually confused for a second haha.

Test-only feature failed as expected.

Post_update ran without issue on a standard profile.

So think this is good.

wim leers’s picture

Assigned: Unassigned » wim leers
Status: Reviewed & tested by the community » Needs work

#3393557: [upstream] Update CKEditor 5 to 40.0.0 landed, this needs a rebase & conflict resolution.

wim leers’s picture

Status: Needs work » Needs review

Hoping @smustgrave can review this one more time — found a pretty big bug during rebasing 😅

wim leers’s picture

Assigned: wim leers » Unassigned
borisson_’s picture

There is a failure in the tests, but it looks like that is unrelated and I'm not sure how to rerun tests with gitlab, this looks rtbc imho

wim leers’s picture

Retesting — Nightwatch & Functional JS have been a bit flakey this week…

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Retesting — Nightwatch & Functional JS have been a bit flakey this week…

Extremely flakey!

Also agree this looks good!

lauriii’s picture

Status: Reviewed & tested by the community » Needs work

I posted couple comments in the MR

wim leers’s picture

Assigned: Unassigned » wim leers

Thanks to @lauriii, a new edge case has been found: because SourceEditingRedundantTagsConstraintValidator was originally designed to handle tags, this code made sense:

    // An array of tags enabled by every plugin other than Source Editing.
    $enabled_plugin_elements = new HTMLRestrictions($this->pluginManager->getProvidedElements(array_keys($other_enabled_plugins), $text_editor, FALSE));
    $disabled_plugin_elements = new HTMLRestrictions($this->pluginManager->getProvidedElements(array_keys($enableable_disabled_plugins), $text_editor, FALSE));
    $enabled_plugin_plain_tags = new HTMLRestrictions($this->pluginManager->getProvidedElements(array_keys($other_enabled_plugins), $text_editor, FALSE, TRUE));
    $disabled_plugin_plain_tags = new HTMLRestrictions($this->pluginManager->getProvidedElements(array_keys($enableable_disabled_plugins), $text_editor, FALSE, TRUE));

However … in the case of plugins with optional additional attributes, the above will result for

      'settings' => [
        'toolbar' => [
          'items' => [
            'numberedList',
            'sourceEditing',
          ],
        ],
        'plugins' => [
          'ckeditor5_list' => [
            'properties' => [
              'reversed' => FALSE,
              'startIndex' => FALSE,
            ],
            'multiBlock' => TRUE,
          ],
          'ckeditor5_sourceEditing' => [
            'allowed_tags' => [
              '<ol start type>',
            ],
          ],
        ],

in concluding that for the enabled ckeditor5_list plugin, the following things can be generated: <ul> <ol> <li> … because of

            'properties' => [
              'reversed' => FALSE,
              'startIndex' => FALSE,
            ],

IOW: what's missing here is what additional attributes could be generated by enabling optional settings! 🐣

wim leers’s picture

Now Umami tests fail 👍 https://git.drupalcode.org/issue/drupal-3396628/-/pipelines/47417/test_r...

And it's not just <ol start type> being made editable through "Source Editing" that triggered a violation:

Drupal\Core\Config\Schema\SchemaIncompleteException: Schema errors for editor.editor.basic_html with the following errors: 0 [settings.plugins.ckeditor5_sourceEditing.allowed_tags.7] The following attribute(s) can optionally be supported by enabled plugins and should not be added to the Source Editing "Manually editable HTML tags" field: <em class="placeholder">List (&lt;ol start&gt;)</em>., 1 [settings.plugins.ckeditor5_sourceEditing.allowed_tags.14] The following attribute(s) can optionally be supported by enabled plugins and should not be added to the Source Editing "Manually editable HTML tags" field: <em class="placeholder">Media (&lt;drupal-media data-view-mode&gt;)</em>.

👍

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Needs review

Fixing Umami's editor config nicely triggered a validation error in the corresponding filter_format config:

Drupal\Tests\demo_umami\Functional\DemoUmamiProfileTest::testConfig
Failed asserting that two arrays are identical.
--- Expected
+++ Actual
@@ @@
-Array &0 ()
+Array &0 (
+    0 => 'The CKEditor 5 "<em class="placeholder">Media</em>" plugin's "<em class="placeholder">Allow the user to override the default view mode</em>" setting should be in sync with the "<em class="placeholder">Embed media</em>" filter's "<em class="placeholder">View modes selectable in the &quot;Edit media&quot; dialog</em>" setting: when checked, two or more view modes must be allowed by the filter.'
+)

👍

Fixed that too now — ready for review again, and WHAT A GREAT FIND from @lauriii 👏

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Threads appear to be answered and pipeline showing green. No randoms this time!

catch’s picture

Status: Reviewed & tested by the community » Needs work

Left a comment on the MR regarding the post update.

xjm’s picture

Reposting my question from Slack: Does the upgrade path work from both Drupal 9 and CKE4 as well as from CKE5/Drupal 10 content getting updated a second time? Moving the fix to presave would also help with that aspect, but it still needs its own consideration since the source data formats from the two versions would be different.

wim leers’s picture

Assigned: Unassigned » wim leers
wim leers’s picture

Assigned: wim leers » Unassigned
Status: Needs work » Needs review

#23: did that. 👍

#24:

Does the upgrade path work from both Drupal 9 and CKE4 as well as from CKE5/Drupal 10 content getting updated a second time?

Yes.

Drupal 9 and CKEditor 4
This part was covered by the original #3261599: Use CKEditor 5's native <ol start> support (and also support <ol reversed>) issue already. See git show e935c438 -- core/modules/ckeditor5/src/Plugin/CKEditor4To5Upgrade/Core.php for the updated 4 → 5 upgrade path, and git show e935c438 -- core/modules/ckeditor5/tests/src/Kernel/SmartDefaultSettingsTest.php for the explicit test coverage. Note the
-              '<ol start type>',
+              '<ol type>',

, meaning that from that point onwards, it wouldn't configure ckeditor5_sourceEditing anymore to enable the user to set <ol start>.

This means that any site upgrading from CKEditor 4 to CKEditor 5 using a release that includes that commit does not need this update path, i.e. it will be a no-op.
Test coverage proving the no-op update path: CKEditor5UpdateOlStartReversed + core/modules/ckeditor5/tests/fixtures/update/editor.editor.test_format_list_ol_start_post_3261599.yml (added just now to explicitly test this case too 👍)
Drupal 10 and CKEditor 5
That's what this issue fixes.
Test coverage proving the belated update path: CKEditor5UpdateOlStartReversed + core/modules/ckeditor5/tests/fixtures/update/editor.editor.test_format_list_ol_start.yml
smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Believe additional feedback has been addressed.

For my personal knowledge is there a good rule of thumb about when post_update should be used vs save?

wim leers’s picture

For my personal knowledge is there a good rule of thumb about when post_update should be used vs save?

I've been struggling with this too, even after @catch has pointed this out … 3 times in 2 months? 🙈

I think the rule is: for all config entities, always 🤔

longwave’s picture

Version: 11.x-dev » 10.2.x-dev
Status: Reviewed & tested by the community » Fixed

This change involves an upgrade path but the update is small, self-contained, has no BC concerns that I can see, and fixes a major bug, therefore I think the impact outweighs the disruption and therefore this can be committed during the beta phase of 10.2.0. It's also nice that we found and fixed extra config validation violations here!

Committed and pushed bcf5a9159e to 11.x and ec24a58c6d to 10.2.x. Thanks!

  • longwave committed ec24a58c on 10.2.x
    Issue #3396628 by Wim Leers, smustgrave, lauriii, xjm, catch: Fix...

  • longwave committed bcf5a915 on 11.x
    Issue #3396628 by Wim Leers, smustgrave, lauriii, xjm, catch: Fix...
catch’s picture

I think the rule is: for all config entities, always

Yes, this is correct :) Anything that could be in the database but also potentially in config shipped with a module.

Status: Fixed » Closed (fixed)

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

joshuami changed the visibility of the branch 3396628-tighten-sourceeditingredundanttagsconstraintvalidator to hidden.