Examples / Documentation on how to implement a multi value media (image) select embed?

Created on 13 January 2023, almost 2 years ago
Updated 9 August 2023, over 1 year ago

Problem/Motivation

Love this module! Its filling a big hole in the ckeditor5 ecosystem right now, but... I'm stuck on how to use this to build an image gallery.

I found "drupal/media_library_form_element", which gave me some syntax to access the form API...

    $form['images'] = [
      '#type' => 'media_library',
      '#allowed_bundles' => ['image'],
      '#title' => t('Upload your image(s)'),
      '#default_value' => NULL,
      '#description' => t('Upload or select your profile image(s).'),
      '#cardinality' => 8,
    ];

(this code gives me the correct media library browser ...)

... but I don't know how to translate that into something that gets rendered.

Does anyone have any examples they could share?

Thank you!

πŸ’¬ Support request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States alphex Atlanta, GA USA

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡΅πŸ‡±Poland bronismateusz

    Have you solved your problem? I am trying to do the same thing.

  • πŸ‡¨πŸ‡ΏCzech Republic milos.kroulik

    I'm having the same issue. Just as an example, I've tried to create a sample module (https://github.com/miloskroulik/ckeditor5_embedded_content_media). I tend to believe the issue is in the way the render array gets rendered - will investigate later on.

  • πŸ‡¨πŸ‡ΏCzech Republic milos.kroulik

    It looks like this may be a bug, after all.

    When I look at the XHR requests done while embedding the media entity, the last one looks like this.

    But with styled list (provided by the examples module), there are some differences:

    • there is an "update_build_id" command, which is missing when I'm embedding media
    • there is a GET request, which returns rendered HTML

    By debugging the EmbeddedContentDialogForm::ajaxSubmitForm method, I discovered, that update_build_id command is missing, because in \Drupal\Core\Form\FormAjaxResponseBuilder::buildResponse $form['#build_id_old'] is the same as $form['#build_id'] when I'm submitting form related to my media embedded content plugin (see above).

    Of course, this might not be a true issue here...

  • πŸ‡¨πŸ‡ΏCzech Republic milos.kroulik
  • πŸ‡¨πŸ‡ΏCzech Republic milos.kroulik
  • πŸ‡¨πŸ‡ΏCzech Republic milos.kroulik

    Just out of curiosity, I've tried to use a simple number widget instead of media selector, which works fine. So perhaps this should be solved in https://www.drupal.org/project/media_library_form_element β†’ module queue?

  • πŸ‡¨πŸ‡ΏCzech Republic milos.kroulik

    I tried to look into JS code a bit to see why the editor preview is not generating. So far it looks like this.editor.model.change((writer) callback is not executed for the media plugin (it is for other plugins).

  • πŸ‡¨πŸ‡¦Canada klimp MontrΓ©al, QC

    I used a custom Media Library Opener + a custom AJAX command to make the media browser work properly. The EmbeddedContent plugin form:

        // Hidden field to store the media image URL.
        $form['image'] = array(
          '#type' => 'hidden',
          '#value' => $this->configuration["photo"],
        );
    
        // Use the custom opener in order to pass values to the custom ajax command.
        $state = MediaLibraryState::create(
          'my_module.opener.embedded_content_my_plugin',
          ['image' => 'image'],
          'image',
          1,
          [
            'filter_format_id' => 'full_html',
             // Pass form values.
            'values' => [
              'value1' => $this->configuration['value1'],
              'value2' => $this->configuration['value2'],
            ]
          ]
        );
    
        $form['open_button'] = [
          '#type' => 'button',
          '#value' => $this->t('Add media'),
          '#attributes' => [
            'class' => [
              'js-media-library-open-button',
            ],
          ],
          '#media_library_state' => $state,
          '#ajax' => [
            'callback' => [MediaLibraryWidget::class, 'openMediaLibrary'],
            'progress' => [
              'type' => 'throbber',
              'message' => $this->t('Opening media library.'),
            ],
            // The AJAX system automatically moves focus to the first tabbable
            // element of the modal, so we need to disable refocus on the button.
            'disable-refocus' => TRUE,
          ],
          // Allow the media library to be opened even if there are form errors.
          '#limit_validation_errors' => [],
        ];
    

    I used MediaLibraryEditorOpener as an example for the custom Media Library Opener. The important method is getSelectionResponse:

      public function getSelectionResponse(MediaLibraryState $state, array $selected_ids) {
        $imageUrl = NULL;
        if (!empty($selected_ids)) {
          // A helper method returning the thumbnail URl for the image.
          $imageUrl = $this->getImageStyleUrl(
            reset($selected_ids),
            'thumbnail'
          );
        }
    
        $response = new AjaxResponse();
        $response->addCommand(new MyInsertMediaCommand([
          // Pass the form parameters and the image URL further to the command.
          'formValues' => $state->getOpenerParameters()["values"],
          'imageUrl' => $imageUrl,
        ]));
    
        return $response;
      }
    

    The command definition:

    class MyInsertMediaCommand implements CommandInterface {
    
      protected $values;
    
      public function __construct($values) {
        $this->values = $values;
      }
    
      public function render() {
        return [
          'command' => 'myInsertMediaCommand',
          'values' => $this->values,
        ];
      }
    }
    

    The command itself:

      Drupal.AjaxCommands.prototype.myInsertMediaCommand = function (ajax, response, status) {
        // Load CKEditor 5 editor from the body field.
        const element = $("#edit-body-0-value").get(0);
        var editor = Drupal.CKEditor5Instances.get(element.getAttribute('data-ckeditor5-id'));
    
        // The fields defined in the EmbeddedContent plugin form.
        const pluginConfig = {
          value1: response.values.formValues.value1,
          value2: response.values.formValues.value2,
          image: response.values.imageUrl,
        };
    
        const attributes = {
          'data-plugin-config': JSON.stringify(pluginConfig),
          'data-plugin-id': 'myPlugin',
        };
    
        // Run the command which will rebuild the CKEditor5 model (and update the preview).
        editor.execute('embeddedContent', attributes);
      };
    
    })(jQuery, Drupal);
    

    In the twig template you have the {{ image }} variable containing the media URL.

    It is a bit clumsy - no media preview in the form, the pop up dialog get closed immediately after the media is selected. Please beware that the code above is simplified.

Production build 0.71.5 2024