Problem/Motivation
This is a follow-up to #2994696: Render embedded media items in CKEditor, which is itself a follow-up to #2940029: Add an input filter to display embedded Media entities, and the third step of #2801307: [META] Support WYSIWYG embedding of media entities.
The first part is a @Filter
plugin, that's what #2940029: Add an input filter to display embedded Media entities provides: Drupal stores media embeds in a structured way using <drupal-media>
tags, that are transformed on output. This way, Drupal stays true to its ethos of structured content.
The second part is to make these <drupal-media>
tags have a great authoring experience. We don't want content authors to have to look, understand and manipulate that markup: that'd be a usability nightmare. That's what #2994696: Render embedded media items in CKEditor handles.
The third part is to not require content authors to manually construct <drupal-media>
tags by hand 😅😇
The scope of this issue is solely the selecting of media from the Media Library and embedding it. Toggling captions and overriding metadata such as alt
is the scope #2994702: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption`!
Proposed resolution
It should:
- offer a smooth media selection experience with a minimum of clicks/key presses and a minimum of cognitive overhead
- offer a button that can be enabled via drag-and-drop in the Text Editor configuration UI at
/admin/config/content/formats/manage/basic_html
- have a crystal clear button icon
Remaining tasks
- Reviews!
Convert toConverted in #34.*.es6.js
- A crystal clear icon for the button 🤓
- UX sign-off
Tests
User interface changes
None.
API changes
None.
Data model changes
None.
Testing steps
- Install latest 8.8.x
- Apply the patch
- Go to Administration => Configuration => Content authoring => Text formats and editors
- Select a text format (e.g. Basic HTML)
- Check " Embed media" under "Enabled filters"
- Unlike in #2994696: Render embedded media items in CKEditor and #2940029: Add an input filter to display embedded Media entities, this step is no longer necessary!
Add<drupal-media data-entity-type data-entity-uuid data-view-mode data-align data-caption>
in "Limit allowed HTML tags and correct faulty HTML" if the filter enabled and "Save configuration" - Drag-and-drop the "Insert Media from Library" button to enable it, this automatically whitelists the necessary HTML. Note that if you also want alignment and captioning, you'll need to still add
data-align
anddata-caption
manually — these are not required and hence not added automatically. That should look like this:
- Go to node add article (
/node/add/article
) - Click the button you just added, you should see the media library selection:
- Select something you like:
- Click the "Source" button in CKEditor
- Add
<drupal-media data-align="center" data-caption="The first core Media embed ever." data-entity-type="media" data-entity-uuid="84911dc4-c086-4781-afc3-eb49b7380ff5" data-view-mode="full"></drupal-media> <p>and</p> <drupal-media data-align="center" data-caption="This media entity is missing" data-entity-type="media" data-entity-uuid="wrong" data-view-mode="full"></drupal-media>
- Click the "Source" button in CKEditor again. Now you should see:
- Now just like in #2940029: Add an input filter to display embedded Media entities's testing steps, save the article, and you should see:
Good preview, isn't it? 🙂 - Now go back to edit it, and observe how the preview loads instantly — just like in https://www.drupal.org/files/issues/2019-06-28/media_embed%20cached%20pr...
Click "Insert selected", this is the result for #13: and this if we go with #15:
Comment | File | Size | Author |
---|---|---|---|
#93 | 2994699-92-editor.png | 2.1 MB | phenaproxima |
#93 | 2994699-92-config.png | 140.46 KB | phenaproxima |
#91 | 2994699-91.patch | 34.77 KB | ckrina |
#90 | 2994699-90.patch | 34.76 KB | ckrina |
#89 | 2994699-89-drupalmedialibrary-hidpi.png | 9.77 KB | phenaproxima |
Comments
Comment #2
phenaproximaComment #3
legovaerComment #4
legovaerI changed the order of these issues as we first need a working CKEditor plugin before we can actually start parsing the code. I have been looking for a workaround for two days so therefore I recommend this approach.
IMO: we should create an additional issue for getting approval of the UX team for the layout of the dialog / button of this plugin so that we can focus on UX in a single issue.
Comment #5
phenaproximaAgreed! Will you kindly open that issue, tag it "Usability", and re-shuffle the postponement order of the meta-issue?
Comment #6
legovaerThis patch adds the plugin to CKEditor and parses the
drupal-entity
tags.Comment #7
Wim LeersComment #9
Wim LeersQuoting #2994696-8: Render embedded media items in CKEditor:
Comment #10
Wim LeersBecause we were still very deep in stabilizing https://www.drupal.org/project/entity_embed, yet we wanted to already validate some core issues that we knew would block this core issue (such as #3044649: Delegate media library selection handling to the "thing" that opened the library and #3038254: Delegate media library access to the "thing" that opened the library), we opened #2998005: [PP-1] Support Drupal core's Media Library in the Entity Embed issue queue to do some early prototyping.
Now that both #2940029: Add an input filter to display embedded Media entities and #2994696: Render embedded media items in CKEditor have core patches, it's time to bring that to Drupal core too :)
I'm currently porting #2998005-51: [PP-1] Support Drupal core's Media Library to a core patch that builds on top of both #2940029 and #2994696.
Comment #11
Wim LeersThe patch that will soon follow was ported from #2998005-51: [PP-1] Support Drupal core's Media Library, but I think it's probably more productive if all work now continues in this issue rather than in a contrib module. Because this will need product manager and UX meeting sign-off, i.e. it needs to have the full attention of core contributors for it to succeed, and hence it should be done solely in Drupal core. Now that the blocking puzzle pieces have core patches (see #10), that is now actually feasible. Closing #2998005.
Comment #12
Wim LeersQuoting one very relevant bit from #2998005-51: [PP-1] Support Drupal core's Media Library:
That's why I think this issue should deal only with point 1: a smooth media selection and embedding experience. Per-embed overrides and changing alignment and toggling captions are for #2994702: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption`
Comment #13
Wim LeersThis patch:
DrupalMediaLibrary
CKEditor pluginDrupalMediaLibrary
requires theDrupalMedia
CKEditor plugin that #2994696: Render embedded media items in CKEditor is adding<drupal-media …>
HTML and inserts that!alt
overiding, nothing: you select media, and then it appears in CKEditor.embed
orembedded
view mode, which will help ensuring a sensible out-of-the-box experience.Comment #14
Wim LeersForgot one screenshot.
Comment #15
Wim LeersAre you also a bit disappointed by that last screenshot in #13? I am. But it's the smallest scope possible.
That's why I wrote:
Perhaps we want to add this new view mode here. Perhaps we want it in a separate issue. TBD.
But what we can do right now is make the insertion from the media library set sane defaults for alignment and captioning: center aligned and allowing the end user to enter a caption immediately after insertion:
Comment #16
Wim LeersForgot #15's screenshot.
Comment #17
Wim LeersA few things worth calling out for reviewers:
It's worth calling out that this CKEditor plugin explicitly lives in the
media_library
module, not in themedia
module.Because sites that only have the
media
module installed of course cannot select media from a non-existent Media Library.That's why this CKEditor plugin is called
DrupalMediaLibrary
and why it's a separate plugin in the first place.This guarantees that the
DrupalMedia
CKEditor plugin from #2994696: Render embedded media items in CKEditor is loaded — which provides the nice previews thanks to CKEditor Widgets.This is copied verbatim from
core/modules/ckeditor/js/plugins/drupalimagecaption/plugin.es6.js
, and was itself originally written by the CKEditor 4 Lead Developer of the time (@reinmarpl).Comment #18
Wim LeersComment #19
Wim LeersComment #20
Wim LeersComment #21
Wim LeersThis should be updated now, because #3038254: Delegate media library access to the "thing" that opened the library landed a few minutes ago! 🥳
Comment #22
Wim LeersAddressed #21.
Comment #23
Wim LeersA few rounds of feedback have been incorporated into #2940029, rebasing #22 on top of #2940029-91: Add an input filter to display embedded Media entities.
Comment #24
Wim LeersRerolled #22 to match #2940029-97: Add an input filter to display embedded Media entities's marking of
data-view-mode
as optional. #2994696-23: Render embedded media items in CKEditor was already updated for the same reason.Comment #25
Wim LeersThe defaults-to-solicit-feedback chosen in #15 were given feedback during yesterday's UX call. We should remove
data-caption
per #2994702-18: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption`.2.Comment #26
Wim Leersvs
@kcolaers in #2994702-21: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption` noticed that there is a file vs class naming inconsistency that we should fix here.
In the same vein: we should not make this coupled to
ckeditor.module
, but instead toeditor.module
. Looks like the code already isn't CKEditor-specific. So this should be renamed toMediaLibraryEditorOpener
.Comment #27
Wim Leers#2940029: Add an input filter to display embedded Media entities landed. Rerolled, on top of #2994696-25: Render embedded media items in CKEditor.
Comment #28
Wim LeersAddressed #26.
Comment #29
oknateAdding test coverage here:
/core/modules/media_library/tests/src/FunctionalJavascript/DrupalMediaLibraryTest.php
(See the interdiff in the next comment).
Removing "Needs tests" issue tag.
One question I have: I'm not sure why there is stuff about captions in the drupalmedia plugin.js in this patch. Is there a way to add a caption I'm not seeing? If so, we'll need to add test coverage for that. I think those changes might belong in the next issue: #2994702: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption`.
Update: It turns out the test failed because the class didn't match the filename, fixed in #33.
Comment #30
oknateHere's an interdiff for the new test added in #29.
Comment #31
oknateSome minor cleanup on test added in #29.
Comment #32
oknateThis would be similar to what we did for the route check MediaFilterController::formatUsesMediaEmbedFilter
drupal_get_path('module', 'media_library')
should be replaced with$this->moduleExtensionList->getPath('media_library')
Comment #33
oknateI had a cut-and-paste error where I failed to rename the class to match the file.
Comment #34
oknateAddressing #32
1. ✅Added in comment #35.
2. ✅Added a check that media_embed filter is enabled to MediaLibraryEditorOpener::checkAccess(). I didn't add a check that DrupalMediaLibrary button enabled, as this should be true if this access check is being called. A check for media_embed filter is more important, as the media embed won't render without the filter. I also added form validation on the text format to assure this filter is enabled if you enable the button on a text format.
3. ✅updated
4. ✅fixed coding style
5. ✅Added test coverage of undo and redo
6. ✅Added form validation requiring media_embed filter to if DrupalMediaLibrary button in toolbar in editor. Added test coverage for this.
Also, converted drupalmedialibrary plugin.js to es6.
Comment #35
oknateAddressing #32.1, adding test coverage for MediaLibraryEditorOpener::checkAccess().
Also, I noticed one bug with "Undo" functionality. I put a note in the test about it:
After you insert a media embed, the undo button should immediately be enabled, and you should be able to undo the embedding. In the test, the Undo button is only enabled after you hit the source button and then hit it again, re-rendering the embed, and presumably the Undo functionality at this point is the Undo handling in drupalmedia plugin.js, not in drupalmedialibrary plugin.js.
Comment #36
oknate@covers for ::checkAccess() was wrong. I had forgot where it was when I was adding that. This method isn't in DrupalMediaLibrary that the test class is covering:
* @coversDefaultClass \Drupal\media_library\Plugin\CKEditorPlugin\DrupalMediaLibrary
Since I'm testing more than the one class, I think I should give the test a more generic name. I'll stick with the pattern previously established by several other modules and go with CKEditorIntegrationTest.
Comment #37
oknateRe-roll against latest patch (194) from #2994696: Render embedded media items in CKEditor. Mostly dropping the CKEditorTestTrait.
Comment #38
oknateRerolling a combined patch. The patch in #37 still applies cleanly on top of 2994696-222.
Comment #39
kim.pepper#2994696: Render embedded media items in CKEditor landed so un-postponing.
Comment #40
Wim LeersIndeed! I'll rebase this and #2994702: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption` 🥳
Comment #41
Wim LeersRebased #37. Review of @oknate's changes since my last patch iteration in #28 to follow next.
Comment #42
Wim LeersIn #28, this was a 8.94 KB patch. Today, it's a 27.4 KB patch, thanks to the test coverage @oknate added.
MediaLibraryEditorOpener::checkAccess()
also checking if the filter is enabled: +1DrupalMediaLibrary
needing themedia_embed
filter: +1 for the form validation error.Patch review + reroll
🔎 Extraneous blank line. Fixed. ✅
🔎 Nit: "filter enabled if button is enabled" sound strange. Improved. ✅
🔎 Nit: extraneous blank line. Fixed. ✅
👎 This validation logic should only run if the text editor is CKEditor. Fixed. ✅
🔎 This should use the same logic as
media_filter_format_edit_form_validate()
to get the translated filter label. Fixed. ✅We still need this for sure 😁
👎 This is hardly an "admin" user. Fixed. ✅
🔎 Nit: "format validation" sounds pretty abstract. Let's rename it to "configuration validation". Done. ✅
👎 This matches the class name. That's odd. Let's instead name this
testButton()
. Fixed. ✅🤔 This can be be made quite a bit simpler. Done. ✅
🤔 Why the
(…)[1]
? I've never seen that before in a test assertion. I grepped my Drupal installation to find something similar (using this regex:xpath.*\)\[\d\]['"]{1}
), and found only one, in a contrib module:\Drupal\entity_reference_revisions\Tests\EntityReferenceRevisionsAdminTest::testMultipleTargetBundles()
has this too.AFAICT this is selecting the second media library item. Why though?
🔎 Übernit: s/Provider/provider/. Fixed. ✅
👎 These are oddly named. Fixed. ✅
👎 These are identical to those in
\Drupal\Tests\media\FunctionalJavascript\CKEditorIntegrationTest
. Let's extract them into a trait that both test classes use. Done. ✅Comment #44
Wim LeersI deliberately omitted one thing from #42 to keep #42 simpler:
data-caption=""
. Since then, it was decided in a UX call that we should not caption media embeds by default — see #25 for that decision. I should've removed this JS addition in #25. Well spotted!Removed it from this patch. I'll add it to #2994702: Allow editors to alter embed-specific metadata, as well as `data-align` and `data-caption` instead.
Comment #45
Wim Leers#41's test results finally came back. The failure is because of a change in the previous patch in the chain, over at #2994696-214: Render embedded media items in CKEditor. Rather than a custom
media-embed-widget
class, we're now relying only on the CKEditor Widget classcke_widget_drupalmedia
. Easy fix :)Comment #47
oknateRe #42.11 :
Actually, it selects the first from the list. It's rare in programming for something to not be zero-based.
see https://stackoverflow.com/a/14295136/1214689
I wrote a test for Entity Browser testing drag and drop re-ordering where I used this pattern a lot. It allows getting the first item from the list in one shot when there is more than one of a selector. I like it because I can use a more general class name as a selector and then grab a specific one using xpath. If you have a more elegant way, I'm all ears.
Re #42.14:
Phenaproxima recommended that we hold off on extracting a trait, see #2994696-191: Render embedded media items in CKEditor.1 and move that into a separate issue. I think the concern is the trait could slow RTBC for this issue (it could "raise committer eyebrows"), and that the methods might need to be reworked to be more generic. Maybe you can discuss it with him.
Comment #49
Wim LeersIn #42 I was unable to reproduce #35. Now I've found a way:
/node/add/article
If before step 2 you click inside the CKEditor iframe instance, or for example type something first, then the undo button does work as expected.
Pinged CKEditor maintainer @kkrzton about this.
Comment #50
Wim Leers#47:
Comment #51
oknateFixing the tests (continuing the effort started in #45).
For those who are catching up, the classes changed in the previous commit (#2994696: Render embedded media items in CKEditor), so:
Comment #52
phenaproximaDidn't read the tests, but I read the rest of the patch. Looks really good to me!
Although it should be obvious, maybe we should also mention that this trait only works with functional JavaScript tests.
This parameter description needs to start with (optional) and state that it defaults to 'edit-body-0-value'.
It might be preferable for us to use $this->assertSession()->assertJsCondition() here, since that will cause the test to fail (and rightfully so), if CKEditor is not ready in time.
What if there is more than one CKEditor instance on the page? Maybe this method should accept an $index parameter, defaulting to 0, to choose which CKEditor to work with. And then it can use that index to generate a unique name, like "ckeditor_0". Alternately, we could have this method loop through every CKEditor frame (getElementsByClassName() returns a set of elements anyway) and assign a unique one to each: "ckeditor_0", "ckeditor_1", etc.
Again, what if there are multiple CKEditor instances?
I'm starting to see that maybe adding this "support for several editors" stuff is out of scope for this issue. If we don't address these concerns here, can we open a postponed follow-up for it?
This method is virtually identical to pressEditorButton(). It might make more sense to remove pressEditorButton() entirely in favor of a pattern like
$this->getEditorButton('drupalmedia')->click()
. Or, if that's too much, how about we just change pressEditorButton() so that it contains one line:$this->getEditorButton($name)->click()
. There's no need for us to repeat this code.I think this could use a
@see
.😁 As opposed to...? (No action needed here.)
...but apparently we have problems with this, from what I hear. Should we add a comment here referencing the undo-related follow-up(s)?
Why wouldn't editor.ui.addButton exist? This could use a comment.
This should be using Drupal\Component\Serialization\Json::decode().
Why are we limiting this to the first button group? Shouldn't we loop through all of them?
Kind of a nitpick, but no real need for a foreach() here. We can just do
$buttons = array_merge($buttons, array_values($button_group['items']))
.🤓💪Nice to see this API getting more exercise!
Nit: "Text Editors" should be "text editors".
We should inject the filter_format entity storage handler in the constructor and use it to load the filter format. Also, we should probably forbid access if the format cannot be loaded.
This isn't our fault, but the filters() method's DX is weird as hell. So, I'd prefer something like the following, to make explicit our requirement that the media_embed filter be present:
I'm wondering if it might not make sense to throw a LogicException if there are multiple selected media IDs. For a text editor,
count($selected_ids) > 1
is most definitely an error condition -- it should not be possible to select more than one.Also, we should inject the media entity storage handler into the class and use it to load the selected media item.
We should inject the media_type entity storage handler as a dependency and use it to load the media types.
Question: do want to make configurable which media types can be chosen? If so, we should do it in a follow-up -- just thinking out loud here.
🤔Hmmm...this is okay for now, but maybe we should open a follow-up to refine this opinion. Especially since we can't count on the
image
media type actually existing.🤓🤔I wonder if we should add -- in a follow-up! -- a method to MediaLibraryState which can merge its parameters into an existing Url object. Something like
$state->mergeUrl(Url::fromRoute('media_library.ui')->toString(TRUE)->getGeneratedUrl()
.This needs design input and blocks RTBC/commit. I have summoned @ckrina. 🧙♂️
Comment #53
phenaproximaTagging for design per #52.22.
Comment #54
Wim Leers#52:
iframe
) and inline mode (contenteditable
).DrupalLink
plugin also does only the 90%, and https://www.drupal.org/project/editor_advanced_link fills most of the remaining 10%. (Quite literally, since about 10% of Drupal 8 sites have that module installed.)image
does not exist, it won't pick it. This is perfectly safe.Comment #55
phenaproximaI'm okay with deferring changes to CKEditorTestTrait, so I opened #3073261: Improve CKEditorTestTrait.
Comment #56
oknateAddressing #52
1. ✅ Added some verbiage about functional javascript.
2-5. Moved these comments to follow up issue.
6. ✅ I like the idea of keeping pressEditorButton() for readability but replacing the redundant code within, so I implemented that suggestion.
7. This looks like it's only affected by classy. So this rule should probably go in classy, either in core/themes/classy/css/components/ui-dialog.css or in a file for media_library style overrides in classy. I need a FE dev who's familiar with the framework to give me some guidance on best practices there.
9. ✅ Added follow up issue: #3073294: Remove obsolete @todo for "Undo bug when first inserting media into unfocused CKEditor" and link to follow-up issue.
10. 🚫 Leaving alone per Wim feedback that this follows an established pattern.
11. ✅ Switched to using Json::decode().
12. ✅ Excellent find. We were only looking at the first row. I added the embed on the second row to verify this, and a fail patch to demonstrate the bug. I added a bug report to the entity_embed issue queue as well.
13. ✅
15. ✅
16. ✅ Injected the filter_format storage in the constructor and added code to forbid access if the config entity cannot be loaded.
17. ✅
18. ✅ Added logic exception. We should add test coverage for this (possibly?). Wim says it's impossible to trigger the error in #54 Perhaps with a Kernel test of some type?
19. ✅Added media type storage. The follow-up I left alone for now.
20. Added a follow up to see if the default selected_type_id can be improved https://www.drupal.org/project/drupal/issues/3073309
Comment #57
oknateComment #58
phenaproximaThanks, @oknate! Few more requests...
s/javascript/JavaScript
I think we can probably revert this. Wim's pushback made sense -- we hard-code a 1-item limit for CKEditor, and it shouldn't be possible to choose more than that. It's not worth the added test coverage to add this exception, IMHO. :)
Why did this change? I think it made more sense the other way, to be honest.
Since we only need the IDs, loading the entities is a heavier operation than simply querying for them. So, this can be changed to
$media_type_ids = $this->mediaTypeStorage->getQuery()->execute()
.
Comment #59
phenaproximaAlso, thinking a bit more about this --
I really think we should make this part of plugin configuration. If it's not set, we can default it to all media types. But we should allow it to be overridden. I can very easily imagine scenarios where site builders only want to allow certain media types to be used in CKEditor, varying by format.
We don't need to expose a UI for this (at least not now), but I would like it to be configurable. If needed, let's do it in a follow-up issue. I have a feeling this is something that will be requested.
And, while I'm at it, this should also be part of plugin configuration. If we make the media types configurable (and I believe we should), then we should also make the default one configurable.
I don't really agree with the "leave it to contrib" approach -- there is no easy way that I can see for contrib to modify this behavior, short of swapping out the entire plugin class. I think it'd be much nicer to just accept the allowed media types, and the default media type, in plugin configuration, then let contrib expose a UI for changing those things.
EDIT: I do, however, agree that making these configurable in this issue would be scope creep. So I will open a follow-up to address this concern. Carry on!
Comment #60
oknateAddressing #58.
1. ✅
2. ✅
3. ✅ I've undone this change for now, and I'll try to avoid making unnecessary changes. This was just a personal thing . The name seemed odd to me. The other core CKEditor plugins have names like "Image", "Drupal link", "Drupal image caption widget", "Styles dropdown". The entity embed module calls it simply "Entity". These are all names, rather than descriptions. They start with nouns or adjectives. "Embed" is a verb, so it sounds like a command or a description of the action it performs.
4. ✅
Comment #61
AaronMcHaleI second #59 although don’t see why we shouldn’t expose a UI, I can see this being useful for a lot of sites.
Comment #62
Wim Leers👍🤩
media_embed
filter, not for the CKEditor integration. Just like we already added adefault_view_mode
setting, we should then add aallowed_media_types
setting. Then the CKEditor integration (but also a similar implementation for any other text editor) can just read that configuration. But before we even go that route, let's first address the reason for adding configuration:I disagree. It'd be trivial. I should've explained why it's trivial. Let me explain by just writing everything that this contrib module would have to do:
Hopefully this convinces you :)
Comment #63
phenaproxima@Wim Leers: I'm still not sure I fully agree with your response to #59. :) However, what we definitely agree on here is that this is not the issue, nor the right time, at which to figure it out. So I've opened #3073535: Allow only a subset of the media library to be exposed to CKEditor for later. I look forward to a civilized battle of the minds in there. :) 🧠
Comment #64
phenaproximaRead the tests. Really straightforward -- I love the way this patch is shaping up!
Nit: We don't need to enable media and media_library; media_library has media as a hard dependency already, and this is not likely to change any time soon.
It would be more readable to use the $page methods for these interactions:
This will also implicitly assert the existence of the field/button.
Nit: We can reduce these down to one line, which, I think would be more readable:
This will find the first .media-library-item element, which is equivalent to the XPath query.
This needs a @see.
This can be one line.
$assert_session->elementExists()->getValue()
.Why do we need to repeatedly switch back into the CKEditor iframe? This could probably use a comment.
I wonder if this should be a dedicated kernel test, for the sake of speed. They're MUCH faster than functional tests (especially functional JS tests).
Comment #65
AaronMcHaleRe #62:
+1
Yeah actually that's a fair point regarding "inserting from the media library" vs "inserting from some subset of the media library".
That being said and regarding your specific example (BTW this is clearly going to be a tangent but still worth mentioning), 30K sites is around 10% of Drupal 8 sites (as reported by https://www.drupal.org/project/usage/drupal). In the case of Editor Advanced Link, 10% might be reporting using that module, but that doesn't mean that X% more sites wouldn't benefit from a feature like that being in Core. The percentage of sites currently using a feature is a good indicator of whether something should be in Core, but it can't be the only one and it shouldn't demerit the value added by including something in Core... How do you measure the true value added to the editing experience by including something in Core out of the box? Does including a particular feature tick another box for more evaluators who are trying to decide which CMS to use? Does adding more features available out of the box make it easier for site builders to choose Drupal because it simply "just works" for their needs? Maybe, or maybe not, but to me these leading questions do form part of the reasons why new Core modules like Media and Layout Builder are in Core and not contrib. That being said, maybe I'm thinking into this too deeply.
Anyway, my ramblings and questions above are more rhetorical than questions that can actually be answered, and I'm going to stop there because this is really more of a discussion for another time and place, and I don't want to side track this issue. But I'd say 30K sites using one Contrib feature is a pretty clear indicator that maybe that feature should at least be considered for inclusion in Core, and there's probably examples of other features which have been committed without having to be justified based on how many sites used an equivalent Contrib module.
Comment #66
Wim LeersGreat question :)
In the case of https://www.drupal.org/project/editor_advanced_link, the argument was that we shouldn't complicate the UX of something that is used millions of times per day for 100% of sites if only 10% of sites need it.
But in this case, it's just configuration. So it would only complicate the site builder experience.
Which means you've (accidentally? :D) convinced me that it's okay for us to add this to Drupal core! 😁 Let's continue this in #3073535: Allow only a subset of the media library to be exposed to CKEditor.
Comment #67
oknateAddressing #64
1. ✅Removed unnecessary dependency.
2. ✅Added $page method for improved readability.
3. ✅Changed code to one line. I think I was confused by some feedback you had for me on another patch about checking if elements exist before calling methods on them. I guess for ->click() and ->getValue() it's fine because they'll throw an error if empty.
4. ✅Added link to the follow-up issue.
5. ✅same as 3
6. ✅Added comment explaining why we keep switching back to the same iframe.
7. ✅Converted test to Kernel test for speed. 🏎🏎🏎
Comment #68
phenaproximaI'm out of things to complain about. Just nitpicks left.
We can delete these lines. They're superseded by
$page->uncheckField('filters[media_embed][status]')
.Nit: This should use the existing $assert_session, rather than calling $this->assertSession() again.
Nit: I think we can call this "testEditorOpenerAccess". The words "MediaLibrary" are superfluous. :)
Nit: These can be collapsed:
After these are fixed, we just need a new icon, which @ckrina is working on. Then it's down to manual testing and review/commit (ideally from a product manager).
Comment #69
oknate1. Added the code for the icon. I took the image icon and added an extra moon.
2. Addressed nits in #68
3. Ran eslint and prettier and cleaned up the es6 and javascript.
Comment #70
phenaproximaChanges look great to me!
So, I think the only remaining tasks are:
Comment #71
webchickWent through a WebchickTestCase with @phenaproxima and @oknate, and here were the results!
1) It would be good when we know what the final icon will be and can get confirmation that it will be visually distinct in some way from the Image button on CKEditor. Because by default, people are going to end up with two buttons that do almost the same thing, at least until their site administrator has configured some stuff differently. (If we don't already, we should maybe spin off a follow-up to talk about what we want the upgrade path to be here, esp. once Media Library is part of Standard profile.)
2) When using the icon to open Media Library, there's a visual bug in that Image is selected by default (+1) but Audio is also highlighted, causing a visual regression:
@phenaproxima explained that this is because there's code somewhere for accessibility reasons to automatically select the first item in a list. That's good, except that because Image isn't the first thing in the list, it's selecting both. Even though this is not the fault of this patch, I really don't think we can commit it with this because it's a pretty obvious visual problem in a primary content author user interface. (We don't want to introduce major bugs as we go.)
We talked about two possible solutions: one to change the logic of that code to act on the element that has focus first, should one exist, and only then falling back to the first option; or two, if that turns out to not be a simple fix, to hack around it by moving Image to the top for now and addressing it in a follow-up. (I would rather not postpone this important thing on a separate bug fix issue for it, so whatever's easiest to fix here +1.)
3) It's a little odd that checkboxes are presented here (indicating multiple selections are possible), but your choices are limited to only one. Radio buttons would be the standard UI element for this kind of choice. However this is a "pre-existing condition" with any time the Media Library is showing you a group of things you are limited to only being able to select 1 of, so fine to handle in a follow-up (and just "normal" priority; there are other visual indicators like the disabling of controls and the fading out of the other selections and the tiny, tiny text in the lower-right saying "0 of 1 selected" to help you understand that you can only select one thing).
4) Once you insert a media element, what I expected to be able to do was position the cursor to the right and press Enter a couple of times (like I do in Microsoft Word, Google Docs, etc.) to get to the place where I could type some more text and/or add another media element. However, this didn't work. @oknate helpfully pointed out that you need to click this tiny, tiny red arrow thingy in order to get another "paragraph" and be on your way and never in one gazillion lifetimes would I have figured that out by myself. :)
Anyway. WELL out of scope for this issue, but IMO worth another follow-up for that, probably "major" though. (If this is indeed something we can even do anything about; I'm not sure if this behaviour is something CKEditor just forces on people but IMO it's gonna trip people up horribly, and @oknate confirmed he has to train his content authors on this all the time).
TL;DR: This is looking great; just the icon and the double-activation bug to sort out and we are good to go! <3
Comment #72
seanBThe media library has a state parameter for the available types, and respects the order that is passed. I think the easiest solution for this would be to make the order configurable in the filter and always select the first media type. I think phenaproxima opened an issue for this already.
It would also be nice to be able to disable media types for embedding, but that is a completely separate issue.
Anyway, great to see how this is all coming together. Thanks everyone for the amazing work!
Comment #73
phenaproximaThanks, @seanB! I agree with your proposed solution. However, this should not be done in the filter, IMHO; it's squarely an aspect of the button's config. There is already an interface that exists to allow CKEditor plugins to define configuration: https://api.drupal.org/api/drupal/core%21modules%21ckeditor%21src%21CKEd.... Let's leverage that.
So, to summarize -- the button should allow all media types, but it should make their order configurable so that the first one is selected (as with the field widget). That keeps things nice and consistent.
Comment #74
seanBJust read the patch as well while I was at it. Very little to complain about. Great work!
While looking at this, it one the one hand seems that this works for all editors, but at the same time we focus specifically on CKEditor.
So my question is, should this work for all text editors? If not, it might help to remove any possibility for confusion in naming the classes, service, and documentation. So for example user
media_library.opener.ckeditor
,MediaLibraryCKEditorOpener
etc.As mentioned in my previous comment, let's make this sortable (can be a followup) and remove the "select image by default" weirdness for now. Or we can force the image type to be the first item. That would fix it as well.
We consistently try to use "media item" instead of "media entity."
Comment #75
ckrinaHere's a bit procrastination sorry... I prepared several icons. I'm adding a Zip with several tests and the 2 I think are more understandable when they are on their smaller size:
Option 1:
Option2:
And some other options if someone else wants to jump in and try something else. All of them are on the ZIP as SVG too.
I'd go for option 2, but it isn't an strong opinion.
Comment #76
AaronMcHaleIn #71 @webchick mentioned:
That got me thinking... is there a reason the user is limited to inserting only 1 item? The Media Library does technically support inserting as many items as it's configured to, I could totally see a scenario where someone is writing an article and wants to insert a several images, but currently they'd have to open the Media Library, upload or select an item, close the Media Library, and then repeat several more times. A more efficient workflow would be if there wasn't a limit of 1 item and so the user could both upload and select, then insert all the media they needed in essentially one operation.
Re #75: I prefer option 2 over option 1, but I also like the last two icons on the last row of the grid of icons.
Comment #77
oknate#76: I agree, given the functionality here, there's no reason this can't support more than one insertion. Here's a proof of concept. The test coverage has been updated to insert three media items at once.
#75: I like option 2 as well. The two eight notes (musical symbol) is more visually distinct from the image icon and works better when small. I also like option 1, as video is more common than music when it comes to embedding media, but when small it will be harder to see. So I agree with you option 2 is better. I'd like to see the final png icon files. I tried converting these into 16x16 png and 32x32 png to attach properly to a patch, but I ran into two issues:
Here's the png included in #75 for the smaller size. You can see it looks weird in chrome. I think it's 17x17, which is part of the problem. If it were 16x16 chrome wouldn't resize it creating the fuzzy aliasing effect.
#74.3 Changed 'media entity' to 'media item'.
#71: Added the workaround for now for the focus vs. active styling bug. I tried to fix it by adding focus on the active element, but I haven't yet found the proper place to do this. I added test coverage to verify that image shows first.
I don't think it's so bad that they aren't alphabetical, despite what I was saying yesterday. But I do think when we add a config to allow choosing the allowed media types, it should allow setting the order too. Then, we don't need a separate config for the active item, it can always be the first one.
I also created a follow up issue for this: https://www.drupal.org/project/drupal/issues/3073799
Comment #78
Wim LeersAmazing progress here! 🥳
DrupalImage
and stop allowing<img>
, and addDrupalMediaLibrary
, themedia_embed
filter and allow<drupal-media>
MediaLibraryEditorOpener
doesn't do anything CKEditor-specific. Other text editor plugins can reuse this. But Drupal core cannot provide integration with other text editors. That's why the additions tomedia_library
indeed are CKEditor-specific: because it's validating the configuration of the CKEditor integration combined with the filter. That's why specifically this naming was chosen. There's no reason to makeMediaLibraryEditorOpener
CKEditor-specific.DrupalImage
+EditorImageDialog
have worked for years. Finally, it makes it impossible for contrib modules to alterEditorMediaDialog
and turn it into a multi-step form and allow overriding metadata immediately upon insertion. (Or at least makes that much more complex.) In short: too many risks, too many unknowns. Let's not slow this issue down by expanding scope.Comment #79
Wim LeersI also only have nits!
🤓 I see XML metadata. This means this image has not yet been optimized. Please use https://imageoptim.com to do that :) The result is fewer bytes to load for our end users!
👍 These match.
🤔 Perhaps we also want to assert that no other attributes were inserted?
Übernit: two spaces after the question mark.
Übernit: "are" on the second line can be moved to the first line.
Comment #80
ckrinaThat's been fast! Good that we're aligned with the icon :)
Here are the 16&32px transparent PNG versions.
Comment #81
phenaproxima@Wim Leers and I have agreed to revert multi-select from this patch, since it's an interesting feature request but it's totally out of scope. :) I've opened a follow-up for us to move @oknate's PoC code and iterate on it: #3073857: Allow multiple selections from the media library in CKEditor
Comment #82
Wim LeersSince @oknate is on his day job. @phenaproxima and I are pair-programming to address the last few things :)
Like @phenaproxima just wrote, this reverts the multi-insert functionality.
Comment #83
AaronMcHaleRe #78
@Wim Leers Thanks for the feedback, that sounds reasonable, happy to visit this further in a follow-up.
Re #81 Thanks for creating the follow-up @phenaproxima
Comment #84
Wim LeersThis patch:
@phenaproxima and I are now doing a final round of review 🤓
Comment #85
Wim LeersJust noticed #84's interdiff and patch were wrong. Sorry about that.
Comment #86
Wim Leers@phenaproxima and I had one last round of review, and found a few nits to fix. We fixed them all.
As far as we are concerned, this is RTBC 🥳🥳🥳
Nit: s/drupalink/drupallink/. Fixed. ✅
Nit: double blank line. Fixed. ✅
Nit: inconsistent with
::pressEditorButton()
. Fixed.@phenaproxima and I documented this more clearly.
@phenaproxima pointed out these classes should be
@internal
.Should use
@covers
.Comment #87
phenaproximaOpened #3073901: Determine an upgrade path from CKEditor image button to media library in response to @webchick's feedback in #71.1.
Comment #88
phenaproximaOpened #3073903: Media library should show radios instead of checkboxes if only one item can be selected in response to @webchick's feedback in response to #71.3.
Comment #89
phenaproximaI think there is one more thing needed before RTBC -- we need to regenerate the icon files.
Here is what the drupalimage plugin (already in core) icon looks like, close up in PHPStorm:
And here is what the drupalmedialibrary icon looks like, also close up in PHPStorm:
There's a very clear difference we should probably fix before commit. :) We will also need to make sure the
hidpi
versions are in agreement too. Here they are, for reference:Assigning to @ckrina, since she created the icons and is therefore in a position to regenerate them. :)
Comment #90
ckrinaSorry it took me a while: I needed to check the no hdpi icon on a normal screen. I hope it's OK now, I've used Wim's suggestion to optimize the PNG (btw, great tool, thanks!).
Comment #91
ckrinaThanks @phenaproxima for letting me know the small icon had white background. Here's the patch again with the transparent one. Hope this time is OK 🤞
Comment #92
ckrinaAnd here's the SVG source. Bot note that the PNGs have been edited per pixels to optimize them per each resolution.
Comment #93
phenaproximaThanks, @ckrina! This looks great now -- screenshots:
I'm removing the "needs usability review" tag, because this functionality has been demoed to the UX team, and it recently passed WebchickTestCase (for those who don't know, @webchick is the undisputed champion of breaking simple patches).
We have an icon we all agree on; the code looks great and is well-tested; scope is contained and all follow-ups are filed. I don't think there's anything else we need to do now except land this issue.
Comment #94
webchickLooks great, and seems like the parts of my feedback that are part of this issue has been addressed! Yay!
However, I can't commit this because:
10:14:12] ‘/Users/angie.byron/Sites/drupal/core/modules/media_library/js/plugins/drupalmedialibrary/plugin.es6.js’ is being checked.
[10:14:13] ‘/Users/angie.byron/Sites/drupal/core/modules/media_library/js/plugins/drupalmedialibrary/plugin.es6.js’ is not updated.
error Command failed with exit code 1.
[10:14:15] ‘/Users/angie.byron/Sites/drupal/core/modules/media_library/js/plugins/drupalmedialibrary/plugin.es6.js’ is being checked.
[10:14:16] ‘/Users/angie.byron/Sites/drupal/core/modules/media_library/js/plugins/drupalmedialibrary/plugin.es6.js’ is not updated.
error Command failed with exit code 1.
So we need a new patch that updates the corresponding .eg6.js files.
Comment #96
webchickActually nevermind. :) @phenaproxima and @WimLeers taught me how to
yarn build:js
from the /core directory.Committed and pushed to 8.8.x. WAHHOOOOO!1!1!1&^@*# Awesome stuff, folks!!
Comment #97
oknateSean B found a bug in the final patch.
#3075443: Follow-up for #2994699: Cardinality should be 1 for inserting embedded media
When I was doing a POC for allowing multiple insertions at a time, and then we reverted that change, there was a line of code that wasn't reverted. The cardinality should be 1 in the MediaLibraryState, not -1.
This should be a quick fix.
Comment #99
oknateredacted
Comment #101
Wim LeersComment #102
pameeela CreditAttribution: pameeela commentedRemoved release notes tag, this is already tagged for highlights, which I think is correct.
Please comment if I'm wrong and there is any potential for disruption from this that should go in release notes.
Comment #103
Wim LeersYou're correct, I didn't realize
required something to be disruptive. Thanks!Comment #104
idebr CreditAttribution: idebr at iO commentedThere is a discussion in #3099878: Media Library: Default value for data-align attribute should not be center whether the default alignment should be 'center'
Comment #105
Jaykumar95please check my comment here for the patch #91 https://www.drupal.org/project/drupal/issues/3073799#comment-14655505.