Getting the following JS console error when submitting the embed step: Uncaught TypeError: Cannot read property 'checkReadOnly' of undefined
This works fine in other browsers, so not sure if it's a CKEditor + Chrome issue only
| Comment | File | Size | Author |
|---|---|---|---|
| #41 | 2544020-41.patch | 10.09 KB | wim leers |
| #41 | interdiff.txt | 2.38 KB | wim leers |
| #40 | 2544020-40.patch | 10.33 KB | wim leers |
| #40 | interdiff.txt | 648 bytes | wim leers |
| #38 | 2544020-38.patch | 10.39 KB | wim leers |
Comments
Comment #1
dave reidHuh, I can't seem to duplicate this anymore.
Comment #2
mpastas commentedHey I'm able to reproduce this error using additional modules such as media_entity_twitter.
Let me know if you can reproduce it as well.
Comment #3
mpastas commentedI see this is happening when there is no range selected within the CKeditor DOM. It means the user did not click inside the editor properly.
Comment #4
mpastas commentedThis is happening because the getSelection method of the ckeditor cannot get a proper range because the DOM element is kind of locking the edition area:
The source code is:
<drupal-entity data-embed-button="media_twitter_button" data-entity-embed-display="view_mode:media.preview" data-entity-type="media" data-entity-uuid="40f58ee8-9e0e-4cb9-8e00-5861500aa252"></drupal-entity>So in Editor Mode, you need to use special break lines clicking in the red arrows of the Ckeditor UI to make a "focus" within the editor area.
Steps to reproduce it:
1. Edit a node and embed an entity in the ckeditor
2. Save the node.
3. Edit the node and hit directly the embed button without clicking the CKeditor edition area.
4. Clicking the submit button in the final step you will get the error in the console.
Comment #5
mpastas commentedComment #6
CTaPByK commentedI was tested and debug a bit this bug and i can confirm conclusions from #4, if we don't have focus to editable area of CKEditor on final submit step we will have error (I tested in firefox and chrome, and error appears just in chrome). There is some reported bugs for that error in CKEditor, and this one maybe is related to problem we mention here https://dev.ckeditor.com/ticket/13620.
Comment #7
wim leersConfirmed.
Comment #8
wim leersIn Drupal core's
drupalimageCKEditor plugin, we have this:Unfortunately, we cannot simply port over this code to the
drupalentityplugin, because its "save callback" is completely unaware of thewidgetobject, and there's non way to access that object using the current code architecture.The code quoted above was introduced in #2039163: Update CKEditor library to 4.4 in Drupal 8 core. That landed on May 9, 2014. The
drupalentityCKEditor plugin landed on May 27, 2014. So, quite likely, thedrupalentityplugin was developed against CKEditor 4.3 and earlier, whereas CKEditor 4.4 finalized the CKEditor Widget API.So, as far as I can tell, Entity Embed never had its CKEditor plugin updated to use the final architecture introduced in CKEditor >=4.4, and that would solve this problem.
Hence its JS should be rewritten, based on that of core's
drupalimageplugin. That would likelyComment #9
wim leersThis is now blocking #2813813: CKEditor's "undo" functionality not working.
Comment #10
wim leersThis also blocks #2282957: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog).
Comment #11
wim leersComment #12
wim leersClosed #2956745: CKEditor js plugin upcast does ot check widget name because thanks to the new scope of this issue since #8, we'll basically get that bugfix "for free", so there's no point in keeping that separate issue around.
Comment #13
bkosborneThank you Wim for pushing this issue forward
Comment #14
wim leersExpect more progress soon — progress in patch form :)
Comment #15
wim leers"Soon" — that did not happen :( All my time and attention went to JSON:API until recently. But now I'm back :)
The original bug report, which I was able to reproduce in #8, is no longer reproducible. Presumably CKEditor updates in the mean time have fixed this (Entity Embed's CKEditor plugin hasn't changed at all). Although https://github.com/ckeditor/ckeditor-dev/issues/2517 and https://github.com/ckeditor/ckeditor-dev/issues/3027 are still open and seem to be related.
Thanks to @oknate, #2466013: Write test for CKEditor integration is nearly ready to be committed, and will give us peace of mind :)
Nevertheless, we should still do what this issue title says, because it'll fix #2813813: CKEditor's "undo" functionality not working and #2282957: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog).
Comment #16
wim leersAs part of working on this, I dug deep into #3026433: `entity_embed.dialog` route should not use `_theme: ajax_base_page`; no longer required as of Drupal 8.2 (now descoped since it was a dupe and fixed) + #2844822: The preview in CKEditor does not use the same Twig template as the one on the front end (default theme) (embed previews apparently intended to allow CSS + JS to be loaded), because the most prominent aspect of the CKEditor plugin is its preview capability, and both of those issues are related to that.
Comment #17
wim leersWhile working on this, I noticed that #2813813 could be done independently of this quite easily, and actually reduces risk, since it results in more JS test coverage ensuring this issue gets done well. See #2813813-12: CKEditor's "undo" functionality not working for details. It just landed! 🥳
Comment #18
wim leersWhile struggling with #2511404-73: Image entities/fields embedded using Entity Embed cannot be linked in CKEditor and a solid amount of cursing, I think I've found a way forward there, that also happens to address what we wanted to achieve in this issue, as well as unblocking #2282957: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog). In other words: a breakthrough :) I have a meeting scheduled with the CKEditor 4 lead developer tomorrow afternoon, so he'll be able to confirm whether this is a good direction or not.
This is a pretty significant refactor of the CKEditor Widget. Rather than storing the truth in the DOM, even though it's ephemeral, not actually the truth, and heavily affected by the use of the Drupal AJAX system, this tries to use the CKEditor Widget API "as intended" (as far as I can see). It uses the facilities that API provides to simplify code. This patch makes the code simpler, more robust, and despite there being lots of TODOs, it actually yields a net reduction in lines of code.
Comment #20
wim leersSee #2282957-13: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog) and #2511404-74: Image entities/fields embedded using Entity Embed cannot be linked in CKEditor for screenshots of what this enables 🥳
Now: Wim → 🛌😴
More tomorrow.
Comment #21
oknateLooks very promising.
Comment #22
wim leersOops, this line should've been part of #2282957-13: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog).
Comment #23
wim leersGreen again, yay!
Let's now make this Drupal AJAX-powered fetching of a server-side preview less hacky.
Comment #24
wim leersComment #25
wim leersBeen making progress with captioning support over at #2282957-17: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog). In working on that, I've noticed that it's now re-fetching a preview from the server even when only the caption has been changed. The caption doesn't need to be rendered by the server.
The re-fetching problem has always existed, until #2813813: CKEditor's "undo" functionality not working fixed it. But the refactor in #18/#22 made that fetching logic less hacky, and in doing that, it is again re-fetching. #23 then properly isolated that logic.
Now that the code has been refactored, I think the next step is to make it conditionally re-fetch: only if it makes sense to do so. The following changes should not trigger a server-side re-render:
data-captionchanges AKA changes incaptioneditable (because it looks exactly like the end result already)(Also, I forgot to remove
generateEmbedId()in #23, that's now dead code!)Comment #26
wim leersSorry, bad at multitasking today.
Comment #27
wim leersYesterday, I met with Krzysztof Krztoń, the CKEditor 4 lead developer. I walked him through what I did in the patch on this issue, plus how #2282957: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog) and #2511404: Image entities/fields embedded using Entity Embed cannot be linked in CKEditor build on top of it.
To my relief, he liked most of what he saw. He actually spent a few hours building a proof of concept based on what I told him we need. He built https://codepen.io/f1ames/pen/arQaYJ on top of the
embedbaseplugin in CKEditor core. Codewise it is fairly similar. Key differences:embedbasedoes to avoid integration with notificationsembedbaseprovides, which we won't be able to useembedbaseprovides, because that is oEmbed-centric and hence JSONP-centric<iframe>instance) that is associated with the rendered embedded entity — we can't just break this despite at least the JS loading being questionable (see #2844822-14: The preview in CKEditor does not use the same Twig template as the one on the front end (default theme))embedbaseto be loaded, and hence requires core to adopt a new CKEditor build, and would prevent us from shipping this with this contrib module (not to mention the additional JS bytes to load, parse and execute that we'd never use)Given those considerations, I've decided to continue refining what we already have rather than restarting from scratch. Given his approval of the approach taken in this patch (plus #2282957 and #2511404), I now feel very confident we can make this work great.
Comment #28
wim leersOne thing I learned from https://codepen.io/f1ames/pen/arQaYJ is https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_plugins_widget.h... — which is a single property that automatically masks the embedded content:
Yay, exactly what we need for Youtube embeds for example!
Unfortunately using that masks the entire widget, we need the
captioneditable to still be available for interaction in #2282957: Caption should work like the drupalimage plugin (editable in WYSIWYG, not in dialog). He came up with a clever hack to solve this:figcaption { position: relative; z-index: 1; }. 😀Unfortunately … it doesn't work at all for us. 😩 Our combination of
display: tableplusfloat: right(for a right-aligned captioned embed) on<figure class="caption align-right">means thewidgetCKEditor plugin'smaskfunctionality doesn't work, because it relies onposition: absolute; top:0; left:0; width:100%; heigh:100%; display:block;to cover the parent exactly through pure CSS. But our CSS — which we've had for more than half a decade and we cannot change since it'd break BC — makes that trick impossible.I spent 2 hours trying various things, but came up empty-handed :(
I will ask Krzysztof to see if he has any more clever ideas to solve this.
Comment #29
oknateThe best ideas we can't do now because of BC concerns could become postponed tickets for 8.x-2.x branch or 9.x-1.x branch.
Comment #30
wim leersI did not let the hours of CSS attempts go to waste: I finished #3037316: Show an outline around the <drupal-entity> element within CKEditor and got it committed — that's a definite step forward compared to our current CSS. The patch attempt in #28 is also relative to that, so now it can easily be applied.
Comment #31
wim leers#29: actually, mask support is going to be critical to meet the accessibility gate in Drupal core.
That being said, mask support is not a hard blocker right now for this issue; this issue can make many other things better, so we can proceed :)
Comment #32
wim leersI discovered problems with undo support (separate from #2813813: CKEditor's "undo" functionality not working, which made undo not work at all, right now it works but it's flaky), but those are apparently pre-existing. Krzysztof is looking into it.
To reproduce:
/media/add/imageto create an image and add it to the media library/node/add/articleto create an articleMediaentity embed of an imageExpected: undo button is now grayed out, and you're in the original state.
Actual: undo button is not grayed out, you're not in the original state. Upon clicking the "undo" button again, it's in the original state.
Possibly related: this appears in the browser console:
The same exact steps to reproduce actually also work in HEAD. So I won't make that block this patch from landing: this is not a regression.
Comment #33
wim leersCreated #3060245: [upstream] CKEditor's "undo" functionality not working correctly for embeds: offers multiple undo steps where there should be only one for #32. Also contains a screencast demonstrating the problem.
Comment #34
wim leersAnother thing I noticed while digging through the CKEditor Widget plugin code: we're not yet setting the
pathNameproperty.Which is why you see
drupal-entityhere:Wouldn't it be nice if that showed instead? Or better yet, if it matched what the context menu is showing you? (Just like #2993323: CKEditor Contextual Menu Item should be more specific.)
Turns out that
pathNameis just the Widget plugin's API abstraction for the underlying API, and hence doesn't allow for the dynamism that we need (multiple entity types could be embedded). Fortunately, there is a way to achieve that:Comment #35
oknatenice!
Comment #36
wim leerswas added in #7, based on #4. But that is no longer reproducible. It looks like Chrome's behavior changed and hence fixed this. Pointless trying to write tests for this if the problem wasn't on our end; we could not even write a test for this if we tried.
Comment #37
wim leersdrupalimagedoesn't listen to thedoubleclickevent on the entire editor and then tries to check if the clicked element was the widget. This is costly and brittle.It's better to rely on the existing events.
Bringing that over from
drupalimage.Put differently: this makes triggering the
editdrupalentitycommand more reliable.Comment #38
wim leers#37 removed one call toisEditableEntityWidget(). There's two calls left: one ingetSelectedEmbeddedEntity()(another helper) and one in the context menu listener.Turns out that
isEditableEntityWidget()was introduced by #2544018: Manual embed should not get an option to Edit Entity, to specifically allow for people to type arbitrary<drupal-entity>markup, and have those be turned into previews, without requiring a corresponding CKEditor toolbar button. Which means that those entities that don't have a corresponding button should not be editable through the UI.I have … concerns about this. But I won't be changing this, because doing so would result in a BC break.
(I certainly won't bring that into core. But it's easier to do that in core, since core already is going to limit this to only Media entities, so we're going to be dealing with a far smaller surface area.)
IOW, these two edge cases must not break CKEditor:
They currently do. #34 also regressed against this. Fixed now.
Comment #40
wim leersOops, that shouldn't have been there. Bad rebase. (This comes from #2511404: Image entities/fields embedded using Entity Embed cannot be linked in CKEditor.)
That explains the test failures.
This should do better.
Comment #41
wim leersTime for a final round of clean-up, then let's land this 🥳
Comment #43
wim leersWHEW.
Comment #45
wim leers#28 was not yet done, created #3064572: Add mask to prevent interaction with embedded media for that.