Problem/Motivation
Thanks to #3228334: Refactor HTMLRestrictionsUtilities to a HtmlRestrictions value object, #3259174: Add missing CKE5 SmartDefaultSettings test coverage (wildcard tag with unsupported attribute) and #3259367: [upstream] Allow configuring *which* HTML tags can be aligned, we discussed this challenge with the CKEditor 5 team in the January 20, 2022 meeting. That is how we found out that <$block> in CKEditor 5 largely maps to HTML 5 block-level elements, but not exactly.
This means that the automatic upgrade path we are providing from CKEditor 4 to CKEditor 5 is not guaranteed to support all attributes on block-level elements through CKEditor 5 plugins it enabled, on text formats with HTML restrictions that list allowed tags/attributes/attribute values (essentially: those using filter_html).
Crucial: all tags are still guaranteed to be supported (<$block> does not add support for explicit tags, but adds support for attributes and/or attribute values on already supported tags). The only thing that we need to add explicit support for, are attributes/attribute values on tags that Drupal thinks <$block> implies, but are not actually supported. We can add support for them on the fly using the GHS plugin.
This is technically a data loss problem, because it is possible that pre-existing content contains an attribute on a tag that Drupal thinks a CKEditor 5 plugin has support for, but this is not actually true. Therefore marking this critical
, even though the actual real-world impact is likely very minimal.
We know of no real-world cases (yet) where data loss would occur. This is theoretical, but important nonetheless.
Proposed resolution
Configure GHS with a configuration where wildcards have been resolved based on Drupal's assumption on what the wildcard should be resolved into. This can be all done on Drupals side since we know which tags and attributes should be supported. For the elements that are directly supported by a plugin, GHS acts only as a fallback, and the plugin that provides support for the tag will be still responsible for converting it.
Example: <h2> is supported by the heading plugin which would be responsible of adding <h2> as a supported tag. The source editor could have additional configuration of <$block class>. This could be resolved into <h2 class>. In this case, since the heading plugin is enabled, the <h2> element would be converted by the heading plugin. When there is a class attribute on the <h2> element, the element would be still converted by the heading plugin, but the class attribute would be converted by GHS, unless the heading plugin (or some other plugin) explicitly provided support for the class attribute.
Remaining tasks
TBD
User interface changes
TBD
API changes
TBD
Data model changes
TBD
Release notes snippet
TBD
Issue fork drupal-3260869
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
Comment #2
wim leersFix markup.
Comment #5
wim leersHah, wow, that is a geniusly simple solution, @lauriii 🤩 😄
This also means that we need to completely redo the issue summary, because the solution is far more elegant, and far simpler than we originally thought/feared! 🥳
Review
🤔 But … isn't there one scenario where that is inadequate: the scenario? Because then we should not restrict ourselves to just the block-level HTML elements that are supported, but to all of them? → NOPE, because in that case
will skip the
if-body, which means this will be present:And this allows all tags, plus all styles, classes and attributes. Which means that anything that a
<$block>wildcard tag could possibly allow will be allowed here too.✅👏
Proof of criticality and fix: tests
I think it'd be great to prove that without this MR, there'd be data loss, and with there won't be. i.e. prove the criticality, and prove the fix.
I believe doing that would require test coverage similar to #3259493: [GHS] Unable to limit attribute values: ::allowedElementsStringToHtmlSupportConfig() does not generate configuration that CKEditor 5 expects. Simply expanding the test coverage there would be 10x simpler. And the test coverage there is literally a functional JS test for this CKE5 plugin and the way it behaves depending on how Drupal configures it, so exactly what we need here. So let's wait for
\Drupal\Tests\ckeditor5\FunctionalJavascript\SourceEditingTestto exist first? 🤓Comment #6
wim leersPer #5.
Comment #7
lauriii+1 for adding integration tests for this. Did not add any yet because as you noticed, it would be much easier to do this on top of the tests being added in #3259493: [GHS] Unable to limit attribute values: ::allowedElementsStringToHtmlSupportConfig() does not generate configuration that CKEditor 5 expects.
Comment #8
lauriiiSeems like #3259493: [GHS] Unable to limit attribute values: ::allowedElementsStringToHtmlSupportConfig() does not generate configuration that CKEditor 5 expects was just committed 💥
Comment #9
wim leers@lauriii added tests 👍
I posted several remarks on the MR, these are the 3 key ones:
Comment #10
lauriiiComment #11
wim leersThe test that was failing before is passing now — the fix @lauriii added was simple: the kernel test was creating an
Editorwithout a matchingFilterFormat.This is the scary part from the issue summary that we absolutely need to fix:
This MR implements the solution proposed in the MR. It for example aims to allow right-aligning an
address"block-level" HTML tag whenever:<address>tag is added to the plugin's configuration of extra allowed elements… except that this part is not yet implemented! We need to ensure that whichever wildcard HTML tags are allowed by CKEditor 5 plugins (in this example: the
ckeditor5_alignment.rightplugin) expands onto the full set of concrete elements.The proposed solution in the issue summary does say:
… but "configure GHS" is not the same as "configure the Source Editing functionality": we can still generate the
config.htmlSupport.allow = [{name: "address", classes: ["text-align-right"]}]configuration.In fact, we need to configure GHS even when the functionality is disabled, otherwise we still suffer the same data loss risk. So whenever a CKEditor 5 plugin is enabled which uses a wildcard tag, we should also enable the
htmlSupport.GeneralHtmlSupportplugin generate the aforementioned configuration.Which brings me to a separate point: somehow along the way we got sidetracked in this MR: we instead focused on adding support for
<$block>to the plugin's configuration, even though that's never been mentioned as being in scope. I'm fine with adding this ability (it's valuable!), so I'm fine with keeping this. But we've definitely not yet solved the critical portion of this — and looks like both @lauriii and I missed that so far 🙈tl;dr: we built the necessary infrastructure, used it for a potential manual work-around for the mismatch, but forgot to do the automatic work-around for the mismatch!
Comment #12
lauriiiI believe #11 has been addressed by the latest commits in the MR.
Comment #13
wim leersI really like what you did at first glance, digging into it… 🤓👏
Comment #14
wim leersI really like what you did, @lauriii, but I believe it can be simplified, and make it significantly easier to understand. Less cognitive load to understand/maintain, by treating the two very distinct concerns ("arbitrary/full HTML" and "wildcard tags mismatch") as two distinct plugins:
489eaab4200aa22e03679df3199df4983e279bf7.Comment #15
wim leers:)
Comment #16
wim leersAs far as I'm concerned this issue is now RTBC.
I contributed only a tiny part of this MR. @lauriii was the lead developer on this. We only bounced back and forth on:
SourceEditingplugin for resolving wildcard tags specified by the end user in the allowed tags for source editing)It looks like @lauriii liked with the changes I proposed on March 4. He's still the architect of this MR, so he can't RTB. I still can.
Therefore: 🚢
Comment #17
lauriii+1 for RTBC. I have reviewed all commits from @Wim Leers on the MR and I'm +1 to every commit. 👏
Comment #18
wim leersOnly thing missing: patches for
10.0.xand9.3.x😊Comment #19
lauriiiOpened relative issue to clarify what $block should resolve into.
Comment #20
wim leersThis blocks #3259367: [upstream] Allow configuring *which* HTML tags can be aligned + #3268307: $block wildcard resolves into a superset of the actual $block tags.
Comment #24
bnjmnmAdding credit for @catch and @alexpott because the issue did not pick up on their activity in the MR
Comment #25
wim leersFYI, from Drupal Slack:
So I think they're +1 :)
I personally don't think we should remove
ckeditor5_wildcardHtmlSupport. It adds a clarity we'd otherwise lack:getEnabledDefinitions()to have very explicit logic to decide which one of these two plugins, if any, we need::getCKEditor5PluginConfig()to have very explicit logic to only compute the configuration for wildcard HTML support if it is actually needed — because at that point it is too late to change which plugins will be enabled (at that point only configuration for plugins can be set, not which plugins are enabled)But if @alexpott feels we should still remove the "wildcard" HTML support plugin, happy to do that in a follow-up.
Meanwhile, we have their blessing, so let's keep CKEditor 5 criticals moving forward 🤞
Comment #27
catchI'm agnostic on the plugin declaration, it seems less obvious where the logic would end up, or if it's more a case of injecting the plugin without declaring it (i.e. moving it out of YAML but otherwise keeping the same?). Either way definitely doesn't need to be addressed here.
Committed/pushed to 10.0.x, cherry-picked to 9.4.x and 9.3.x, thanks!