backdrop-issues
backdrop-issues copied to clipboard
Multiple image browsers in CKEditor insert image functionality
Description of the bug
When using CKeditor image insert functionality, and when the Text editor settings have the "Image uploading" functionality turned off, multiple instances of the file browser are shown. This was first reported in the Forum. Additionally, the progress bar doesn't stop spinning.
Steps To Reproduce
- Start with a Vanilla install of Backdrop (e.g. Tugboat demo site)
- Visit
/admin/config/content/formats/filtered_html - Turn off
Enable image upload - Go to the content create form
node/add/page - Click the image icon and watch the bug in its full glory (see attached image)
Actual behavior
There are 3 instances of the file browser.
Expected behavior
Only one file browser should be shown
Additional information
- Backdrop CMS version: 1.23.0
- PHP 7.4.30
A couple of additional observations:
- The image browser is attached to the form by an ajax call triggered by Javascript. JS basically "clicks" a form submit button with the name
library_open(line 237 offilter.js). - This causes the server to return a View, which is prepended to the element with class
.editor-image-libraryby_filter_image_library_ajax.inc - This works as expected when the Upload image functionality is enabled
- When it's not, JS clicks the button multiple times, resulting in multiple Views being prepended to the element. Furthermore, if you click the image icon again without refreshing the page, the button is clicked more times every time, and you'll get more Views prepended every time.
I can also confirm that bug. It might have to do with the fact that normally (with upload on) the src input isn't visible but gets activated after toggling. When the upload form isn't enabled, the src input is visible initially. Tricky...
No toggling and the triggers fire right away.
Bingo! The issue is twofold:
-
The theming function for
filter_format_editor_image_form()found infilter.theme.incinserts an empty<div class="editor-image-library">within the form itself. This div is not needed here. In fact,Backdrop.behaviors.editorImageDialoginfilter.jsadds adivwith the same class to the DOM, and then populates it (them) with the result of the image browser View obtained via ajax. So, we end up with two divs and two image browsers, one in the left side of the dialog within form, and another one in the correct location. (NB: the image browser in the left side does not appear when we have "Enable image uploads" because there is javascript code that removes thisdiv(or rather, these two divs) when the dialog is first opened on the "Upload an image" option). -
The main culprit for the multiple (and "multiplying") image browsers on the right side of the dialog is a listener for the
dialog:aftercreatecustom event, thrown by dialog. Because this listener is located within theattachmethod for the behaviorBackdrop.behaviors.editorImageDialog, it gets attached to thewindowelement multiple times, every time there is an ajax call to get the content of the dialog. This causes multiple js "clicking" of the invisible ajax button that loads the View for display every time we open the dialog and select "Select from library", resulting in multiple views being attached.
Moving this dialog:aftercreate event listener outside the attach method is the solution here. I tried using once() to avoid multiple listener attachments, but once() doesn't seem to work when you use it on window.
Taking the listener out of the method is actually done in a couple of other instances in Backdrop JS. For example, in:
- dialog.ajax.js
- file.js
I've tested this and it works well.
An additional clarification: these multiple listener attachments and calls do exist, but go unnoticed, when you have the "Enable image upload" filter option on, because the default item in the "Insert image" dialog is the "Upload an image" item. The multiple calls don't cause any problems to this item when you open the dialog.
PR coming
PR https://github.com/backdrop/backdrop/pull/4260
Brilliant! (Again. :wink:) A quick test in the sandbox and I can confirm it works. Will test more thoroughly ASAP.
I'm wondering if it may be possible to include this fix in 1.23.1? Testing and code review anyone?
Is it possible to have this code-reviewed? It's a nasty bug that affects the UX. @indigoxela, any change you may have the time? 🙏🏽
I also confirmed the bug in a vanilla installation of latest 1.x, and then confirmed that the bug is fixed in the PR sandbox 👍🏼
The code change also seems good to me (removing the additional div from core/modules/filter/filter.theme.inc , and moving the code outside attach within Backdrop.behaviors.editorImageDialog).
I'm not expert in JS, but I'm adding the milestone, and marking RTBC in order to grab the attention of our core committers next time they check the queue. I think that @quicksketch may be more suitable, but other core committers might also be comfortable and proficient with JS.
This implementation looks good to me. We could improve it slightly by checking which dialog got opened. Right now it fires and tries to manipulate the dialog contents regardless of which dialog is opened (for example a link dialog also gets acted upon). However, since none of the selectors match nothing actually happens on these other dialogs. In the interest of keeping changes minimal and solving this immediate problem, I think we can merge this as-is.
https://github.com/backdrop/backdrop/pull/4260 merged into 1.x and 1.23.x. Thanks @argiepiano, @indigoxela, and @klonos!