From db7b466c5691f68332b3ade5e50fd4075bb2b5bf Mon Sep 17 00:00:00 2001
From: Alexandre Dias <alex.jm.dias@gmail.com>
Date: Wed, 26 Oct 2022 17:11:54 +0100
Subject: [PATCH 01/19] Add media_library support.

---
 .../src/Form/VideoEmbedFieldForm.php          | 180 ++++++++++++++++++
 .../Plugin/media/Source/VideoEmbedField.php   |  18 +-
 .../media/Source/VideoEmbedFieldInterface.php |  11 ++
 .../video_embed_media.module                  |  17 ++
 4 files changed, 221 insertions(+), 5 deletions(-)
 create mode 100644 modules/video_embed_media/src/Form/VideoEmbedFieldForm.php
 create mode 100644 modules/video_embed_media/src/Plugin/media/Source/VideoEmbedFieldInterface.php
 create mode 100644 modules/video_embed_media/video_embed_media.module

diff --git a/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php b/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php
new file mode 100644
index 0000000..c726e0f
--- /dev/null
+++ b/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php
@@ -0,0 +1,180 @@
+<?php
+
+namespace Drupal\video_embed_media\Form;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\Url;
+use Drupal\media_library\Form\AddFormBase;
+use Drupal\media_library\MediaLibraryUiBuilder;
+use Drupal\media_library\OpenerResolverInterface;
+use Drupal\video_embed_field\ProviderManager;
+use Drupal\video_embed_media\Plugin\media\Source\VideoEmbedFieldInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Creates a form to create media entities from Video Embed fields.
+ */
+class VideoEmbedFieldForm extends AddFormBase {
+
+  /**
+   * The video provider manager.
+   *
+   * @var \Drupal\video_embed_field\ProviderManager
+   */
+  protected $providerManager;
+
+  /**
+   * The renderer.
+   *
+   * @var \Drupal\Core\Render\RendererInterface
+   */
+  protected $renderer;
+
+  /**
+   * Constructs a new OEmbedForm.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\media_library\MediaLibraryUiBuilder $library_ui_builder
+   *   The media library UI builder.
+   * @param \Drupal\video_embed_field\ProviderManager $provider_manager
+   *   The video provider plugin manager.
+   * @param \Drupal\Core\Render\RendererInterface $renderer
+   *   The renderer.
+   * @param \Drupal\media_library\OpenerResolverInterface|null $opener_resolver
+   *   The opener resolver.
+   */
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, MediaLibraryUiBuilder $library_ui_builder, ProviderManager $provider_manager, RendererInterface $renderer, OpenerResolverInterface $opener_resolver = NULL) {
+    parent::__construct($entity_type_manager, $library_ui_builder, $opener_resolver);
+    $this->providerManager = $provider_manager;
+    $this->renderer = $renderer;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('entity_type.manager'),
+      $container->get('media_library.ui_builder'),
+      $container->get('video_embed_field.provider_manager'),
+      $container->get('renderer'),
+      $container->get('media_library.opener_resolver')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId(): string {
+    return $this->getBaseFormId() . '_video_embed';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getMediaType(FormStateInterface $form_state) {
+    if ($this->mediaType) {
+      return $this->mediaType;
+    }
+
+    $media_type = parent::getMediaType($form_state);
+    if (!$media_type->getSource() instanceof VideoEmbedFieldInterface) {
+      throw new \InvalidArgumentException('Can only add media types which use an Video Embed source plugin.');
+    }
+    return $media_type;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function buildInputElement(array $form, FormStateInterface $form_state) {
+    $media_type = $this->getMediaType($form_state);
+    $data_definition = $media_type->getSource()->getSourceFieldDefinition($media_type)
+      ->getItemDefinition();
+
+    // Add a container to group the input elements for styling purposes.
+    $form['container'] = [
+      '#type' => 'container',
+    ];
+
+    $form['container']['video_url'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Add @type URL', [
+        '@type' => $this->getMediaType($form_state)->label(),
+      ]),
+      '#allowed_providers' => $data_definition->getSetting('allowed_providers'),
+      '#theme' => 'input__video',
+      '#required' => TRUE,
+    ];
+
+    $form['container']['submit'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Add'),
+      '#button_type' => 'primary',
+      '#validate' => ['::validateUrl'],
+      '#submit' => ['::addButtonSubmit'],
+      // @todo Move validation in https://www.drupal.org/node/2988215
+      '#ajax' => [
+        'callback' => '::updateFormCallback',
+        'wrapper' => 'media-library-wrapper',
+        // Add a fixed URL to post the form since AJAX forms are automatically
+        // posted to <current> instead of $form['#action'].
+        // @todo Remove when https://www.drupal.org/project/drupal/issues/2504115
+        //   is fixed.
+        'url' => Url::fromRoute('media_library.ui'),
+        'options' => [
+          'query' => $this->getMediaLibraryState($form_state)->all() + [
+              FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
+            ],
+        ],
+      ],
+    ];
+    return $form;
+  }
+
+  /**
+   * Validates the oEmbed URL.
+   *
+   * @param array $form
+   *   The complete form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current form state.
+   */
+  public function validateUrl(array &$form, FormStateInterface $form_state) {
+    $provider = $this->getProvider($form_state->getValue('video_url'));
+    // Display an error if no provider can be loaded for this video.
+    if (!$provider) {
+      $form_state->setErrorByName('video_url', $this->t('Could not find a video provider to handle the given URL.'));
+    }
+  }
+
+  /**
+   * Submit handler for the add button.
+   *
+   * @param array $form
+   *   The form render array.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   */
+  public function addButtonSubmit(array $form, FormStateInterface $form_state) {
+    $this->processInputValues([$form_state->getValue('video_url')], $form, $form_state);
+  }
+
+  /**
+   * Get a provider from some input.
+   *
+   * @param string $input
+   *   The input string.
+   *
+   * @return bool|\Drupal\video_embed_field\ProviderPluginInterface
+   *   A video provider or FALSE on failure.
+   */
+  protected function getProvider(string $input) {
+    return $this->providerManager->loadProviderFromInput($input);
+  }
+
+}
diff --git a/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedField.php b/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedField.php
index 566f0f3..08d71a9 100644
--- a/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedField.php
+++ b/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedField.php
@@ -5,6 +5,7 @@ namespace Drupal\video_embed_media\Plugin\media\Source;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldTypePluginManagerInterface;
 use Drupal\media\MediaInterface;
 use Drupal\media\MediaSourceBase;
@@ -23,7 +24,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  *   default_thumbnail_filename = "video.png"
  * )
  */
-class VideoEmbedField extends MediaSourceBase {
+class VideoEmbedField extends MediaSourceBase implements VideoEmbedFieldInterface {
 
   /**
    * The video provider manager.
@@ -84,7 +85,7 @@ class VideoEmbedField extends MediaSourceBase {
   /**
    * {@inheritdoc}
    */
-  public function defaultConfiguration() {
+  public function defaultConfiguration(): array {
     return [
       'source_field' => 'field_media_video_embed_field',
     ];
@@ -142,7 +143,7 @@ class VideoEmbedField extends MediaSourceBase {
   /**
    * {@inheritdoc}
    */
-  public function getMetadataAttributes() {
+  public function getMetadataAttributes(): array {
     return [
       'id' => $this->t('Video ID.'),
       'source' => $this->t('Video source machine name.'),
@@ -181,7 +182,7 @@ class VideoEmbedField extends MediaSourceBase {
   /**
    * {@inheritdoc}
    */
-  public function getSourceFieldDefinition(MediaTypeInterface $type) {
+  public function getSourceFieldDefinition(MediaTypeInterface $type): ?FieldDefinitionInterface {
     // video_embed_media has not historically had a value in
     // $this->configuration['source_field'], instead just creating
     // field_media_video_embed_field on install and treating that as the source.
@@ -191,9 +192,16 @@ class VideoEmbedField extends MediaSourceBase {
     if ($field) {
       // Be sure that the suggested source field actually exists.
       $fields = $this->entityFieldManager->getFieldDefinitions('media', $type->id());
-      return isset($fields[$field]) ? $fields[$field] : NULL;
+      return $fields[$field] ?? NULL;
     }
     return NULL;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getSourceFieldConstraints(): array {
+    return [];
+  }
+
 }
diff --git a/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedFieldInterface.php b/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedFieldInterface.php
new file mode 100644
index 0000000..b8225a6
--- /dev/null
+++ b/modules/video_embed_media/src/Plugin/media/Source/VideoEmbedFieldInterface.php
@@ -0,0 +1,11 @@
+<?php
+
+namespace Drupal\video_embed_media\Plugin\media\Source;
+
+use Drupal\media\MediaSourceFieldConstraintsInterface;
+
+/**
+ * Defines additional functionality for source plugins that use Video Embed field.
+ */
+interface VideoEmbedFieldInterface extends MediaSourceFieldConstraintsInterface {
+}
diff --git a/modules/video_embed_media/video_embed_media.module b/modules/video_embed_media/video_embed_media.module
new file mode 100644
index 0000000..4142712
--- /dev/null
+++ b/modules/video_embed_media/video_embed_media.module
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Contains hook implementations for the media_library module.
+ */
+
+use Drupal\video_embed_media\Form\VideoEmbedFieldForm;
+
+/**
+* Implements hook_media_source_info_alter().
+*/
+function video_embed_media_media_source_info_alter(array &$sources) {
+  if (empty($sources['video_embed_field']['forms']['media_library_add'])) {
+    $sources['video_embed_field']['forms']['media_library_add'] = VideoEmbedFieldForm::class;
+  }
+}
-- 
GitLab


From bfd6aea359527a33be472d652343019f434c1dfe Mon Sep 17 00:00:00 2001
From: Alexandre Dias <alex.jm.dias@gmail.com>
Date: Thu, 27 Oct 2022 13:06:43 +0100
Subject: [PATCH 02/19] Add missing maxlength.

---
 modules/video_embed_media/src/Form/VideoEmbedFieldForm.php | 1 +
 1 file changed, 1 insertion(+)

diff --git a/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php b/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php
index c726e0f..bb32167 100644
--- a/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php
+++ b/modules/video_embed_media/src/Form/VideoEmbedFieldForm.php
@@ -106,6 +106,7 @@ class VideoEmbedFieldForm extends AddFormBase {
       '#title' => $this->t('Add @type URL', [
         '@type' => $this->getMediaType($form_state)->label(),
       ]),
+      '#maxlength' => $data_definition->getSetting('max_length'),
       '#allowed_providers' => $data_definition->getSetting('allowed_providers'),
       '#theme' => 'input__video',
       '#required' => TRUE,
-- 
GitLab


From 461f9848b049a820a5f0cf6716a95f91f5ffd042 Mon Sep 17 00:00:00 2001
From: Alexandre Dias <alex.jm.dias@gmail.com>
Date: Sun, 30 Oct 2022 16:43:15 +0000
Subject: [PATCH 03/19] Replace TYPE_MARKUP_LANGUAGE with
 TYPE_TRANSFORM_IRREVERSIBLE.

---
 .../src/Plugin/Filter/VideoEmbedWysiwyg.php                    | 2 +-
 modules/video_embed_wysiwyg/video_embed_wysiwyg.module         | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
index f0c50e7..4486bc0 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
@@ -19,7 +19,7 @@ use Drupal\Core\Render\RendererInterface;
  *   title = @Translation("Video Embed WYSIWYG"),
  *   id = "video_embed_wysiwyg",
  *   description = @Translation("Enables the use of video_embed_wysiwyg."),
- *   type = Drupal\filter\Plugin\FilterInterface::TYPE_MARKUP_LANGUAGE
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE
  * )
  */
 class VideoEmbedWysiwyg extends FilterBase implements ContainerFactoryPluginInterface {
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
index bd05974..586d49b 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
@@ -34,6 +34,7 @@ function video_embed_wysiwyg_toolbar_filter_validate($form, FormStateInterface $
   $button_enabled = FALSE;
   $key = ['editor', 'settings', 'toolbar', 'button_groups'];
   $button_rows = $form_state->hasValue($key) ? json_decode($form_state->getValue($key), TRUE) : [];
+
   if (!empty($button_rows)) {
     foreach ($button_rows as $button_row) {
       foreach ($button_row as $button_group) {
@@ -47,7 +48,7 @@ function video_embed_wysiwyg_toolbar_filter_validate($form, FormStateInterface $
     }
   }
   // The button and filter can either both be enabled or disabled.
-  if ($filter_enabled !== $button_enabled) {
+  if ($filter_enabled !== $button_enabled && $form_state->getValue('editor')['editor'] === 'ckeditor') {
     $form_state->setError($form['filters']['status']['video_embed_wysiwyg'], t('To embed videos, make sure you have enabled the "Video Embed WYSIWYG" filter and dragged the video icon into the WYSIWYG toolbar. For more information <a href="@url">read the documentation</a>.', ['@url' => VIDEO_EMBED_WYSIWYG_DOCUMENTATION_URL]));
   }
 }
-- 
GitLab


From 35a77a281339364c6b4cf33d515fca19f5d243ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Tue, 14 Feb 2023 17:37:45 +0100
Subject: [PATCH 04/19] WIP, see @todo for lasting work

---
 modules/video_embed_wysiwyg/.gitignore        |    1 +
 .../css/video_embed.admin.css                 |    4 +
 modules/video_embed_wysiwyg/icons/film.svg    |    1 +
 .../icons/play-circle (copie).svg             |    1 +
 .../video_embed_wysiwyg/icons/play-circle.svg |    1 +
 modules/video_embed_wysiwyg/icons/play.svg    |    1 +
 modules/video_embed_wysiwyg/icons/video.svg   |    1 +
 .../video_embed_wysiwyg/js/build/README.txt   |    1 +
 .../ckeditor5_plugins/videoEmbed/src/index.js |    5 +
 .../videoEmbed/src/insertvideoembedcommand.js |   47 +
 .../videoEmbed/src/videoembed.js              |   10 +
 .../videoEmbed/src/videoembedediting.js       |  102 +
 .../videoEmbed/src/videoembedui.js            |   38 +
 modules/video_embed_wysiwyg/package.json      |   19 +
 .../CKEditor5Plugin/VideoEmbedWysiwyg.php     |   37 +
 .../video_embed_wysiwyg.ckeditor5.yml         |   17 +
 .../video_embed_wysiwyg.info.yml              |    2 +-
 .../video_embed_wysiwyg.libraries.yml         |   12 +
 .../video_embed_wysiwyg.module                |    3 +
 modules/video_embed_wysiwyg/webpack.config.js |   66 +
 modules/video_embed_wysiwyg/yarn.lock         | 2589 +++++++++++++++++
 21 files changed, 2957 insertions(+), 1 deletion(-)
 create mode 100644 modules/video_embed_wysiwyg/.gitignore
 create mode 100644 modules/video_embed_wysiwyg/css/video_embed.admin.css
 create mode 100644 modules/video_embed_wysiwyg/icons/film.svg
 create mode 100644 modules/video_embed_wysiwyg/icons/play-circle (copie).svg
 create mode 100644 modules/video_embed_wysiwyg/icons/play-circle.svg
 create mode 100644 modules/video_embed_wysiwyg/icons/play.svg
 create mode 100644 modules/video_embed_wysiwyg/icons/video.svg
 create mode 100644 modules/video_embed_wysiwyg/js/build/README.txt
 create mode 100644 modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
 create mode 100644 modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
 create mode 100644 modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembed.js
 create mode 100644 modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
 create mode 100644 modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
 create mode 100644 modules/video_embed_wysiwyg/package.json
 create mode 100644 modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
 create mode 100644 modules/video_embed_wysiwyg/video_embed_wysiwyg.ckeditor5.yml
 create mode 100644 modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml
 create mode 100644 modules/video_embed_wysiwyg/webpack.config.js
 create mode 100644 modules/video_embed_wysiwyg/yarn.lock

diff --git a/modules/video_embed_wysiwyg/.gitignore b/modules/video_embed_wysiwyg/.gitignore
new file mode 100644
index 0000000..b512c09
--- /dev/null
+++ b/modules/video_embed_wysiwyg/.gitignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/css/video_embed.admin.css b/modules/video_embed_wysiwyg/css/video_embed.admin.css
new file mode 100644
index 0000000..7ef5780
--- /dev/null
+++ b/modules/video_embed_wysiwyg/css/video_embed.admin.css
@@ -0,0 +1,4 @@
+.ckeditor5-toolbar-button-videoEmbed {
+  /* @todo Choose the best icon and remove others. */
+  background-image: url(../icons/film.svg);
+}
diff --git a/modules/video_embed_wysiwyg/icons/film.svg b/modules/video_embed_wysiwyg/icons/film.svg
new file mode 100644
index 0000000..ccf8983
--- /dev/null
+++ b/modules/video_embed_wysiwyg/icons/film.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M488 64h-8v20c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12V64H96v20c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12V64h-8C10.7 64 0 74.7 0 88v336c0 13.3 10.7 24 24 24h8v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h320v-20c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v20h8c13.3 0 24-10.7 24-24V88c0-13.3-10.7-24-24-24zM96 372c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12H44c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm272 208c0 6.6-5.4 12-12 12H156c-6.6 0-12-5.4-12-12v-96c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v96zm0-168c0 6.6-5.4 12-12 12H156c-6.6 0-12-5.4-12-12v-96c0-6.6 5.4-12 12-12h200c6.6 0 12 5.4 12 12v96zm112 152c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40zm0-96c0 6.6-5.4 12-12 12h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/icons/play-circle (copie).svg b/modules/video_embed_wysiwyg/icons/play-circle (copie).svg
new file mode 100644
index 0000000..778c5fa
--- /dev/null
+++ b/modules/video_embed_wysiwyg/icons/play-circle (copie).svg	
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/icons/play-circle.svg b/modules/video_embed_wysiwyg/icons/play-circle.svg
new file mode 100644
index 0000000..0ce0085
--- /dev/null
+++ b/modules/video_embed_wysiwyg/icons/play-circle.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/icons/play.svg b/modules/video_embed_wysiwyg/icons/play.svg
new file mode 100644
index 0000000..e817cc8
--- /dev/null
+++ b/modules/video_embed_wysiwyg/icons/play.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/icons/video.svg b/modules/video_embed_wysiwyg/icons/video.svg
new file mode 100644
index 0000000..92f4988
--- /dev/null
+++ b/modules/video_embed_wysiwyg/icons/video.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M336.2 64H47.8C21.4 64 0 85.4 0 111.8v288.4C0 426.6 21.4 448 47.8 448h288.4c26.4 0 47.8-21.4 47.8-47.8V111.8c0-26.4-21.4-47.8-47.8-47.8zm189.4 37.7L416 177.3v157.4l109.6 75.5c21.2 14.6 50.4-.3 50.4-25.8V127.5c0-25.4-29.1-40.4-50.4-25.8z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/build/README.txt b/modules/video_embed_wysiwyg/js/build/README.txt
new file mode 100644
index 0000000..c21c74d
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/build/README.txt
@@ -0,0 +1 @@
+This is the default destination folder for CKEditor 5 plugin builds.
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
new file mode 100644
index 0000000..6fcd277
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
@@ -0,0 +1,5 @@
+import VideoEmbed from './videoembed';
+
+export default {
+  VideoEmbed,
+};
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
new file mode 100644
index 0000000..97ad84a
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
@@ -0,0 +1,47 @@
+/**
+ * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed
+ * toolbar button is pressed.
+ */
+
+import { Command } from 'ckeditor5/src/core';
+
+export default class InsertVideoEmbedCommand extends Command {
+  execute() {
+    const { model } = this.editor;
+
+    model.change((writer) => {
+      // Insert <videoEmbed * /> at the current selection position
+      // in a way that will result in creating a valid model structure.
+      model.insertContent(createVideoEmbed(writer));
+    });
+  }
+
+  refresh() {
+    const { model } = this.editor;
+    const { selection } = model.document;
+
+    // Determine if the cursor (selection) is in a position where adding a
+    // videoEmbed is permitted. This is based on the schema of the model(s)
+    // currently containing the cursor.
+    const allowedIn = model.schema.findAllowedParent(
+        selection.getFirstPosition(),
+        'videoEmbed',
+    );
+
+    // If the cursor is not in a location where a videoEmbed can be added,
+    // return null so the addition doesn't happen.
+    this.isEnabled = allowedIn !== null;
+  }
+}
+
+function createVideoEmbed(writer) {
+  // Create instances of the element registered with the editor in
+  // videoembedediting.js.
+  const videoEmbed = writer.createElement('videoEmbed');
+
+  // @todo
+
+  // Return the element to be added to the editor.
+  return videoEmbed;
+}
+
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembed.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembed.js
new file mode 100644
index 0000000..c6f5bff
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembed.js
@@ -0,0 +1,10 @@
+import VideoEmbedEditing from './videoembedediting';
+import VideoEmbedUI from './videoembedui';
+import { Plugin } from 'ckeditor5/src/core';
+
+export default class VideoEmbed extends Plugin {
+
+static get requires() {
+    return [VideoEmbedEditing, VideoEmbedUI];
+  }
+}
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
new file mode 100644
index 0000000..3153259
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -0,0 +1,102 @@
+import { Plugin } from 'ckeditor5/src/core';
+import { toWidget, toWidgetEditable } from 'ckeditor5/src/widget';
+import { Widget } from 'ckeditor5/src/widget';
+import InsertVideoEmbedCommand from './insertvideoembedcommand';
+
+
+/**
+ * CKEditor 5 plugins do not work directly with the DOM. They are defined as
+ * plugin-specific data models that are then converted to markup that
+ * is inserted in the DOM.
+ *
+ * CKEditor 5 internally interacts with videoEmbed as this model:
+ * @todo List attributes in this doc.
+ * <videoEmbed />
+ *
+ * Which is converted in database (dataDowncast) as this markup:
+ * <p>{"video_url":"https://some.video.url","settings":{"responsive":0or1,"width":"42","height":"42","autoplay":0or1}}</p>
+ *
+ * The Drupal video_embed_wysiwyg format filter will then convert this into a
+ * real HTML video embed, on PHP frontend rendering.
+ *
+ * videoEmbed model elements are also converted to HTML for preview in CKE5 UI
+ * (editingDowncast).
+ *
+ * And the database markup can be converted back to model (upcast).
+ *
+ * This file has the logic for defining the videoEmbed model, and for how it is
+ * converted from/to standard DOM markup for database/UI.
+ */
+export default class VideoEmbedEditing extends Plugin {
+  static get requires() {
+    return [Widget];
+  }
+
+  init() {
+    this._defineSchema();
+    this._defineConverters();
+    this.editor.commands.add(
+        'insertVideoEmbed',
+        new InsertVideoEmbedCommand(this.editor),
+    );
+  }
+
+  /*
+   * This registers the structure that will be seen by CKEditor 5 as
+   * <videoEmbed .../>
+   *
+   * The logic in _defineConverters() will determine how this is converted to
+   * markup.
+   */
+  _defineSchema() {
+    // Schemas are registered via the central `editor` object.
+    const schema = this.editor.model.schema;
+
+
+    // @todo register allowed model attributes.
+    schema.register('videoEmbed', {
+      // Behaves like a self-contained object (e.g. an image).
+      isObject: true,
+      // Allow in places where other blocks are allowed (e.g. directly in the root).
+      allowWhere: '$block',
+    });
+  }
+
+  /**
+   * Converters determine how CKEditor 5 models are converted into markup and
+   * vice-versa.
+   */
+  _defineConverters() {
+    // Converters are registered via the central editor object.
+    const { conversion } = this.editor;
+
+    // Upcast Converters: determine how existing HTML is interpreted by the
+    // editor. These trigger when an editor instance loads.
+    //
+    // If {"video_url":...} is present in the existing markup
+    // processed by CKEditor, then CKEditor recognizes and loads it as a
+    // <videoEmbed> model.
+    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
+    //conversion.for('upcast').[...]
+
+
+    // Data Downcast Converters: converts stored model data into HTML.
+    // These trigger when content is saved.
+    //
+    // Instances of <videoEmbed> are saved as
+    // <p>{{"video_url":...}</p>.
+    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
+    //conversion.for('dataDowncast').[...]
+
+
+    // Editing Downcast Converters. These render the content to the user for
+    // editing, i.e. this determines what gets seen in the editor. These trigger
+    // after the Data Upcast Converters, and are re-triggered any time there
+    // are changes to any of the models' properties.
+    //
+    // Convert the <videoEmbed> model into a container widget in the editor UI.
+    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
+    //conversion.for('editingDowncast').[...]
+  }
+}
+
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
new file mode 100644
index 0000000..94ba981
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
@@ -0,0 +1,38 @@
+/**
+ * @file registers the videoEmbed toolbar button and binds functionality to it.
+ */
+
+import { Plugin } from 'ckeditor5/src/core';
+import { ButtonView } from 'ckeditor5/src/ui';
+/* @todo Choose the best icon and remove others. */
+import icon from '../../../../icons/film.svg';
+
+export default class VideoEmbedUI extends Plugin {
+  init() {
+    const editor = this.editor;
+
+    // This will register the videoEmbed toolbar button.
+    editor.ui.componentFactory.add('videoEmbed', (locale) => {
+      const command = editor.commands.get('insertVideoEmbed');
+      const buttonView = new ButtonView(locale);
+
+      // Create the toolbar button.
+      buttonView.set({
+        label: editor.t('Video Embed'),
+        icon,
+        tooltip: true,
+      });
+
+      // Bind the state of the button to the command.
+      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
+
+      // Execute the command when the button is clicked (executed).
+      this.listenTo(buttonView, 'execute', () =>
+          editor.execute('insertVideoEmbed'),
+      );
+
+      return buttonView;
+    });
+  }
+}
+
diff --git a/modules/video_embed_wysiwyg/package.json b/modules/video_embed_wysiwyg/package.json
new file mode 100644
index 0000000..529a8ff
--- /dev/null
+++ b/modules/video_embed_wysiwyg/package.json
@@ -0,0 +1,19 @@
+{
+  "name": "drupal-ckeditor5",
+  "version": "1.0.0",
+  "description": "Drupal CKEditor 5 integration",
+  "author": "",
+  "license": "GPL-2.0-or-later",
+  "scripts": {
+    "watch": "webpack --mode development --watch",
+    "build": "webpack"
+  },
+  "devDependencies": {
+    "@ckeditor/ckeditor5-dev-utils": "^30.0.0",
+    "ckeditor5": "~34.1.0",
+    "raw-loader": "^4.0.2",
+    "terser-webpack-plugin": "^5.2.0",
+    "webpack": "^5.51.1",
+    "webpack-cli": "^4.4.0"
+  }
+}
diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
new file mode 100644
index 0000000..dd57409
--- /dev/null
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\video_embed_wysiwyg\Plugin\CKEditor5Plugin;
+
+use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableTrait;
+use Drupal\ckeditor5\Plugin\CKEditor5PluginDefault;
+use Drupal\editor\EditorInterface;
+
+/**
+ * This class transmits the Drupal config to the javascript plugin.
+ */
+class VideoEmbedWysiwyg extends CKEditor5PluginDefault {
+
+  use CKEditor5PluginConfigurableTrait;
+
+  /**
+   * @param mixed[] $static_plugin_config
+   * @param \Drupal\editor\EditorInterface $editor
+   *
+   * @return mixed[]
+   */
+  public function getDynamicPluginConfig(array $static_plugin_config, EditorInterface $editor): array {
+    $format = $editor->getFilterFormat();
+    /** @var \Drupal\filter\Plugin\FilterInterface $filter */
+    $filter = $format->filters('video_embed_wysiwyg');
+    $filter_config = $filter->getConfiguration();
+    $parent_config = parent::getDynamicPluginConfig($static_plugin_config, $editor);
+    // @todo Ensure this is the info the plugin needs.
+    return array_merge_recursive($parent_config,
+      [
+        'VideoEmbed' => $filter_config['settings']
+      ]);
+  }
+
+}
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.ckeditor5.yml b/modules/video_embed_wysiwyg/video_embed_wysiwyg.ckeditor5.yml
new file mode 100644
index 0000000..6f75201
--- /dev/null
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.ckeditor5.yml
@@ -0,0 +1,17 @@
+video_embed_wysiwyg_video_embed:
+  provider: video_embed_wysiwyg
+  ckeditor5:
+    plugins:
+      - videoEmbed.VideoEmbed
+  drupal:
+    label: Video Embed WYSIWYG
+    library: video_embed_wysiwyg/video_embed
+    admin_library: video_embed_wysiwyg/admin.video_embed
+    toolbar_items:
+      videoEmbed:
+        label: Video embed
+    elements:
+      - <p>
+    conditions:
+      filter: video_embed_wysiwyg
+    class: Drupal\video_embed_wysiwyg\Plugin\CKEditor5Plugin\VideoEmbedWysiwyg
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml b/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml
index 40b8f94..c2a6ac5 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml
@@ -5,5 +5,5 @@ package: Video Embed Field
 core_version_requirement: ^9.2 || ^10
 dependencies:
   - drupal:field
-  - drupal:ckeditor
+  - drupal:editor
   - video_embed_field:video_embed_field
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml b/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml
new file mode 100644
index 0000000..0b134bf
--- /dev/null
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml
@@ -0,0 +1,12 @@
+video_embed:
+  js:
+    js/build/videoEmbed.js: { preprocess: false, minified: true }
+  dependencies:
+    - core/ckeditor5
+
+# Loaded in the text format configuration form to provide styling for the icon
+# used in toolbar config.
+admin.video_embed:
+  css:
+    theme:
+      css/video_embed.admin.css: { }
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
index 586d49b..223cc9a 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
@@ -3,6 +3,9 @@
 /**
  * @file
  * Module file for video_embed_wysiwyg.
+ * @todo test and fix CKE5 plugin.
+ * @todo CKE5 upgrade path if needed.
+ * @todo Add a comment on code that runs only for CKE4.
  */
 
 use Drupal\editor\Entity\Editor;
diff --git a/modules/video_embed_wysiwyg/webpack.config.js b/modules/video_embed_wysiwyg/webpack.config.js
new file mode 100644
index 0000000..a10c7c2
--- /dev/null
+++ b/modules/video_embed_wysiwyg/webpack.config.js
@@ -0,0 +1,66 @@
+const path = require('path');
+const fs = require('fs');
+const webpack = require('webpack');
+const { styles, builds } = require('@ckeditor/ckeditor5-dev-utils');
+const TerserPlugin = require('terser-webpack-plugin');
+
+function getDirectories(srcpath) {
+  return fs
+    .readdirSync(srcpath)
+    .filter((item) => fs.statSync(path.join(srcpath, item)).isDirectory());
+}
+
+module.exports = [];
+// Loop through every subdirectory in src, each a different plugin, and build
+// each one in ./build.
+getDirectories('./js/ckeditor5_plugins').forEach((dir) => {
+  const bc = {
+    mode: 'production',
+    optimization: {
+      minimize: true,
+      minimizer: [
+        new TerserPlugin({
+          terserOptions: {
+            format: {
+              comments: false,
+            },
+          },
+          test: /\.js(\?.*)?$/i,
+          extractComments: false,
+        }),
+      ],
+      moduleIds: 'named',
+    },
+    entry: {
+      path: path.resolve(
+        __dirname,
+        'js/ckeditor5_plugins',
+        dir,
+        'src/index.js',
+      ),
+    },
+    output: {
+      path: path.resolve(__dirname, './js/build'),
+      filename: `${dir}.js`,
+      library: ['CKEditor5', dir],
+      libraryTarget: 'umd',
+      libraryExport: 'default',
+    },
+    plugins: [
+      // It is possible to require the ckeditor5-dll.manifest.json used in
+      // core/node_modules rather than having to install CKEditor 5 here.
+      // However, that requires knowing the location of that file relative to
+      // where your module code is located.
+      new webpack.DllReferencePlugin({
+        manifest: require('./node_modules/ckeditor5/build/ckeditor5-dll.manifest.json'), // eslint-disable-line global-require, import/no-unresolved
+        scope: 'ckeditor5/src',
+        name: 'CKEditor5.dll',
+      }),
+    ],
+    module: {
+      rules: [{ test: /\.svg$/, use: 'raw-loader' }],
+    },
+  };
+
+  module.exports.push(bc);
+});
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/yarn.lock b/modules/video_embed_wysiwyg/yarn.lock
new file mode 100644
index 0000000..569df04
--- /dev/null
+++ b/modules/video_embed_wysiwyg/yarn.lock
@@ -0,0 +1,2589 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
+  integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
+  dependencies:
+    "@babel/highlight" "^7.18.6"
+
+"@babel/generator@^7.20.1":
+  version "7.20.1"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.1.tgz#ef32ecd426222624cbd94871a7024639cf61a9fa"
+  integrity sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==
+  dependencies:
+    "@babel/types" "^7.20.0"
+    "@jridgewell/gen-mapping" "^0.3.2"
+    jsesc "^2.5.1"
+
+"@babel/helper-environment-visitor@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
+  integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
+
+"@babel/helper-function-name@^7.19.0":
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
+  integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
+  dependencies:
+    "@babel/template" "^7.18.10"
+    "@babel/types" "^7.19.0"
+
+"@babel/helper-hoist-variables@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
+  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-split-export-declaration@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
+  integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-string-parser@^7.19.4":
+  version "7.19.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
+  integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
+
+"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
+  version "7.19.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
+  integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
+
+"@babel/highlight@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
+  integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.18.6"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.18.10", "@babel/parser@^7.18.9", "@babel/parser@^7.20.1":
+  version "7.20.1"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.1.tgz#3e045a92f7b4623cafc2425eddcb8cf2e54f9cc5"
+  integrity sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==
+
+"@babel/template@^7.18.10":
+  version "7.18.10"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
+  integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==
+  dependencies:
+    "@babel/code-frame" "^7.18.6"
+    "@babel/parser" "^7.18.10"
+    "@babel/types" "^7.18.10"
+
+"@babel/traverse@^7.18.9":
+  version "7.20.1"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
+  integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
+  dependencies:
+    "@babel/code-frame" "^7.18.6"
+    "@babel/generator" "^7.20.1"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-function-name" "^7.19.0"
+    "@babel/helper-hoist-variables" "^7.18.6"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/parser" "^7.20.1"
+    "@babel/types" "^7.20.0"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
+"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0":
+  version "7.20.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.0.tgz#52c94cf8a7e24e89d2a194c25c35b17a64871479"
+  integrity sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==
+  dependencies:
+    "@babel/helper-string-parser" "^7.19.4"
+    "@babel/helper-validator-identifier" "^7.19.1"
+    to-fast-properties "^2.0.0"
+
+"@ckeditor/ckeditor5-clipboard@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-35.4.0.tgz#8529fd45d06a7edea0f73cd0b5b3052f2272335c"
+  integrity sha512-B6rIQxvOrHvO9TZRC8JA0wKk+IfN880UJkYIg1qlhf9HFNVjdVbtHaiCsPD+TzGmQN3XHXfNjgjabGRIn0iZmw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    "@ckeditor/ckeditor5-widget" "^35.4.0"
+    lodash-es "^4.17.11"
+
+"@ckeditor/ckeditor5-core@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-35.4.0.tgz#39390445c8363a80d4ce0e45d93efa13b8523f6e"
+  integrity sha512-Rf0H7C4inCj/YC8aii0cT7TC/IuBIQ+tXmu9qd8/1BJ/rz1MCHXtBPApjTbFp33OE3aOFB5+NUaKt05k/dL3OA==
+  dependencies:
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    lodash-es "^4.17.15"
+
+"@ckeditor/ckeditor5-dev-utils@^30.0.0", "@ckeditor/ckeditor5-dev-utils@^30.5.0":
+  version "30.5.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-utils/-/ckeditor5-dev-utils-30.5.0.tgz#798291a79183db716b667591a2ccebe6fcb7a7f8"
+  integrity sha512-R5oC9ka68X7NwafM5rFvIv6q0qT2kMsBkRikdEygx7cmGkV4dy7uM5HuOBUuIoLW7Md2o3QfkD3dnk6OdzuuJw==
+  dependencies:
+    "@babel/parser" "^7.18.9"
+    "@babel/traverse" "^7.18.9"
+    "@ckeditor/ckeditor5-dev-webpack-plugin" "^30.5.0"
+    chalk "^3.0.0"
+    cli-cursor "^3.1.0"
+    cli-spinners "^2.6.1"
+    cssnano "^5.0.0"
+    del "^5.0.0"
+    escodegen "^1.9.0"
+    fs-extra "^8.1.0"
+    is-interactive "^1.0.0"
+    javascript-stringify "^1.6.0"
+    pofile "^1.0.9"
+    postcss "^8.4.12"
+    postcss-import "^14.1.0"
+    postcss-loader "^4.3.0"
+    postcss-mixins "^9.0.2"
+    postcss-nesting "^10.1.4"
+    raw-loader "^4.0.1"
+    shelljs "^0.8.1"
+    style-loader "^2.0.0"
+    terser-webpack-plugin "^4.2.3"
+    through2 "^3.0.1"
+    ts-loader "^9.3.0"
+
+"@ckeditor/ckeditor5-dev-webpack-plugin@^30.5.0":
+  version "30.5.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-dev-webpack-plugin/-/ckeditor5-dev-webpack-plugin-30.5.0.tgz#732033e117ce0b00cb0efaf009495ab767ec47de"
+  integrity sha512-mErNKfGd8XBjJxB7K7yCDnNq4pLQKbEjwJHf9g2EW4gOD1U55rgPc1XpmgfxhMj44QQ8YOZXAQ/Y/55AN7GATA==
+  dependencies:
+    "@ckeditor/ckeditor5-dev-utils" "^30.5.0"
+    chalk "^4.0.0"
+    rimraf "^3.0.2"
+    semver "^7.3.4"
+    webpack-sources "^2.0.1"
+
+"@ckeditor/ckeditor5-engine@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-35.4.0.tgz#cb0ed9f0c5a9ef00b24ffbd8d2100fff1e0e90cb"
+  integrity sha512-67QKtUGJeLM072h9qURvzczYGU3ecuxR9LLmM4dffnV+PBNQ9e8RDCY7PuuEP0pplmAUI6/XqoZJIbk6h7ZV3Q==
+  dependencies:
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    lodash-es "^4.17.15"
+
+"@ckeditor/ckeditor5-enter@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-35.4.0.tgz#c0f967dc3f48faeb07d839ac0426227e118ade56"
+  integrity sha512-y95RnA/Gw72e220PJKVwNbwPzX4SRs82/rXu1jVyJXty7CcEZqqfyRtW6odICAXr5eKI5XKgzFgpFYULL3D9Nw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+
+"@ckeditor/ckeditor5-paragraph@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-35.4.0.tgz#db6babd19eb37c66771b7355d0cd0880cb9b599c"
+  integrity sha512-8nhkEEFv1WClhH6q/HW8P596d+dlatSVc46kQ2+jGlYirL8P66tV/nK+OiE8z1d897oVr4QPGsqk2qGkRFUChw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+
+"@ckeditor/ckeditor5-select-all@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-35.4.0.tgz#b7c20e9f686e59497e84825c4786dd874e22d4e2"
+  integrity sha512-c+pIIY77SP6ux4/cyD7cCrllQAqtFVSnzNYdy7ygNPqljCGngCnpSV9xfCO/blFo6/zx2vsmzVGdRq3ArzGoMg==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+
+"@ckeditor/ckeditor5-typing@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-35.4.0.tgz#b786032a541cfd102562eb07c21c62e0b6d502c6"
+  integrity sha512-Ad/PHWbVWcnAj9oevkkfLqf6CmvCFOti466uhvfOCKRNVf2+/xuGwleOGr8W6Lir/x/qav7ojFjKPKDxqbPXhA==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    lodash-es "^4.17.15"
+
+"@ckeditor/ckeditor5-ui@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-35.4.0.tgz#76e59032aee6652c6bd717f30fc330a064b3451e"
+  integrity sha512-0SmYE+k1cYQPqyw2rQsPDV/RpudneBh1bNfiaTOz+rqViJIMe+TxiuK6Fz+znNZ05s0exr+ZHWvMttGqlVoQNw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    lodash-es "^4.17.15"
+
+"@ckeditor/ckeditor5-undo@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-35.4.0.tgz#f79b19be69b8b9ab57592cfe4ec4645b3728b773"
+  integrity sha512-0RhsK0f/pX/7KB/JXYTLiDOswmUTQ9EKIIuewAwr7LTsBf4Q309FZSFdbeTmc0wIyX33212Xh5xsi3LyG1VJRg==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+
+"@ckeditor/ckeditor5-upload@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-35.4.0.tgz#57944a4e824cdee37bb53d795dbe98055e11d748"
+  integrity sha512-+eJAluAc4mAFmx5FNuSGjkCYmbm0V9NpSleubAXEx2e+KNiLarPAnsolwRaAcYXcloNp4C9/l0D+lPEx7VRYtg==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+
+"@ckeditor/ckeditor5-utils@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-35.4.0.tgz#c5c296a2c1883684e674b1a710fcc41b745e156b"
+  integrity sha512-sFjbb+1VYdLbELDLWVYk86WzVN7Lo3sXHbVhdr8+kc0Ufxdr3mTFHDAkiymFt2fs1FOB5gZyWJlJU+EeJnhKUw==
+  dependencies:
+    lodash-es "^4.17.15"
+
+"@ckeditor/ckeditor5-widget@^35.4.0":
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-35.4.0.tgz#a80ed4c4f57a1198b47c4e93090f8ebe62f70ecb"
+  integrity sha512-SNYOXXWu7XV1BZET+ar0Cea25836vzNtUqXlDPwBx/jrmK86b8GMbFR99P2bUG0NvtIsH5cSk7XCmnxb4ZQ6wA==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+    "@ckeditor/ckeditor5-enter" "^35.4.0"
+    "@ckeditor/ckeditor5-typing" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    lodash-es "^4.17.15"
+
+"@csstools/selector-specificity@^2.0.0":
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36"
+  integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
+
+"@discoveryjs/json-ext@^0.5.0":
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
+  integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
+
+"@gar/promisify@^1.0.1":
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
+  integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
+
+"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
+  integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
+  dependencies:
+    "@jridgewell/set-array" "^1.0.1"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@3.1.0":
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
+  integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
+
+"@jridgewell/set-array@^1.0.1":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+  integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/source-map@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
+  integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
+  dependencies:
+    "@jridgewell/gen-mapping" "^0.3.0"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10":
+  version "1.4.14"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
+  integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
+
+"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9":
+  version "0.3.17"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
+  integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==
+  dependencies:
+    "@jridgewell/resolve-uri" "3.1.0"
+    "@jridgewell/sourcemap-codec" "1.4.14"
+
+"@nodelib/fs.scandir@2.1.5":
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+  dependencies:
+    "@nodelib/fs.stat" "2.0.5"
+    run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+  dependencies:
+    "@nodelib/fs.scandir" "2.1.5"
+    fastq "^1.6.0"
+
+"@npmcli/fs@^1.0.0":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257"
+  integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==
+  dependencies:
+    "@gar/promisify" "^1.0.1"
+    semver "^7.3.5"
+
+"@npmcli/move-file@^1.0.1":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674"
+  integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==
+  dependencies:
+    mkdirp "^1.0.4"
+    rimraf "^3.0.2"
+
+"@trysound/sax@0.2.0":
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
+  integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
+
+"@types/eslint-scope@^3.7.3":
+  version "3.7.4"
+  resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16"
+  integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==
+  dependencies:
+    "@types/eslint" "*"
+    "@types/estree" "*"
+
+"@types/eslint@*":
+  version "8.4.9"
+  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.9.tgz#f7371980148697f4b582b086630319b55324b5aa"
+  integrity sha512-jFCSo4wJzlHQLCpceUhUnXdrPuCNOjGFMQ8Eg6JXxlz3QaCKOb7eGi2cephQdM4XTYsNej69P9JDJ1zqNIbncQ==
+  dependencies:
+    "@types/estree" "*"
+    "@types/json-schema" "*"
+
+"@types/estree@*":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
+  integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
+
+"@types/estree@^0.0.51":
+  version "0.0.51"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
+  integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
+
+"@types/glob@^7.1.1":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
+  integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
+  dependencies:
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/json-schema@*", "@types/json-schema@^7.0.8":
+  version "7.0.11"
+  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
+  integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
+
+"@types/minimatch@*":
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
+  integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
+
+"@types/node@*":
+  version "18.11.9"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
+  integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
+
+"@types/parse-json@^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+
+"@webassemblyjs/ast@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
+  integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==
+  dependencies:
+    "@webassemblyjs/helper-numbers" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f"
+  integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==
+
+"@webassemblyjs/helper-api-error@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16"
+  integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==
+
+"@webassemblyjs/helper-buffer@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5"
+  integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==
+
+"@webassemblyjs/helper-numbers@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae"
+  integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==
+  dependencies:
+    "@webassemblyjs/floating-point-hex-parser" "1.11.1"
+    "@webassemblyjs/helper-api-error" "1.11.1"
+    "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1"
+  integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==
+
+"@webassemblyjs/helper-wasm-section@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a"
+  integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-buffer" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/wasm-gen" "1.11.1"
+
+"@webassemblyjs/ieee754@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614"
+  integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==
+  dependencies:
+    "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5"
+  integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==
+  dependencies:
+    "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff"
+  integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==
+
+"@webassemblyjs/wasm-edit@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6"
+  integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-buffer" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/helper-wasm-section" "1.11.1"
+    "@webassemblyjs/wasm-gen" "1.11.1"
+    "@webassemblyjs/wasm-opt" "1.11.1"
+    "@webassemblyjs/wasm-parser" "1.11.1"
+    "@webassemblyjs/wast-printer" "1.11.1"
+
+"@webassemblyjs/wasm-gen@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76"
+  integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/ieee754" "1.11.1"
+    "@webassemblyjs/leb128" "1.11.1"
+    "@webassemblyjs/utf8" "1.11.1"
+
+"@webassemblyjs/wasm-opt@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2"
+  integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-buffer" "1.11.1"
+    "@webassemblyjs/wasm-gen" "1.11.1"
+    "@webassemblyjs/wasm-parser" "1.11.1"
+
+"@webassemblyjs/wasm-parser@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199"
+  integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/helper-api-error" "1.11.1"
+    "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+    "@webassemblyjs/ieee754" "1.11.1"
+    "@webassemblyjs/leb128" "1.11.1"
+    "@webassemblyjs/utf8" "1.11.1"
+
+"@webassemblyjs/wast-printer@1.11.1":
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0"
+  integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==
+  dependencies:
+    "@webassemblyjs/ast" "1.11.1"
+    "@xtuc/long" "4.2.2"
+
+"@webpack-cli/configtest@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5"
+  integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==
+
+"@webpack-cli/info@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1"
+  integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==
+  dependencies:
+    envinfo "^7.7.3"
+
+"@webpack-cli/serve@^1.7.0":
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1"
+  integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==
+
+"@xtuc/ieee754@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+  integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+  integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+acorn-import-assertions@^1.7.6:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"
+  integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
+
+acorn@^8.5.0, acorn@^8.7.1:
+  version "8.8.1"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
+  integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
+
+aggregate-error@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
+  integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
+  dependencies:
+    clean-stack "^2.0.0"
+    indent-string "^4.0.0"
+
+ajv-keywords@^3.5.2:
+  version "3.5.2"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+  integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv@^6.12.5:
+  version "6.12.6"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+  dependencies:
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+ansi-styles@^4.1.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+  dependencies:
+    color-convert "^2.0.1"
+
+array-union@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+  integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+balanced-match@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+big.js@^5.2.2:
+  version "5.2.2"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+  integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+boolbase@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
+browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.21.4:
+  version "4.21.4"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
+  integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
+  dependencies:
+    caniuse-lite "^1.0.30001400"
+    electron-to-chromium "^1.4.251"
+    node-releases "^2.0.6"
+    update-browserslist-db "^1.0.9"
+
+buffer-from@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+  integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+cacache@^15.0.5:
+  version "15.3.0"
+  resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb"
+  integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==
+  dependencies:
+    "@npmcli/fs" "^1.0.0"
+    "@npmcli/move-file" "^1.0.1"
+    chownr "^2.0.0"
+    fs-minipass "^2.0.0"
+    glob "^7.1.4"
+    infer-owner "^1.0.4"
+    lru-cache "^6.0.0"
+    minipass "^3.1.1"
+    minipass-collect "^1.0.2"
+    minipass-flush "^1.0.5"
+    minipass-pipeline "^1.2.2"
+    mkdirp "^1.0.3"
+    p-map "^4.0.0"
+    promise-inflight "^1.0.1"
+    rimraf "^3.0.2"
+    ssri "^8.0.1"
+    tar "^6.0.2"
+    unique-filename "^1.1.1"
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camelcase-css@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
+  integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
+
+caniuse-api@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
+  integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
+  dependencies:
+    browserslist "^4.0.0"
+    caniuse-lite "^1.0.0"
+    lodash.memoize "^4.1.2"
+    lodash.uniq "^4.5.0"
+
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400:
+  version "1.0.30001429"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz#70cdae959096756a85713b36dd9cb82e62325639"
+  integrity sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==
+
+chalk@^2.0.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
+  integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+chalk@^4.0.0, chalk@^4.1.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+chownr@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
+  integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
+
+chrome-trace-event@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
+  integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
+
+ckeditor5@~35.4.0:
+  version "35.4.0"
+  resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-35.4.0.tgz#0ce67af211551b96856b780e3729481cadbb34df"
+  integrity sha512-vBEQVkFCbjYmEPVkyWsOqU44DOovUio6xBuCwroe4TuJLplqeRasCjFwB0DPknXQU8U0iM3Lh/QSKRyN92pw3Q==
+  dependencies:
+    "@ckeditor/ckeditor5-clipboard" "^35.4.0"
+    "@ckeditor/ckeditor5-core" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^35.4.0"
+    "@ckeditor/ckeditor5-enter" "^35.4.0"
+    "@ckeditor/ckeditor5-paragraph" "^35.4.0"
+    "@ckeditor/ckeditor5-select-all" "^35.4.0"
+    "@ckeditor/ckeditor5-typing" "^35.4.0"
+    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-undo" "^35.4.0"
+    "@ckeditor/ckeditor5-upload" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    "@ckeditor/ckeditor5-widget" "^35.4.0"
+
+clean-stack@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
+  integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
+
+cli-cursor@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+  integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+  dependencies:
+    restore-cursor "^3.1.0"
+
+cli-spinners@^2.6.1:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a"
+  integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==
+
+clone-deep@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
+  integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
+  dependencies:
+    is-plain-object "^2.0.4"
+    kind-of "^6.0.2"
+    shallow-clone "^3.0.0"
+
+color-convert@^1.9.0:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@~1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+colord@^2.9.1:
+  version "2.9.3"
+  resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
+  integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
+
+colorette@^2.0.14:
+  version "2.0.19"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
+  integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
+
+commander@^2.20.0:
+  version "2.20.3"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@^7.0.0, commander@^7.2.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+  integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
+commondir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+  integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+cosmiconfig@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
+  integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
+  dependencies:
+    "@types/parse-json" "^4.0.0"
+    import-fresh "^3.2.1"
+    parse-json "^5.0.0"
+    path-type "^4.0.0"
+    yaml "^1.10.0"
+
+cross-spawn@^7.0.3:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+  dependencies:
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
+
+css-declaration-sorter@^6.3.1:
+  version "6.3.1"
+  resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz#be5e1d71b7a992433fb1c542c7a1b835e45682ec"
+  integrity sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==
+
+css-select@^4.1.3:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+  integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
+  dependencies:
+    boolbase "^1.0.0"
+    css-what "^6.0.1"
+    domhandler "^4.3.1"
+    domutils "^2.8.0"
+    nth-check "^2.0.1"
+
+css-tree@^1.1.2, css-tree@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+  integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+  dependencies:
+    mdn-data "2.0.14"
+    source-map "^0.6.1"
+
+css-what@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+  integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
+cssesc@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+  integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+cssnano-preset-default@^5.2.13:
+  version "5.2.13"
+  resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz#e7353b0c57975d1bdd97ac96e68e5c1b8c68e990"
+  integrity sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==
+  dependencies:
+    css-declaration-sorter "^6.3.1"
+    cssnano-utils "^3.1.0"
+    postcss-calc "^8.2.3"
+    postcss-colormin "^5.3.0"
+    postcss-convert-values "^5.1.3"
+    postcss-discard-comments "^5.1.2"
+    postcss-discard-duplicates "^5.1.0"
+    postcss-discard-empty "^5.1.1"
+    postcss-discard-overridden "^5.1.0"
+    postcss-merge-longhand "^5.1.7"
+    postcss-merge-rules "^5.1.3"
+    postcss-minify-font-values "^5.1.0"
+    postcss-minify-gradients "^5.1.1"
+    postcss-minify-params "^5.1.4"
+    postcss-minify-selectors "^5.2.1"
+    postcss-normalize-charset "^5.1.0"
+    postcss-normalize-display-values "^5.1.0"
+    postcss-normalize-positions "^5.1.1"
+    postcss-normalize-repeat-style "^5.1.1"
+    postcss-normalize-string "^5.1.0"
+    postcss-normalize-timing-functions "^5.1.0"
+    postcss-normalize-unicode "^5.1.1"
+    postcss-normalize-url "^5.1.0"
+    postcss-normalize-whitespace "^5.1.1"
+    postcss-ordered-values "^5.1.3"
+    postcss-reduce-initial "^5.1.1"
+    postcss-reduce-transforms "^5.1.0"
+    postcss-svgo "^5.1.0"
+    postcss-unique-selectors "^5.1.1"
+
+cssnano-utils@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861"
+  integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==
+
+cssnano@^5.0.0:
+  version "5.1.14"
+  resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.14.tgz#07b0af6da73641276fe5a6d45757702ebae2eb05"
+  integrity sha512-Oou7ihiTocbKqi0J1bB+TRJIQX5RMR3JghA8hcWSw9mjBLQ5Y3RWqEDoYG3sRNlAbCIXpqMoZGbq5KDR3vdzgw==
+  dependencies:
+    cssnano-preset-default "^5.2.13"
+    lilconfig "^2.0.3"
+    yaml "^1.10.2"
+
+csso@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
+  integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
+  dependencies:
+    css-tree "^1.1.2"
+
+debug@^4.1.0:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+  dependencies:
+    ms "2.1.2"
+
+deep-is@~0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+  integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+del@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
+  integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==
+  dependencies:
+    globby "^10.0.1"
+    graceful-fs "^4.2.2"
+    is-glob "^4.0.1"
+    is-path-cwd "^2.2.0"
+    is-path-inside "^3.0.1"
+    p-map "^3.0.0"
+    rimraf "^3.0.0"
+    slash "^3.0.0"
+
+dir-glob@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+  integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+  dependencies:
+    path-type "^4.0.0"
+
+dom-serializer@^1.0.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
+  integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+  dependencies:
+    domelementtype "^2.0.1"
+    domhandler "^4.2.0"
+    entities "^2.0.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+  integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^4.2.0, domhandler@^4.3.1:
+  version "4.3.1"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+  integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+  dependencies:
+    domelementtype "^2.2.0"
+
+domutils@^2.8.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+  integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+  dependencies:
+    dom-serializer "^1.0.1"
+    domelementtype "^2.2.0"
+    domhandler "^4.2.0"
+
+electron-to-chromium@^1.4.251:
+  version "1.4.284"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592"
+  integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==
+
+emojis-list@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+  integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
+
+enhanced-resolve@^5.0.0, enhanced-resolve@^5.10.0:
+  version "5.10.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
+  integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
+  dependencies:
+    graceful-fs "^4.2.4"
+    tapable "^2.2.0"
+
+entities@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+  integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+envinfo@^7.7.3:
+  version "7.8.1"
+  resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
+  integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==
+
+error-ex@^1.3.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+es-module-lexer@^0.9.0:
+  version "0.9.3"
+  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
+  integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
+
+escalade@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escodegen@^1.9.0:
+  version "1.14.3"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
+  integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
+  dependencies:
+    esprima "^4.0.1"
+    estraverse "^4.2.0"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.6.1"
+
+eslint-scope@5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+  integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+  dependencies:
+    esrecurse "^4.3.0"
+    estraverse "^4.1.1"
+
+esprima@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esrecurse@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+  integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+  dependencies:
+    estraverse "^5.2.0"
+
+estraverse@^4.1.1, estraverse@^4.2.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.2.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+esutils@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+  integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+events@^3.2.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+  integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+fast-deep-equal@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-glob@^3.0.3, fast-glob@^3.2.11:
+  version "3.2.12"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
+  integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@~2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+  integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fastest-levenshtein@^1.0.12:
+  version "1.0.16"
+  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
+  integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
+
+fastq@^1.6.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
+  integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
+  dependencies:
+    reusify "^1.0.4"
+
+fill-range@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+  dependencies:
+    to-regex-range "^5.0.1"
+
+find-cache-dir@^3.3.1:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b"
+  integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==
+  dependencies:
+    commondir "^1.0.1"
+    make-dir "^3.0.2"
+    pkg-dir "^4.1.0"
+
+find-up@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+  integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+  dependencies:
+    locate-path "^5.0.0"
+    path-exists "^4.0.0"
+
+fs-extra@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
+  integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
+  dependencies:
+    graceful-fs "^4.2.0"
+    jsonfile "^4.0.0"
+    universalify "^0.1.0"
+
+fs-minipass@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
+  integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
+  dependencies:
+    minipass "^3.0.0"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+glob-parent@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob-to-regexp@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+  integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+glob@^7.0.0, glob@^7.1.3, glob@^7.1.4:
+  version "7.2.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.1.1"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^11.1.0:
+  version "11.12.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globby@^10.0.1:
+  version "10.0.2"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
+  integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==
+  dependencies:
+    "@types/glob" "^7.1.1"
+    array-union "^2.1.0"
+    dir-glob "^3.0.1"
+    fast-glob "^3.0.3"
+    glob "^7.1.3"
+    ignore "^5.1.1"
+    merge2 "^1.2.3"
+    slash "^3.0.0"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+  version "4.2.10"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
+  integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+  dependencies:
+    function-bind "^1.1.1"
+
+ignore@^5.1.1:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
+  integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
+
+import-fresh@^3.2.1:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+import-local@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"
+  integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
+  dependencies:
+    pkg-dir "^4.2.0"
+    resolve-cwd "^3.0.0"
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+  integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+indent-string@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+  integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
+infer-owner@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
+  integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.3, inherits@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+interpret@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+  integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
+interpret@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
+  integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-core-module@^2.9.0:
+  version "2.11.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
+  integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
+  dependencies:
+    has "^1.0.3"
+
+is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-glob@^4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-interactive@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
+  integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
+
+is-number@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-cwd@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+  integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
+
+is-path-inside@^3.0.1:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-plain-object@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+  dependencies:
+    isobject "^3.0.1"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+isobject@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+  integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+
+javascript-stringify@^1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3"
+  integrity sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==
+
+jest-worker@^26.5.0:
+  version "26.6.2"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
+  integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
+  dependencies:
+    "@types/node" "*"
+    merge-stream "^2.0.0"
+    supports-color "^7.0.0"
+
+jest-worker@^27.4.5:
+  version "27.5.1"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
+  integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
+  dependencies:
+    "@types/node" "*"
+    merge-stream "^2.0.0"
+    supports-color "^8.0.0"
+
+js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+jsesc@^2.5.1:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json5@^2.1.2:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
+  integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
+
+jsonfile@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+  integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
+kind-of@^6.0.2:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+  integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+klona@^2.0.4:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc"
+  integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+lilconfig@^2.0.3:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
+  integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
+
+lines-and-columns@^1.1.6:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+  integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+loader-runner@^4.2.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+  integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
+
+loader-utils@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.3.tgz#d4b15b8504c63d1fc3f2ade52d41bc8459d6ede1"
+  integrity sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==
+  dependencies:
+    big.js "^5.2.2"
+    emojis-list "^3.0.0"
+    json5 "^2.1.2"
+
+locate-path@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+  integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+  dependencies:
+    p-locate "^4.1.0"
+
+lodash-es@^4.17.11, lodash-es@^4.17.15:
+  version "4.17.21"
+  resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash.memoize@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+  integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
+
+lodash.uniq@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+  integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
+
+lru-cache@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+  dependencies:
+    yallist "^4.0.0"
+
+make-dir@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+  integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+  dependencies:
+    semver "^6.0.0"
+
+mdn-data@2.0.14:
+  version "2.0.14"
+  resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+  integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
+merge-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.2.3, merge2@^1.3.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.0, micromatch@^4.0.4:
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+  dependencies:
+    braces "^3.0.2"
+    picomatch "^2.3.1"
+
+mime-db@1.52.0:
+  version "1.52.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.27:
+  version "2.1.35"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+  dependencies:
+    mime-db "1.52.0"
+
+mimic-fn@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+minimatch@^3.1.1:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minipass-collect@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
+  integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
+  dependencies:
+    minipass "^3.0.0"
+
+minipass-flush@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373"
+  integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
+  dependencies:
+    minipass "^3.0.0"
+
+minipass-pipeline@^1.2.2:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
+  integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
+  dependencies:
+    minipass "^3.0.0"
+
+minipass@^3.0.0, minipass@^3.1.1:
+  version "3.3.4"
+  resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.4.tgz#ca99f95dd77c43c7a76bf51e6d200025eee0ffae"
+  integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==
+  dependencies:
+    yallist "^4.0.0"
+
+minizlib@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
+  integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
+  dependencies:
+    minipass "^3.0.0"
+    yallist "^4.0.0"
+
+mkdirp@^1.0.3, mkdirp@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+  integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+ms@2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+nanoid@^3.3.4:
+  version "3.3.4"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
+  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
+
+neo-async@^2.6.2:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+  integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+node-releases@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
+  integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
+
+normalize-url@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+  integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+nth-check@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+  integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+  dependencies:
+    boolbase "^1.0.0"
+
+once@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+  dependencies:
+    wrappy "1"
+
+onetime@^5.1.0:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+  integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+  dependencies:
+    mimic-fn "^2.1.0"
+
+optionator@^0.8.1:
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
+  integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.6"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    word-wrap "~1.2.3"
+
+p-limit@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+  dependencies:
+    p-try "^2.0.0"
+
+p-limit@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+  dependencies:
+    yocto-queue "^0.1.0"
+
+p-locate@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+  integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+  dependencies:
+    p-limit "^2.2.0"
+
+p-map@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d"
+  integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==
+  dependencies:
+    aggregate-error "^3.0.0"
+
+p-map@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
+  integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
+  dependencies:
+    aggregate-error "^3.0.0"
+
+p-try@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+parse-json@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    error-ex "^1.3.1"
+    json-parse-even-better-errors "^2.3.0"
+    lines-and-columns "^1.1.6"
+
+path-exists@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-parse@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-type@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pify@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+
+pkg-dir@^4.1.0, pkg-dir@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+  integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+  dependencies:
+    find-up "^4.0.0"
+
+pofile@^1.0.9:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.1.3.tgz#e2c0d4052b9829f171b888bfb35c87791dbea297"
+  integrity sha512-sk96pUvpNwDV6PLrnhr68Uu1S5NohsxqLKz0GuracgrDo40BdF/r1RhHnjakUk6Q4Z0OKIybOQ7GevLKGN1iYw==
+
+postcss-calc@^8.2.3:
+  version "8.2.4"
+  resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5"
+  integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==
+  dependencies:
+    postcss-selector-parser "^6.0.9"
+    postcss-value-parser "^4.2.0"
+
+postcss-colormin@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a"
+  integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==
+  dependencies:
+    browserslist "^4.16.6"
+    caniuse-api "^3.0.0"
+    colord "^2.9.1"
+    postcss-value-parser "^4.2.0"
+
+postcss-convert-values@^5.1.3:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393"
+  integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==
+  dependencies:
+    browserslist "^4.21.4"
+    postcss-value-parser "^4.2.0"
+
+postcss-discard-comments@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696"
+  integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==
+
+postcss-discard-duplicates@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848"
+  integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==
+
+postcss-discard-empty@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c"
+  integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==
+
+postcss-discard-overridden@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e"
+  integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==
+
+postcss-import@^14.1.0:
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
+  integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
+  dependencies:
+    postcss-value-parser "^4.0.0"
+    read-cache "^1.0.0"
+    resolve "^1.1.7"
+
+postcss-js@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
+  integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
+  dependencies:
+    camelcase-css "^2.0.1"
+
+postcss-loader@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.3.0.tgz#2c4de9657cd4f07af5ab42bd60a673004da1b8cc"
+  integrity sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==
+  dependencies:
+    cosmiconfig "^7.0.0"
+    klona "^2.0.4"
+    loader-utils "^2.0.0"
+    schema-utils "^3.0.0"
+    semver "^7.3.4"
+
+postcss-merge-longhand@^5.1.7:
+  version "5.1.7"
+  resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16"
+  integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+    stylehacks "^5.1.1"
+
+postcss-merge-rules@^5.1.3:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz#8f97679e67cc8d08677a6519afca41edf2220894"
+  integrity sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==
+  dependencies:
+    browserslist "^4.21.4"
+    caniuse-api "^3.0.0"
+    cssnano-utils "^3.1.0"
+    postcss-selector-parser "^6.0.5"
+
+postcss-minify-font-values@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b"
+  integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-minify-gradients@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c"
+  integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==
+  dependencies:
+    colord "^2.9.1"
+    cssnano-utils "^3.1.0"
+    postcss-value-parser "^4.2.0"
+
+postcss-minify-params@^5.1.4:
+  version "5.1.4"
+  resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352"
+  integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==
+  dependencies:
+    browserslist "^4.21.4"
+    cssnano-utils "^3.1.0"
+    postcss-value-parser "^4.2.0"
+
+postcss-minify-selectors@^5.2.1:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6"
+  integrity sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==
+  dependencies:
+    postcss-selector-parser "^6.0.5"
+
+postcss-mixins@^9.0.2:
+  version "9.0.4"
+  resolved "https://registry.yarnpkg.com/postcss-mixins/-/postcss-mixins-9.0.4.tgz#75cd3cdb619a7e08c4c51ebb094db5f6d65b3831"
+  integrity sha512-XVq5jwQJDRu5M1XGkdpgASqLk37OqkH4JCFDXl/Dn7janOJjCTEKL+36cnRVy7bMtoBzALfO7bV7nTIsFnUWLA==
+  dependencies:
+    fast-glob "^3.2.11"
+    postcss-js "^4.0.0"
+    postcss-simple-vars "^7.0.0"
+    sugarss "^4.0.1"
+
+postcss-nesting@^10.1.4:
+  version "10.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-10.2.0.tgz#0b12ce0db8edfd2d8ae0aaf86427370b898890be"
+  integrity sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==
+  dependencies:
+    "@csstools/selector-specificity" "^2.0.0"
+    postcss-selector-parser "^6.0.10"
+
+postcss-normalize-charset@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed"
+  integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==
+
+postcss-normalize-display-values@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8"
+  integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-positions@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92"
+  integrity sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-repeat-style@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2"
+  integrity sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-string@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228"
+  integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-timing-functions@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb"
+  integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-unicode@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030"
+  integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==
+  dependencies:
+    browserslist "^4.21.4"
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-url@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc"
+  integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==
+  dependencies:
+    normalize-url "^6.0.1"
+    postcss-value-parser "^4.2.0"
+
+postcss-normalize-whitespace@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa"
+  integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-ordered-values@^5.1.3:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38"
+  integrity sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==
+  dependencies:
+    cssnano-utils "^3.1.0"
+    postcss-value-parser "^4.2.0"
+
+postcss-reduce-initial@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz#c18b7dfb88aee24b1f8e4936541c29adbd35224e"
+  integrity sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==
+  dependencies:
+    browserslist "^4.21.4"
+    caniuse-api "^3.0.0"
+
+postcss-reduce-transforms@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9"
+  integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+
+postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
+  version "6.0.10"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
+  integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
+  dependencies:
+    cssesc "^3.0.0"
+    util-deprecate "^1.0.2"
+
+postcss-simple-vars@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-simple-vars/-/postcss-simple-vars-7.0.0.tgz#f1d10a979762aa4e7e3450a35a32885112893d1b"
+  integrity sha512-SPSkKQK7mKjD/tqcTbZkDi3KP+C/cTGXnKQmSt3AisJtnZE6ZxHEUoOGRfpV0B5dW1Y36EETfRHx10WLHpXThA==
+
+postcss-svgo@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d"
+  integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==
+  dependencies:
+    postcss-value-parser "^4.2.0"
+    svgo "^2.7.0"
+
+postcss-unique-selectors@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6"
+  integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==
+  dependencies:
+    postcss-selector-parser "^6.0.5"
+
+postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+  integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^8.4.12:
+  version "8.4.18"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.18.tgz#6d50046ea7d3d66a85e0e782074e7203bc7fbca2"
+  integrity sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==
+  dependencies:
+    nanoid "^3.3.4"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+  integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
+
+promise-inflight@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+  integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+queue-microtask@^1.2.2:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+randombytes@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+  dependencies:
+    safe-buffer "^5.1.0"
+
+raw-loader@^4.0.1, raw-loader@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6"
+  integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==
+  dependencies:
+    loader-utils "^2.0.0"
+    schema-utils "^3.0.0"
+
+read-cache@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
+  integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
+  dependencies:
+    pify "^2.3.0"
+
+"readable-stream@2 || 3":
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+  integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+rechoir@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+  integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
+  dependencies:
+    resolve "^1.1.6"
+
+rechoir@^0.7.0:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.1.tgz#9478a96a1ca135b5e88fc027f03ee92d6c645686"
+  integrity sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==
+  dependencies:
+    resolve "^1.9.0"
+
+resolve-cwd@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+  integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+  dependencies:
+    resolve-from "^5.0.0"
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-from@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+  integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.9.0:
+  version "1.22.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
+  integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+  dependencies:
+    is-core-module "^2.9.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
+
+restore-cursor@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+  integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+  dependencies:
+    onetime "^5.1.0"
+    signal-exit "^3.0.2"
+
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@^3.0.0, rimraf@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+  dependencies:
+    glob "^7.1.3"
+
+run-parallel@^1.1.9:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+  dependencies:
+    queue-microtask "^1.2.2"
+
+safe-buffer@^5.1.0, safe-buffer@~5.2.0:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281"
+  integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
+  dependencies:
+    "@types/json-schema" "^7.0.8"
+    ajv "^6.12.5"
+    ajv-keywords "^3.5.2"
+
+semver@^6.0.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+semver@^7.3.4, semver@^7.3.5:
+  version "7.3.8"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
+  integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
+  dependencies:
+    lru-cache "^6.0.0"
+
+serialize-javascript@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
+  integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
+  dependencies:
+    randombytes "^2.1.0"
+
+serialize-javascript@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8"
+  integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==
+  dependencies:
+    randombytes "^2.1.0"
+
+shallow-clone@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
+  integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
+  dependencies:
+    kind-of "^6.0.2"
+
+shebang-command@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+  dependencies:
+    shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+shelljs@^0.8.1:
+  version "0.8.5"
+  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
+  integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
+  dependencies:
+    glob "^7.0.0"
+    interpret "^1.0.0"
+    rechoir "^0.6.2"
+
+signal-exit@^3.0.2:
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+  integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+slash@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+  integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+source-list-map@^2.0.0, source-list-map@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+  integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
+
+source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+source-map-support@~0.5.20:
+  version "0.5.21"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+  integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+ssri@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af"
+  integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==
+  dependencies:
+    minipass "^3.1.1"
+
+stable@^0.1.8:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+string_decoder@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+  integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+  dependencies:
+    safe-buffer "~5.2.0"
+
+style-loader@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c"
+  integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==
+  dependencies:
+    loader-utils "^2.0.0"
+    schema-utils "^3.0.0"
+
+stylehacks@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9"
+  integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==
+  dependencies:
+    browserslist "^4.21.4"
+    postcss-selector-parser "^6.0.4"
+
+sugarss@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-4.0.1.tgz#128a783ed71ee0fc3b489ce1f7d5a89bc1e24383"
+  integrity sha512-WCjS5NfuVJjkQzK10s8WOBY+hhDxxNt/N6ZaGwxFZ+wN3/lKKFSaaKUNecULcTTvE4urLcKaZFQD8vO0mOZujw==
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^7.0.0, supports-color@^7.1.0:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+  dependencies:
+    has-flag "^4.0.0"
+
+supports-color@^8.0.0:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+  integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+  dependencies:
+    has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+svgo@^2.7.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
+  integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
+  dependencies:
+    "@trysound/sax" "0.2.0"
+    commander "^7.2.0"
+    css-select "^4.1.3"
+    css-tree "^1.1.3"
+    csso "^4.2.0"
+    picocolors "^1.0.0"
+    stable "^0.1.8"
+
+tapable@^2.1.1, tapable@^2.2.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+  integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
+tar@^6.0.2:
+  version "6.1.12"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.12.tgz#3b742fb05669b55671fb769ab67a7791ea1a62e6"
+  integrity sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==
+  dependencies:
+    chownr "^2.0.0"
+    fs-minipass "^2.0.0"
+    minipass "^3.0.0"
+    minizlib "^2.1.1"
+    mkdirp "^1.0.3"
+    yallist "^4.0.0"
+
+terser-webpack-plugin@^4.2.3:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a"
+  integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==
+  dependencies:
+    cacache "^15.0.5"
+    find-cache-dir "^3.3.1"
+    jest-worker "^26.5.0"
+    p-limit "^3.0.2"
+    schema-utils "^3.0.0"
+    serialize-javascript "^5.0.1"
+    source-map "^0.6.1"
+    terser "^5.3.4"
+    webpack-sources "^1.4.3"
+
+terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.0:
+  version "5.3.6"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c"
+  integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==
+  dependencies:
+    "@jridgewell/trace-mapping" "^0.3.14"
+    jest-worker "^27.4.5"
+    schema-utils "^3.1.1"
+    serialize-javascript "^6.0.0"
+    terser "^5.14.1"
+
+terser@^5.14.1, terser@^5.3.4:
+  version "5.15.1"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.1.tgz#8561af6e0fd6d839669c73b92bdd5777d870ed6c"
+  integrity sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==
+  dependencies:
+    "@jridgewell/source-map" "^0.3.2"
+    acorn "^8.5.0"
+    commander "^2.20.0"
+    source-map-support "~0.5.20"
+
+through2@^3.0.1:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4"
+  integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==
+  dependencies:
+    inherits "^2.0.4"
+    readable-stream "2 || 3"
+
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-regex-range@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+  dependencies:
+    is-number "^7.0.0"
+
+ts-loader@^9.3.0:
+  version "9.4.1"
+  resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.1.tgz#b6f3d82db0eac5a8295994f8cb5e4940ff6b1060"
+  integrity sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==
+  dependencies:
+    chalk "^4.1.0"
+    enhanced-resolve "^5.0.0"
+    micromatch "^4.0.0"
+    semver "^7.3.4"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
+  dependencies:
+    prelude-ls "~1.1.2"
+
+unique-filename@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
+  integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
+  dependencies:
+    unique-slug "^2.0.0"
+
+unique-slug@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c"
+  integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==
+  dependencies:
+    imurmurhash "^0.1.4"
+
+universalify@^0.1.0:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
+update-browserslist-db@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3"
+  integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==
+  dependencies:
+    escalade "^3.1.1"
+    picocolors "^1.0.0"
+
+uri-js@^4.2.2:
+  version "4.4.1"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+  dependencies:
+    punycode "^2.1.0"
+
+util-deprecate@^1.0.1, util-deprecate@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+watchpack@^2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
+  integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
+  dependencies:
+    glob-to-regexp "^0.4.1"
+    graceful-fs "^4.1.2"
+
+webpack-cli@^4.4.0:
+  version "4.10.0"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31"
+  integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==
+  dependencies:
+    "@discoveryjs/json-ext" "^0.5.0"
+    "@webpack-cli/configtest" "^1.2.0"
+    "@webpack-cli/info" "^1.5.0"
+    "@webpack-cli/serve" "^1.7.0"
+    colorette "^2.0.14"
+    commander "^7.0.0"
+    cross-spawn "^7.0.3"
+    fastest-levenshtein "^1.0.12"
+    import-local "^3.0.2"
+    interpret "^2.2.0"
+    rechoir "^0.7.0"
+    webpack-merge "^5.7.3"
+
+webpack-merge@^5.7.3:
+  version "5.8.0"
+  resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61"
+  integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==
+  dependencies:
+    clone-deep "^4.0.1"
+    wildcard "^2.0.0"
+
+webpack-sources@^1.4.3:
+  version "1.4.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+  integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
+  dependencies:
+    source-list-map "^2.0.0"
+    source-map "~0.6.1"
+
+webpack-sources@^2.0.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd"
+  integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==
+  dependencies:
+    source-list-map "^2.0.1"
+    source-map "^0.6.1"
+
+webpack-sources@^3.2.3:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+  integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@^5.51.1:
+  version "5.74.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980"
+  integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==
+  dependencies:
+    "@types/eslint-scope" "^3.7.3"
+    "@types/estree" "^0.0.51"
+    "@webassemblyjs/ast" "1.11.1"
+    "@webassemblyjs/wasm-edit" "1.11.1"
+    "@webassemblyjs/wasm-parser" "1.11.1"
+    acorn "^8.7.1"
+    acorn-import-assertions "^1.7.6"
+    browserslist "^4.14.5"
+    chrome-trace-event "^1.0.2"
+    enhanced-resolve "^5.10.0"
+    es-module-lexer "^0.9.0"
+    eslint-scope "5.1.1"
+    events "^3.2.0"
+    glob-to-regexp "^0.4.1"
+    graceful-fs "^4.2.9"
+    json-parse-even-better-errors "^2.3.1"
+    loader-runner "^4.2.0"
+    mime-types "^2.1.27"
+    neo-async "^2.6.2"
+    schema-utils "^3.1.0"
+    tapable "^2.1.1"
+    terser-webpack-plugin "^5.1.3"
+    watchpack "^2.4.0"
+    webpack-sources "^3.2.3"
+
+which@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+  dependencies:
+    isexe "^2.0.0"
+
+wildcard@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
+  integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
+
+word-wrap@~1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+  integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+yallist@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yaml@^1.10.0, yaml@^1.10.2:
+  version "1.10.2"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yocto-queue@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
\ No newline at end of file
-- 
GitLab


From b2688a94e1f3ca70d31fbfe4e12b06eae3754581 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Fri, 17 Feb 2023 09:07:51 +0100
Subject: [PATCH 05/19] WIP, see @todo for lasting work

---
 .../css/video_embed.admin.css                 |   2 +-
 .../icons/play-circle (copie).svg             |   1 -
 .../video_embed_wysiwyg/icons/play-circle.svg |   2 +-
 modules/video_embed_wysiwyg/icons/play.svg    |   1 -
 .../js/build/videoEmbed.js                    |   1 +
 .../ckeditor5_plugins/videoEmbed/src/index.js |   1 +
 .../videoEmbed/src/videoembedediting.js       |   9 +-
 .../videoEmbed/src/videoembedui.js            | 100 +++++++-
 .../CKEditor5Plugin/VideoEmbedWysiwyg.php     |   8 +-
 modules/video_embed_wysiwyg/yarn.lock         | 217 +++++++++---------
 10 files changed, 219 insertions(+), 123 deletions(-)
 delete mode 100644 modules/video_embed_wysiwyg/icons/play-circle (copie).svg
 delete mode 100644 modules/video_embed_wysiwyg/icons/play.svg
 create mode 100644 modules/video_embed_wysiwyg/js/build/videoEmbed.js

diff --git a/modules/video_embed_wysiwyg/css/video_embed.admin.css b/modules/video_embed_wysiwyg/css/video_embed.admin.css
index 7ef5780..abf5b07 100644
--- a/modules/video_embed_wysiwyg/css/video_embed.admin.css
+++ b/modules/video_embed_wysiwyg/css/video_embed.admin.css
@@ -1,4 +1,4 @@
 .ckeditor5-toolbar-button-videoEmbed {
   /* @todo Choose the best icon and remove others. */
-  background-image: url(../icons/film.svg);
+  background-image: url(../icons/play-circle.svg);
 }
diff --git a/modules/video_embed_wysiwyg/icons/play-circle (copie).svg b/modules/video_embed_wysiwyg/icons/play-circle (copie).svg
deleted file mode 100644
index 778c5fa..0000000
--- a/modules/video_embed_wysiwyg/icons/play-circle (copie).svg	
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/icons/play-circle.svg b/modules/video_embed_wysiwyg/icons/play-circle.svg
index 0ce0085..778c5fa 100644
--- a/modules/video_embed_wysiwyg/icons/play-circle.svg
+++ b/modules/video_embed_wysiwyg/icons/play-circle.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm115.7 272l-176 101c-15.8 8.8-35.7-2.5-35.7-21V152c0-18.4 19.8-29.8 35.7-21l176 107c16.4 9.2 16.4 32.9 0 42z"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/icons/play.svg b/modules/video_embed_wysiwyg/icons/play.svg
deleted file mode 100644
index e817cc8..0000000
--- a/modules/video_embed_wysiwyg/icons/play.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"/></svg>
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
new file mode 100644
index 0000000..6f05a06
--- /dev/null
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":()=>{eval('throw new Error("Module parse failed: Unexpected token (61:4)\\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders\\n|       // @todo register allowed model attributes.\\n|       allowAttributes:\\n>     });\\n|   }\\n| ");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract it's values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo adapt this copy-pasted code.\n      existingValues = selectedVideoEmbedElement.hasAttribute('data-entity-uuid') ? {\n        'data-entity-uuid': selectedVideoEmbedElement.getAttribute('data-entity-uuid'),\n        'data-entity-type': selectedVideoEmbedElement.getAttribute('data-entity-type'),\n      } : {};\n    }\n\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        ({attributes}) => {\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adopted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var _=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](_,_.exports,__webpack_require__),_.exports}__webpack_require__.d=(e,t)=>{for(var _ in t)__webpack_require__.o(t,_)&&!__webpack_require__.o(e,_)&&Object.defineProperty(e,_,{enumerable:!0,get:t[_]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
index 6fcd277..d56de08 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
@@ -1,5 +1,6 @@
 import VideoEmbed from './videoembed';
 
+// @todo Remove console.log calls.
 export default {
   VideoEmbed,
 };
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
index 3153259..8fd9b0b 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -53,12 +53,11 @@ export default class VideoEmbedEditing extends Plugin {
     const schema = this.editor.model.schema;
 
 
-    // @todo register allowed model attributes.
+
     schema.register('videoEmbed', {
-      // Behaves like a self-contained object (e.g. an image).
-      isObject: true,
-      // Allow in places where other blocks are allowed (e.g. directly in the root).
-      allowWhere: '$block',
+      inheritAllFrom: '$blockObject',
+      // @todo register allowed model attributes.
+      // allowAttributes:
     });
   }
 
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
index 94ba981..dab160d 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
@@ -2,10 +2,11 @@
  * @file registers the videoEmbed toolbar button and binds functionality to it.
  */
 
-import { Plugin } from 'ckeditor5/src/core';
-import { ButtonView } from 'ckeditor5/src/ui';
+import {Plugin} from 'ckeditor5/src/core';
+import {ButtonView} from 'ckeditor5/src/ui';
+
 /* @todo Choose the best icon and remove others. */
-import icon from '../../../../icons/film.svg';
+import icon from '../../../../icons/play-circle.svg';
 
 export default class VideoEmbedUI extends Plugin {
   init() {
@@ -27,12 +28,101 @@ export default class VideoEmbedUI extends Plugin {
       buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
 
       // Execute the command when the button is clicked (executed).
-      this.listenTo(buttonView, 'execute', () =>
-          editor.execute('insertVideoEmbed'),
+      this.listenTo(buttonView, 'execute', () => {
+            console.log('button execution');
+            this.openEditingDialog();
+          }
       );
 
       return buttonView;
     });
   }
+
+  /**
+   * Opens video embed form when the editing button is clicked.
+   */
+  openEditingDialog() {
+    console.log('dialog opening');
+    const {editor} = this;
+
+    // If the selected element while we click the button is an instance
+    // of the video_embed widget, extract its values so they can be
+    // sent to the server to prime the configuration form.
+    let existingValues = {};
+    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()
+    if (selectedVideoEmbedElement) {
+      // @todo adapt this copy-pasted code.
+      existingValues = selectedVideoEmbedElement.hasAttribute('data-entity-uuid') ? {
+        'data-entity-uuid': selectedVideoEmbedElement.getAttribute('data-entity-uuid'),
+        'data-entity-type': selectedVideoEmbedElement.getAttribute('data-entity-type'),
+      } : {};
+    }
+
+    this._openDialog(
+        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),
+        existingValues,
+        ({attributes}) => {
+          editor.execute('insertVideoEmbed', attributes);
+        },
+        {
+          title: Drupal.t('Video Embed'),
+          dialogClass: 'video-embed-dialog'
+        }
+    );
+  }
+
+  /**
+   * @todo Return the focused videoEmbed element (the cke5 widget system may
+   * help with that).
+   *
+   * @private
+   */
+  _getSelectedVideoEmbedElement() {
+    return null;
+  }
+
+  /**
+   * This method is adopted from drupal's ckeditor5.js file due to an issue
+   * where the "editor_object" isn't passed to the ajax request.
+   *
+   * See https://www.drupal.org/project/drupal/issues/3303191
+   *
+   * @param {string} url
+   *   The URL that contains the contents of the dialog.
+   * @param {object} existingValues
+   *   Existing values that will be sent via POST to the url for the dialog
+   *   contents.
+   * @param {function} saveCallback
+   *   A function to be called upon saving the dialog.
+   * @param {object} dialogSettings
+   *   An object containing settings to be passed to the jQuery UI.
+   */
+  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {
+    // Add a consistent dialog class.
+    const classes = dialogSettings.dialogClass
+        ? dialogSettings.dialogClass.split(' ')
+        : [];
+    classes.push('ui-dialog--narrow');
+    dialogSettings.dialogClass = classes.join(' ');
+    dialogSettings.autoResize =
+        window.matchMedia('(min-width: 600px)').matches;
+    dialogSettings.width = 'auto';
+
+    const ckeditorAjaxDialog = Drupal.ajax({
+      dialog: dialogSettings,
+      dialogType: 'modal',
+      selector: '.ckeditor5-dialog-loading-link',
+      url,
+      progress: {type: 'fullscreen'},
+      submit: {
+        editor_object: existingValues,
+      },
+    });
+    ckeditorAjaxDialog.execute();
+
+    // Store the save callback to be executed when this dialog is closed.
+    Drupal.ckeditor5.saveCallback = saveCallback;
+  }
+
 }
 
diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
index dd57409..13f1f19 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
@@ -10,6 +10,8 @@ use Drupal\editor\EditorInterface;
 
 /**
  * This class transmits the Drupal config to the javascript plugin.
+ *
+ * @todo Add the settings form for the plugin.
  */
 class VideoEmbedWysiwyg extends CKEditor5PluginDefault {
 
@@ -22,15 +24,19 @@ class VideoEmbedWysiwyg extends CKEditor5PluginDefault {
    * @return mixed[]
    */
   public function getDynamicPluginConfig(array $static_plugin_config, EditorInterface $editor): array {
+    $plugin_config = [
+      'format' => $editor->id(),
+    ];
     $format = $editor->getFilterFormat();
     /** @var \Drupal\filter\Plugin\FilterInterface $filter */
     $filter = $format->filters('video_embed_wysiwyg');
     $filter_config = $filter->getConfiguration();
+    $plugin_config += $filter_config['settings'];
     $parent_config = parent::getDynamicPluginConfig($static_plugin_config, $editor);
     // @todo Ensure this is the info the plugin needs.
     return array_merge_recursive($parent_config,
       [
-        'VideoEmbed' => $filter_config['settings']
+        'videoEmbed' => $plugin_config,
       ]);
   }
 
diff --git a/modules/video_embed_wysiwyg/yarn.lock b/modules/video_embed_wysiwyg/yarn.lock
index 569df04..eace212 100644
--- a/modules/video_embed_wysiwyg/yarn.lock
+++ b/modules/video_embed_wysiwyg/yarn.lock
@@ -103,25 +103,25 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
-"@ckeditor/ckeditor5-clipboard@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-35.4.0.tgz#8529fd45d06a7edea0f73cd0b5b3052f2272335c"
-  integrity sha512-B6rIQxvOrHvO9TZRC8JA0wKk+IfN880UJkYIg1qlhf9HFNVjdVbtHaiCsPD+TzGmQN3XHXfNjgjabGRIn0iZmw==
-  dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
-    "@ckeditor/ckeditor5-widget" "^35.4.0"
+"@ckeditor/ckeditor5-clipboard@^34.1.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-clipboard/-/ckeditor5-clipboard-34.2.0.tgz#ab69636365b0bd95631817fe4f5c3cc22bc6fce3"
+  integrity sha512-OcdFj9yT7C5yKPHtTKWvjGMJLpigrkdJN4AZhdJJPigiuYG0c5mnCuTvOYxp2kVijFWRjhPlwIyPVTtDZ0vnzw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-engine" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
+    "@ckeditor/ckeditor5-widget" "^34.2.0"
     lodash-es "^4.17.11"
 
-"@ckeditor/ckeditor5-core@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-35.4.0.tgz#39390445c8363a80d4ce0e45d93efa13b8523f6e"
-  integrity sha512-Rf0H7C4inCj/YC8aii0cT7TC/IuBIQ+tXmu9qd8/1BJ/rz1MCHXtBPApjTbFp33OE3aOFB5+NUaKt05k/dL3OA==
+"@ckeditor/ckeditor5-core@^34.1.0", "@ckeditor/ckeditor5-core@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-core/-/ckeditor5-core-34.2.0.tgz#4ba72e3407310843a784630c598501ccc42a585b"
+  integrity sha512-6K0aToibRt28sCVYpMqdSKGvMifjwziqxLxyEh38CyDZJBUf7QPEAPlEpKAFTisHNEmC4471tr8UPpvNgqUXGA==
   dependencies:
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    "@ckeditor/ckeditor5-engine" "^34.2.0"
+    "@ckeditor/ckeditor5-ui" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
     lodash-es "^4.17.15"
 
 "@ckeditor/ckeditor5-dev-utils@^30.0.0", "@ckeditor/ckeditor5-dev-utils@^30.5.0":
@@ -165,95 +165,96 @@
     semver "^7.3.4"
     webpack-sources "^2.0.1"
 
-"@ckeditor/ckeditor5-engine@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-35.4.0.tgz#cb0ed9f0c5a9ef00b24ffbd8d2100fff1e0e90cb"
-  integrity sha512-67QKtUGJeLM072h9qURvzczYGU3ecuxR9LLmM4dffnV+PBNQ9e8RDCY7PuuEP0pplmAUI6/XqoZJIbk6h7ZV3Q==
+"@ckeditor/ckeditor5-engine@^34.1.0", "@ckeditor/ckeditor5-engine@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-engine/-/ckeditor5-engine-34.2.0.tgz#449376625bad9e8beea9e89e201dd4fb599fc38f"
+  integrity sha512-9/i6TZ+Sy5T6hnuCtmeLTfwLSY8LaS7qFkW6gsM9NEB+LSSu930GP0Ss30Nw6dYo/JmYiQEpkiRJzKYIjrH8Pg==
   dependencies:
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
     lodash-es "^4.17.15"
 
-"@ckeditor/ckeditor5-enter@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-35.4.0.tgz#c0f967dc3f48faeb07d839ac0426227e118ade56"
-  integrity sha512-y95RnA/Gw72e220PJKVwNbwPzX4SRs82/rXu1jVyJXty7CcEZqqfyRtW6odICAXr5eKI5XKgzFgpFYULL3D9Nw==
-  dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-
-"@ckeditor/ckeditor5-paragraph@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-35.4.0.tgz#db6babd19eb37c66771b7355d0cd0880cb9b599c"
-  integrity sha512-8nhkEEFv1WClhH6q/HW8P596d+dlatSVc46kQ2+jGlYirL8P66tV/nK+OiE8z1d897oVr4QPGsqk2qGkRFUChw==
-  dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
-
-"@ckeditor/ckeditor5-select-all@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-35.4.0.tgz#b7c20e9f686e59497e84825c4786dd874e22d4e2"
-  integrity sha512-c+pIIY77SP6ux4/cyD7cCrllQAqtFVSnzNYdy7ygNPqljCGngCnpSV9xfCO/blFo6/zx2vsmzVGdRq3ArzGoMg==
-  dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
-
-"@ckeditor/ckeditor5-typing@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-35.4.0.tgz#b786032a541cfd102562eb07c21c62e0b6d502c6"
-  integrity sha512-Ad/PHWbVWcnAj9oevkkfLqf6CmvCFOti466uhvfOCKRNVf2+/xuGwleOGr8W6Lir/x/qav7ojFjKPKDxqbPXhA==
-  dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
+"@ckeditor/ckeditor5-enter@^34.1.0", "@ckeditor/ckeditor5-enter@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-enter/-/ckeditor5-enter-34.2.0.tgz#6d90a374396ef05ecde7f6cb0fcd6d3ca38e20b1"
+  integrity sha512-QxaT3jH0qsZaE0Egj1D19o6YBz/EJKs0am5ny5hDnd5sntvIUk9PNGEu/v3mRmNqZqrhRu4BuedvdRzYWseUjw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-engine" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
+
+"@ckeditor/ckeditor5-paragraph@^34.1.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-paragraph/-/ckeditor5-paragraph-34.2.0.tgz#cf981adb76bf40649ce04358674d2c1262b8753a"
+  integrity sha512-xcXUsXz3PY355gJ8u+y0qFLWcScYo0CZPZSbs5YwDz7g9lV8foVVzzdW7ITYwr5/YIpJsjjxYC+dDUqsH6EpBQ==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-ui" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
+
+"@ckeditor/ckeditor5-select-all@^34.1.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-select-all/-/ckeditor5-select-all-34.2.0.tgz#49ca1e239dda9d6045716ebd6707a4cf1a8a6203"
+  integrity sha512-/Va85RwNlmpgQ7vWxiAFLyzXhXrWiA5Pde7yCNcc6hJpqnaGcqvscOJoZLMk5oASTvMnPhQIgNSMDN/oq6ej0Q==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-ui" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
+
+"@ckeditor/ckeditor5-typing@^34.1.0", "@ckeditor/ckeditor5-typing@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-typing/-/ckeditor5-typing-34.2.0.tgz#6f408e671ef5acf526076128f9422a13d914776f"
+  integrity sha512-Eq8mhb8M7RwUmeVUantN+PrqxDELXCvLCcpixy+ge/5lM8wxVcn/SonfUL9PLqs2eluRc4Bx+mstMQySglkVkw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-engine" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
     lodash-es "^4.17.15"
 
-"@ckeditor/ckeditor5-ui@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-35.4.0.tgz#76e59032aee6652c6bd717f30fc330a064b3451e"
-  integrity sha512-0SmYE+k1cYQPqyw2rQsPDV/RpudneBh1bNfiaTOz+rqViJIMe+TxiuK6Fz+znNZ05s0exr+ZHWvMttGqlVoQNw==
+"@ckeditor/ckeditor5-ui@^34.1.0", "@ckeditor/ckeditor5-ui@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-ui/-/ckeditor5-ui-34.2.0.tgz#56a0fe2eb87c2e44b6c6d9440e6b6077a244214c"
+  integrity sha512-XL561G/e3b1YLGHNjLxS9IgoVn4BSugHmidEXYNUTMLATRCKld1XMUKFsB/wm3DwLBUfWn4d2j3qdcO2CnDuBg==
   dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
     lodash-es "^4.17.15"
 
-"@ckeditor/ckeditor5-undo@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-35.4.0.tgz#f79b19be69b8b9ab57592cfe4ec4645b3728b773"
-  integrity sha512-0RhsK0f/pX/7KB/JXYTLiDOswmUTQ9EKIIuewAwr7LTsBf4Q309FZSFdbeTmc0wIyX33212Xh5xsi3LyG1VJRg==
+"@ckeditor/ckeditor5-undo@^34.1.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-undo/-/ckeditor5-undo-34.2.0.tgz#7ea368fc46d4f1f663a2e59cba7390bd90b62017"
+  integrity sha512-WW3f6ku36DpKhUxXACfNFm2DaKcJ2Rz0EFEkol0+offpOjltJnUEJ7LvfOthGdMvGz+5lmnySTbkvOvNruq1Ew==
   dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-engine" "^34.2.0"
+    "@ckeditor/ckeditor5-ui" "^34.2.0"
 
-"@ckeditor/ckeditor5-upload@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-35.4.0.tgz#57944a4e824cdee37bb53d795dbe98055e11d748"
-  integrity sha512-+eJAluAc4mAFmx5FNuSGjkCYmbm0V9NpSleubAXEx2e+KNiLarPAnsolwRaAcYXcloNp4C9/l0D+lPEx7VRYtg==
+"@ckeditor/ckeditor5-upload@^34.1.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-upload/-/ckeditor5-upload-34.2.0.tgz#8a55065bba3e2e3f6134872f0735a4ed0257bf6b"
+  integrity sha512-HBJr0/wFE+R13aIXRF/xJVQqo6Yh34EgbnrNYYhlNiHG40Vr6079eCuoZrnY3vwEsjtFNnTRQ433+RqxJ652zw==
   dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-ui" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
 
-"@ckeditor/ckeditor5-utils@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-35.4.0.tgz#c5c296a2c1883684e674b1a710fcc41b745e156b"
-  integrity sha512-sFjbb+1VYdLbELDLWVYk86WzVN7Lo3sXHbVhdr8+kc0Ufxdr3mTFHDAkiymFt2fs1FOB5gZyWJlJU+EeJnhKUw==
+"@ckeditor/ckeditor5-utils@^34.1.0", "@ckeditor/ckeditor5-utils@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-utils/-/ckeditor5-utils-34.2.0.tgz#d84177671afbc849b0435075f00311f9cc181288"
+  integrity sha512-jHJV2S8DzmpVvd3jdercY6HsGRAwpm/MK79Rs/Mrc3NNYKzN9SVFs/NLbrELNoMZeJ1WKt5BwKgBY+PEOpfyLw==
   dependencies:
     lodash-es "^4.17.15"
 
-"@ckeditor/ckeditor5-widget@^35.4.0":
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-35.4.0.tgz#a80ed4c4f57a1198b47c4e93090f8ebe62f70ecb"
-  integrity sha512-SNYOXXWu7XV1BZET+ar0Cea25836vzNtUqXlDPwBx/jrmK86b8GMbFR99P2bUG0NvtIsH5cSk7XCmnxb4ZQ6wA==
-  dependencies:
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-    "@ckeditor/ckeditor5-enter" "^35.4.0"
-    "@ckeditor/ckeditor5-typing" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
+"@ckeditor/ckeditor5-widget@^34.1.0", "@ckeditor/ckeditor5-widget@^34.2.0":
+  version "34.2.0"
+  resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-widget/-/ckeditor5-widget-34.2.0.tgz#0df140bc4c40287251cf5f5a970f616bdbd470e3"
+  integrity sha512-h2iF/RRK+GjvVHb6VY7+slnIV+IdWdLfZS83OECQNYp2e+6kN/JZp+PxiyYC4asPTraL43zJGzlgT53Jof77vw==
+  dependencies:
+    "@ckeditor/ckeditor5-core" "^34.2.0"
+    "@ckeditor/ckeditor5-engine" "^34.2.0"
+    "@ckeditor/ckeditor5-enter" "^34.2.0"
+    "@ckeditor/ckeditor5-typing" "^34.2.0"
+    "@ckeditor/ckeditor5-ui" "^34.2.0"
+    "@ckeditor/ckeditor5-utils" "^34.2.0"
     lodash-es "^4.17.15"
 
 "@csstools/selector-specificity@^2.0.0":
@@ -736,23 +737,23 @@ chrome-trace-event@^1.0.2:
   resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
   integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
 
-ckeditor5@~35.4.0:
-  version "35.4.0"
-  resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-35.4.0.tgz#0ce67af211551b96856b780e3729481cadbb34df"
-  integrity sha512-vBEQVkFCbjYmEPVkyWsOqU44DOovUio6xBuCwroe4TuJLplqeRasCjFwB0DPknXQU8U0iM3Lh/QSKRyN92pw3Q==
-  dependencies:
-    "@ckeditor/ckeditor5-clipboard" "^35.4.0"
-    "@ckeditor/ckeditor5-core" "^35.4.0"
-    "@ckeditor/ckeditor5-engine" "^35.4.0"
-    "@ckeditor/ckeditor5-enter" "^35.4.0"
-    "@ckeditor/ckeditor5-paragraph" "^35.4.0"
-    "@ckeditor/ckeditor5-select-all" "^35.4.0"
-    "@ckeditor/ckeditor5-typing" "^35.4.0"
-    "@ckeditor/ckeditor5-ui" "^35.4.0"
-    "@ckeditor/ckeditor5-undo" "^35.4.0"
-    "@ckeditor/ckeditor5-upload" "^35.4.0"
-    "@ckeditor/ckeditor5-utils" "^35.4.0"
-    "@ckeditor/ckeditor5-widget" "^35.4.0"
+ckeditor5@~34.1.0:
+  version "34.1.0"
+  resolved "https://registry.yarnpkg.com/ckeditor5/-/ckeditor5-34.1.0.tgz#3bd10c603f877891ee57e210fdd918762e2b865a"
+  integrity sha512-bWcmXEx4C7AC+FywiTrhbs63mUc8vwEualSDzyJIZLd5HULLznqJwjeON/icKtzCiBLEeUFoeDHLC5yWAEj8sA==
+  dependencies:
+    "@ckeditor/ckeditor5-clipboard" "^34.1.0"
+    "@ckeditor/ckeditor5-core" "^34.1.0"
+    "@ckeditor/ckeditor5-engine" "^34.1.0"
+    "@ckeditor/ckeditor5-enter" "^34.1.0"
+    "@ckeditor/ckeditor5-paragraph" "^34.1.0"
+    "@ckeditor/ckeditor5-select-all" "^34.1.0"
+    "@ckeditor/ckeditor5-typing" "^34.1.0"
+    "@ckeditor/ckeditor5-ui" "^34.1.0"
+    "@ckeditor/ckeditor5-undo" "^34.1.0"
+    "@ckeditor/ckeditor5-upload" "^34.1.0"
+    "@ckeditor/ckeditor5-utils" "^34.1.0"
+    "@ckeditor/ckeditor5-widget" "^34.1.0"
 
 clean-stack@^2.0.0:
   version "2.2.0"
@@ -2586,4 +2587,4 @@ yaml@^1.10.0, yaml@^1.10.2:
 yocto-queue@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
-  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
\ No newline at end of file
+  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-- 
GitLab


From e891499204b0979028eca44532e0b111dcc694d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 23 Feb 2023 14:50:59 +0100
Subject: [PATCH 06/19] WIP, see @todo for lasting work

---
 .../js/build/videoEmbed.js                    |  2 +-
 .../videoEmbed/src/insertvideoembedcommand.js | 24 +++----
 .../videoEmbed/src/videoembedediting.js       | 65 ++++++++++++++-----
 .../videoEmbed/src/videoembedui.js            | 41 +++++++++---
 .../video_embed_wysiwyg.libraries.yml         |  3 +
 5 files changed, 96 insertions(+), 39 deletions(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index 6f05a06..28adbef 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":()=>{eval('throw new Error("Module parse failed: Unexpected token (61:4)\\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders\\n|       // @todo register allowed model attributes.\\n|       allowAttributes:\\n>     });\\n|   }\\n| ");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract it's values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo adapt this copy-pasted code.\n      existingValues = selectedVideoEmbedElement.hasAttribute('data-entity-uuid') ? {\n        'data-entity-uuid': selectedVideoEmbedElement.getAttribute('data-entity-uuid'),\n        'data-entity-type': selectedVideoEmbedElement.getAttribute('data-entity-type'),\n      } : {};\n    }\n\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        ({attributes}) => {\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adopted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var _=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](_,_.exports,__webpack_require__),_.exports}__webpack_require__.d=(e,t)=>{for(var _ in t)__webpack_require__.o(t,_)&&!__webpack_require__.o(e,_)&&Object.defineProperty(e,_,{enumerable:!0,get:t[_]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    console.log('command execution');\n    console.log(attributes);\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\nconsole.log('createVideoEmbed');\nconsole.log(videoEmbed);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this \"text\":\n * {\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If {\"preview_thumbnail\":......} is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js\n    //conversion.for('upcast').[...]\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // {\"preview_thumbnail\":......}.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        return writer.createText(JSON.stringify(data));\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    console.log('calling this._openDialog');\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          console.log('attributes:');\n          console.log(attributes);\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    console.log('_openDialog');\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    console.log('ckeditorAjaxDialog.execute()');\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    console.log('storing the right callback');\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
index 97ad84a..ff01ffd 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
@@ -3,22 +3,24 @@
  * toolbar button is pressed.
  */
 
-import { Command } from 'ckeditor5/src/core';
+import {Command} from 'ckeditor5/src/core';
 
 export default class InsertVideoEmbedCommand extends Command {
-  execute() {
-    const { model } = this.editor;
+  execute(attributes) {
+    console.log('command execution');
+    console.log(attributes);
+    const {model} = this.editor;
 
     model.change((writer) => {
-      // Insert <videoEmbed * /> at the current selection position
+      // Insert <videoEmbed *></videoEmbed> at the current selection position
       // in a way that will result in creating a valid model structure.
-      model.insertContent(createVideoEmbed(writer));
+      model.insertContent(createVideoEmbed(writer, attributes));
     });
   }
 
   refresh() {
-    const { model } = this.editor;
-    const { selection } = model.document;
+    const {model} = this.editor;
+    const {selection} = model.document;
 
     // Determine if the cursor (selection) is in a position where adding a
     // videoEmbed is permitted. This is based on the schema of the model(s)
@@ -34,12 +36,12 @@ export default class InsertVideoEmbedCommand extends Command {
   }
 }
 
-function createVideoEmbed(writer) {
+function createVideoEmbed(writer, attributes) {
   // Create instances of the element registered with the editor in
   // videoembedediting.js.
-  const videoEmbed = writer.createElement('videoEmbed');
-
-  // @todo
+  const videoEmbed = writer.createElement('videoEmbed', attributes);
+console.log('createVideoEmbed');
+console.log(videoEmbed);
 
   // Return the element to be added to the editor.
   return videoEmbed;
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
index 8fd9b0b..23a878b 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -1,6 +1,6 @@
-import { Plugin } from 'ckeditor5/src/core';
-import { toWidget, toWidgetEditable } from 'ckeditor5/src/widget';
-import { Widget } from 'ckeditor5/src/widget';
+import {Plugin} from 'ckeditor5/src/core';
+import {toWidget, toWidgetEditable} from 'ckeditor5/src/widget';
+import {Widget} from 'ckeditor5/src/widget';
 import InsertVideoEmbedCommand from './insertvideoembedcommand';
 
 
@@ -10,11 +10,15 @@ import InsertVideoEmbedCommand from './insertvideoembedcommand';
  * is inserted in the DOM.
  *
  * CKEditor 5 internally interacts with videoEmbed as this model:
- * @todo List attributes in this doc.
- * <videoEmbed />
+ * <videoEmbed videoUrl="https://some.video.url" responsive="trueorfalse"
+ * width="42" height="42" autoplay="trueorfalse"
+ * previewThumbnail="/some/image/path.jpg" settingsSummary="Some help
+ * text."></videoEmbed>
  *
- * Which is converted in database (dataDowncast) as this markup:
- * <p>{"video_url":"https://some.video.url","settings":{"responsive":0or1,"width":"42","height":"42","autoplay":0or1}}</p>
+ * Which is converted in database (dataDowncast) as this "text":
+ * {"preview_thumbnail":"/some/image/path.jpg",
+ * "video_url":"https://some.video.url","settings":{"responsive":0or1,"width":"42","height":"42","autoplay":0or1}",
+ * settings_summary":["Some help text."]}
  *
  * The Drupal video_embed_wysiwyg format filter will then convert this into a
  * real HTML video embed, on PHP frontend rendering.
@@ -43,7 +47,7 @@ export default class VideoEmbedEditing extends Plugin {
 
   /*
    * This registers the structure that will be seen by CKEditor 5 as
-   * <videoEmbed .../>
+   * <videoEmbed *></videoEmbed>
    *
    * The logic in _defineConverters() will determine how this is converted to
    * markup.
@@ -53,11 +57,9 @@ export default class VideoEmbedEditing extends Plugin {
     const schema = this.editor.model.schema;
 
 
-
     schema.register('videoEmbed', {
       inheritAllFrom: '$blockObject',
-      // @todo register allowed model attributes.
-      // allowAttributes:
+      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']
     });
   }
 
@@ -67,12 +69,12 @@ export default class VideoEmbedEditing extends Plugin {
    */
   _defineConverters() {
     // Converters are registered via the central editor object.
-    const { conversion } = this.editor;
+    const {conversion} = this.editor;
 
     // Upcast Converters: determine how existing HTML is interpreted by the
     // editor. These trigger when an editor instance loads.
     //
-    // If {"video_url":...} is present in the existing markup
+    // If {"preview_thumbnail":......} is present in the existing markup
     // processed by CKEditor, then CKEditor recognizes and loads it as a
     // <videoEmbed> model.
     // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
@@ -83,9 +85,21 @@ export default class VideoEmbedEditing extends Plugin {
     // These trigger when content is saved.
     //
     // Instances of <videoEmbed> are saved as
-    // <p>{{"video_url":...}</p>.
-    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
-    //conversion.for('dataDowncast').[...]
+    // {"preview_thumbnail":......}.
+    conversion.for('dataDowncast').elementToElement({
+      model: 'videoEmbed',
+      view: (modelElement, {writer}) => {
+        const data = {};
+        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');
+        data.video_url = modelElement.getAttribute('videoUrl');
+        data.settings = {};
+        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {
+          data.settings[attributeName] = modelElement.getAttribute(attributeName);
+        });
+        data.settings_summary = [modelElement.getAttribute('settingsSummary')];
+        return writer.createText(JSON.stringify(data));
+      }
+    });
 
 
     // Editing Downcast Converters. These render the content to the user for
@@ -94,8 +108,23 @@ export default class VideoEmbedEditing extends Plugin {
     // are changes to any of the models' properties.
     //
     // Convert the <videoEmbed> model into a container widget in the editor UI.
-    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
-    //conversion.for('editingDowncast').[...]
+    conversion.for('editingDowncast').elementToElement({
+          model: 'videoEmbed',
+          view: (modelElement, {writer}) => {
+            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [
+              writer.createEmptyElement('img', {
+                class: 'video-embed-widget__image',
+                src: modelElement.getAttribute('previewThumbnail')
+              }),
+              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [
+                writer.createText(modelElement.getAttribute('settingsSummary'))
+              ])
+            ]);
+
+            return toWidget(preview, writer, {label: Drupal.t('Video Embed')});
+          }
+        }
+    );
   }
 }
 
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
index dab160d..6367950 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
@@ -48,20 +48,40 @@ export default class VideoEmbedUI extends Plugin {
     // If the selected element while we click the button is an instance
     // of the video_embed widget, extract its values so they can be
     // sent to the server to prime the configuration form.
-    let existingValues = {};
+    let existingValues = {settings: {}};
     const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()
     if (selectedVideoEmbedElement) {
-      // @todo adapt this copy-pasted code.
-      existingValues = selectedVideoEmbedElement.hasAttribute('data-entity-uuid') ? {
-        'data-entity-uuid': selectedVideoEmbedElement.getAttribute('data-entity-uuid'),
-        'data-entity-type': selectedVideoEmbedElement.getAttribute('data-entity-type'),
-      } : {};
+      // @todo ensure this is the right way to implement this (ensure the
+      // element is indeed a model one, not a view one).
+      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {
+        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');
+      }
+      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {
+        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {
+          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);
+        }
+      });
     }
-
+    console.log('calling this._openDialog');
     this._openDialog(
         Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),
         existingValues,
-        ({attributes}) => {
+        (newValues) => {
+
+          const attributes = {
+            videoUrl: newValues.video_url,
+            responsive: newValues.settings.responsive,
+            width: newValues.settings.width,
+            height: newValues.settings.height,
+            autoplay: newValues.settings.autoplay,
+            // These attributes are useful only for editor preview, but are
+            // keeped on dataDowncast so that they can be retrieved on later
+            // upcast+editingDowncast.
+            settingsSummary: newValues.settings_summary[0],
+            previewThumbnail: newValues.preview_thumbnail,
+          }
+          console.log('attributes:');
+          console.log(attributes);
           editor.execute('insertVideoEmbed', attributes);
         },
         {
@@ -82,7 +102,7 @@ export default class VideoEmbedUI extends Plugin {
   }
 
   /**
-   * This method is adopted from drupal's ckeditor5.js file due to an issue
+   * This method is adapted from drupal's ckeditor5.js file due to an issue
    * where the "editor_object" isn't passed to the ajax request.
    *
    * See https://www.drupal.org/project/drupal/issues/3303191
@@ -98,6 +118,7 @@ export default class VideoEmbedUI extends Plugin {
    *   An object containing settings to be passed to the jQuery UI.
    */
   _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {
+    console.log('_openDialog');
     // Add a consistent dialog class.
     const classes = dialogSettings.dialogClass
         ? dialogSettings.dialogClass.split(' ')
@@ -118,9 +139,11 @@ export default class VideoEmbedUI extends Plugin {
         editor_object: existingValues,
       },
     });
+    console.log('ckeditorAjaxDialog.execute()');
     ckeditorAjaxDialog.execute();
 
     // Store the save callback to be executed when this dialog is closed.
+    console.log('storing the right callback');
     Drupal.ckeditor5.saveCallback = saveCallback;
   }
 
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml b/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml
index 0b134bf..13c3a4d 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.libraries.yml
@@ -1,6 +1,9 @@
 video_embed:
   js:
     js/build/videoEmbed.js: { preprocess: false, minified: true }
+  css:
+    theme:
+      plugin/plugin.css: { }
   dependencies:
     - core/ckeditor5
 
-- 
GitLab


From 6dfc028186507398d06d4e85a95a7a2ac356a5e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 2 Mar 2023 18:00:26 +0100
Subject: [PATCH 07/19] WIP, see @todo for lasting work

---
 .../js/build/videoEmbed.js                    |  2 +-
 .../videoEmbed/src/videoembedediting.js       | 41 +++++++++++++++----
 2 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index 28adbef..069d21e 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    console.log('command execution');\n    console.log(attributes);\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\nconsole.log('createVideoEmbed');\nconsole.log(videoEmbed);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this \"text\":\n * {\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If {\"preview_thumbnail\":......} is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js\n    //conversion.for('upcast').[...]\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // {\"preview_thumbnail\":......}.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        return writer.createText(JSON.stringify(data));\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    console.log('calling this._openDialog');\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          console.log('attributes:');\n          console.log(attributes);\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    console.log('_openDialog');\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    console.log('ckeditorAjaxDialog.execute()');\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    console.log('storing the right callback');\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    console.log('command execution');\n    console.log(attributes);\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\nconsole.log('createVideoEmbed');\nconsole.log(videoEmbed);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n\n    const pattern = function (element) {\n      if (element.name === 'p') {\n        if (element.getChild(0).is('text')) {\n          // @todo debug this:\n          let text = element.getChild(0).data;\n          console.log('text:');console.log(text);\n          if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n            console.log('data:');console.log(data);\n            return {name: true};\n          }\n        }\n      }\n\n      return null;\n    };\n\n    conversion.for('upcast').elementToElement({\n      view: pattern,\n      // @todo convert json text to model attributes\n      model: 'videoEmbed',\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        let p = writer.createElement('paragraph');\n        writer.insertText(JSON.stringify(data), p);\n        return p;\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    console.log('calling this._openDialog');\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          console.log('attributes:');\n          console.log(attributes);\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    console.log('_openDialog');\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    console.log('ckeditorAjaxDialog.execute()');\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    console.log('storing the right callback');\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
index 23a878b..1b960c7 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -15,10 +15,10 @@ import InsertVideoEmbedCommand from './insertvideoembedcommand';
  * previewThumbnail="/some/image/path.jpg" settingsSummary="Some help
  * text."></videoEmbed>
  *
- * Which is converted in database (dataDowncast) as this "text":
- * {"preview_thumbnail":"/some/image/path.jpg",
+ * Which is converted in database (dataDowncast) as this:
+ * <p>{"preview_thumbnail":"/some/image/path.jpg",
  * "video_url":"https://some.video.url","settings":{"responsive":0or1,"width":"42","height":"42","autoplay":0or1}",
- * settings_summary":["Some help text."]}
+ * settings_summary":["Some help text."]}</p>
  *
  * The Drupal video_embed_wysiwyg format filter will then convert this into a
  * real HTML video embed, on PHP frontend rendering.
@@ -74,18 +74,40 @@ export default class VideoEmbedEditing extends Plugin {
     // Upcast Converters: determine how existing HTML is interpreted by the
     // editor. These trigger when an editor instance loads.
     //
-    // If {"preview_thumbnail":......} is present in the existing markup
+    // If <p>{"preview_thumbnail":......}</p> is present in the existing markup
     // processed by CKEditor, then CKEditor recognizes and loads it as a
     // <videoEmbed> model.
-    // @todo Implement this, see video_embed_wysiwyg/plugin/plugin.js
-    //conversion.for('upcast').[...]
+
+    const pattern = function (element) {
+      if (element.name === 'p') {
+        if (element.getChild(0).is('text')) {
+          // @todo debug this:
+          let text = element.getChild(0).data;
+          console.log('text:');console.log(text);
+          if (text.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/)) {
+            console.log('data:');console.log(data);
+            return {name: true};
+          }
+        }
+      }
+
+      return null;
+    };
+
+    conversion.for('upcast').elementToElement({
+      view: pattern,
+      // @todo convert json text to model attributes
+      model: 'videoEmbed',
+      // Avoid it's converted to a normal paragraph.
+      converterPriority: 'high'
+    });
 
 
     // Data Downcast Converters: converts stored model data into HTML.
     // These trigger when content is saved.
     //
     // Instances of <videoEmbed> are saved as
-    // {"preview_thumbnail":......}.
+    // <p>{"preview_thumbnail":......}</p>.
     conversion.for('dataDowncast').elementToElement({
       model: 'videoEmbed',
       view: (modelElement, {writer}) => {
@@ -97,7 +119,9 @@ export default class VideoEmbedEditing extends Plugin {
           data.settings[attributeName] = modelElement.getAttribute(attributeName);
         });
         data.settings_summary = [modelElement.getAttribute('settingsSummary')];
-        return writer.createText(JSON.stringify(data));
+        let p = writer.createElement('paragraph');
+        writer.insertText(JSON.stringify(data), p);
+        return p;
       }
     });
 
@@ -127,4 +151,3 @@ export default class VideoEmbedEditing extends Plugin {
     );
   }
 }
-
-- 
GitLab


From 56b997d3dfbdab3437c42d290eede597545733c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 9 Mar 2023 18:12:28 +0100
Subject: [PATCH 08/19] WIP, see @todo for lasting work

---
 .../js/build/videoEmbed.js                    |  2 +-
 .../videoEmbed/src/videoembedediting.js       | 45 +++++++++++--------
 2 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index 069d21e..c4956ee 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    console.log('command execution');\n    console.log(attributes);\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\nconsole.log('createVideoEmbed');\nconsole.log(videoEmbed);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n\n    const pattern = function (element) {\n      if (element.name === 'p') {\n        if (element.getChild(0).is('text')) {\n          // @todo debug this:\n          let text = element.getChild(0).data;\n          console.log('text:');console.log(text);\n          if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n            console.log('data:');console.log(data);\n            return {name: true};\n          }\n        }\n      }\n\n      return null;\n    };\n\n    conversion.for('upcast').elementToElement({\n      view: pattern,\n      // @todo convert json text to model attributes\n      model: 'videoEmbed',\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        let p = writer.createElement('paragraph');\n        writer.insertText(JSON.stringify(data), p);\n        return p;\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    console.log('calling this._openDialog');\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          console.log('attributes:');\n          console.log(attributes);\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    console.log('_openDialog');\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    console.log('ckeditorAjaxDialog.execute()');\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    console.log('storing the right callback');\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    console.log('command execution');\n    console.log(attributes);\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\nconsole.log('createVideoEmbed');\nconsole.log(videoEmbed);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @todo debug error in console at upcast (it works if I remove upcast\n    //  conversion).\n    // @see https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html\n    conversion.for('upcast').elementToElement({\n      view: function (element) {\n        if (element.name === 'p') {\n          if (element.getChild(0).is('text')) {\n            let text = element.getChild(0).data;\n            if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n              return {name: true};\n            }\n          }\n        }\n        return null;\n      },\n      model: (viewElement, {writer}) => {\n        let data = JSON.parse(viewElement.getChild(0).data);\n        return writer.createElement('videoEmbed',\n            {\n              'videoUrl': data.video_url,\n              'responsive': !!data.settings.responsive,\n              'width': data.settings.width,\n              'height': data.settings.height,\n              'autoplay': !!data.settings.autoplay,\n              'previewThumbnail': data.preview_thumbnail,\n              'settingsSummary': data.settings_summary,\n            });\n      },\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        let p = writer.createElement('paragraph');\n        writer.insertText(JSON.stringify(data), p);\n        return p;\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    console.log('calling this._openDialog');\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          console.log('attributes:');\n          console.log(attributes);\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    console.log('_openDialog');\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    console.log('ckeditorAjaxDialog.execute()');\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    console.log('storing the right callback');\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
index 1b960c7..f0dd37e 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -77,27 +77,34 @@ export default class VideoEmbedEditing extends Plugin {
     // If <p>{"preview_thumbnail":......}</p> is present in the existing markup
     // processed by CKEditor, then CKEditor recognizes and loads it as a
     // <videoEmbed> model.
-
-    const pattern = function (element) {
-      if (element.name === 'p') {
-        if (element.getChild(0).is('text')) {
-          // @todo debug this:
-          let text = element.getChild(0).data;
-          console.log('text:');console.log(text);
-          if (text.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/)) {
-            console.log('data:');console.log(data);
-            return {name: true};
+    // @todo debug error in console at upcast (it works if I remove upcast
+    //  conversion).
+    // @see https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html
+    conversion.for('upcast').elementToElement({
+      view: function (element) {
+        if (element.name === 'p') {
+          if (element.getChild(0).is('text')) {
+            let text = element.getChild(0).data;
+            if (text.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/)) {
+              return {name: true};
+            }
           }
         }
-      }
-
-      return null;
-    };
-
-    conversion.for('upcast').elementToElement({
-      view: pattern,
-      // @todo convert json text to model attributes
-      model: 'videoEmbed',
+        return null;
+      },
+      model: (viewElement, {writer}) => {
+        let data = JSON.parse(viewElement.getChild(0).data);
+        return writer.createElement('videoEmbed',
+            {
+              'videoUrl': data.video_url,
+              'responsive': !!data.settings.responsive,
+              'width': data.settings.width,
+              'height': data.settings.height,
+              'autoplay': !!data.settings.autoplay,
+              'previewThumbnail': data.preview_thumbnail,
+              'settingsSummary': data.settings_summary,
+            });
+      },
       // Avoid it's converted to a normal paragraph.
       converterPriority: 'high'
     });
-- 
GitLab


From a66f421ab5714f0df12647fdf76d819c3f852181 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 16 Mar 2023 11:11:06 +0100
Subject: [PATCH 09/19] WIP, see @todo for lasting work

---
 modules/video_embed_wysiwyg/js/build/videoEmbed.js   |  2 +-
 .../js/ckeditor5_plugins/videoEmbed/src/index.js     |  1 -
 .../videoEmbed/src/insertvideoembedcommand.js        |  4 ----
 .../videoEmbed/src/videoembedediting.js              | 12 ++++--------
 .../ckeditor5_plugins/videoEmbed/src/videoembedui.js |  8 --------
 5 files changed, 5 insertions(+), 22 deletions(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index c4956ee..0040b53 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n// @todo Remove console.log calls.\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    console.log('command execution');\n    console.log(attributes);\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\nconsole.log('createVideoEmbed');\nconsole.log(videoEmbed);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @todo debug error in console at upcast (it works if I remove upcast\n    //  conversion).\n    // @see https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html\n    conversion.for('upcast').elementToElement({\n      view: function (element) {\n        if (element.name === 'p') {\n          if (element.getChild(0).is('text')) {\n            let text = element.getChild(0).data;\n            if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n              return {name: true};\n            }\n          }\n        }\n        return null;\n      },\n      model: (viewElement, {writer}) => {\n        let data = JSON.parse(viewElement.getChild(0).data);\n        return writer.createElement('videoEmbed',\n            {\n              'videoUrl': data.video_url,\n              'responsive': !!data.settings.responsive,\n              'width': data.settings.width,\n              'height': data.settings.height,\n              'autoplay': !!data.settings.autoplay,\n              'previewThumbnail': data.preview_thumbnail,\n              'settingsSummary': data.settings_summary,\n            });\n      },\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        let p = writer.createElement('paragraph');\n        writer.insertText(JSON.stringify(data), p);\n        return p;\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            console.log('button execution');\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    console.log('dialog opening');\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    console.log('calling this._openDialog');\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          console.log('attributes:');\n          console.log(attributes);\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    console.log('_openDialog');\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    console.log('ckeditorAjaxDialog.execute()');\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    console.log('storing the right callback');\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @see\n    // https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html\n    conversion.for('upcast').elementToElement({\n      view: function (element) {\n        if (element.name === 'p') {\n          if (element.getChild(0).is('text')) {\n            let text = element.getChild(0).data;\n            if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n              return {name: true};\n            }\n          }\n        }\n        return null;\n      },\n      model: (viewElement, {writer}) => {\n        let data = JSON.parse(viewElement.getChild(0).data);\n        return writer.createElement('videoEmbed',\n            {\n              'videoUrl': data.video_url,\n              'responsive': !!data.settings.responsive,\n              'width': data.settings.width,\n              'height': data.settings.height,\n              'autoplay': !!data.settings.autoplay,\n              'previewThumbnail': data.preview_thumbnail,\n              'settingsSummary': data.settings_summary[0],\n            });\n      },\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        return writer.createContainerElement('p', {}, [writer.createText(JSON.stringify(data))]);\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
index d56de08..6fcd277 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/index.js
@@ -1,6 +1,5 @@
 import VideoEmbed from './videoembed';
 
-// @todo Remove console.log calls.
 export default {
   VideoEmbed,
 };
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
index ff01ffd..71126f7 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js
@@ -7,8 +7,6 @@ import {Command} from 'ckeditor5/src/core';
 
 export default class InsertVideoEmbedCommand extends Command {
   execute(attributes) {
-    console.log('command execution');
-    console.log(attributes);
     const {model} = this.editor;
 
     model.change((writer) => {
@@ -40,8 +38,6 @@ function createVideoEmbed(writer, attributes) {
   // Create instances of the element registered with the editor in
   // videoembedediting.js.
   const videoEmbed = writer.createElement('videoEmbed', attributes);
-console.log('createVideoEmbed');
-console.log(videoEmbed);
 
   // Return the element to be added to the editor.
   return videoEmbed;
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
index f0dd37e..38918a9 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -77,9 +77,8 @@ export default class VideoEmbedEditing extends Plugin {
     // If <p>{"preview_thumbnail":......}</p> is present in the existing markup
     // processed by CKEditor, then CKEditor recognizes and loads it as a
     // <videoEmbed> model.
-    // @todo debug error in console at upcast (it works if I remove upcast
-    //  conversion).
-    // @see https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html
+    // @see
+    // https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html
     conversion.for('upcast').elementToElement({
       view: function (element) {
         if (element.name === 'p') {
@@ -102,7 +101,7 @@ export default class VideoEmbedEditing extends Plugin {
               'height': data.settings.height,
               'autoplay': !!data.settings.autoplay,
               'previewThumbnail': data.preview_thumbnail,
-              'settingsSummary': data.settings_summary,
+              'settingsSummary': data.settings_summary[0],
             });
       },
       // Avoid it's converted to a normal paragraph.
@@ -126,9 +125,7 @@ export default class VideoEmbedEditing extends Plugin {
           data.settings[attributeName] = modelElement.getAttribute(attributeName);
         });
         data.settings_summary = [modelElement.getAttribute('settingsSummary')];
-        let p = writer.createElement('paragraph');
-        writer.insertText(JSON.stringify(data), p);
-        return p;
+        return writer.createContainerElement('p', {}, [writer.createText(JSON.stringify(data))]);
       }
     });
 
@@ -151,7 +148,6 @@ export default class VideoEmbedEditing extends Plugin {
                 writer.createText(modelElement.getAttribute('settingsSummary'))
               ])
             ]);
-
             return toWidget(preview, writer, {label: Drupal.t('Video Embed')});
           }
         }
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
index 6367950..5554a6c 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
@@ -29,7 +29,6 @@ export default class VideoEmbedUI extends Plugin {
 
       // Execute the command when the button is clicked (executed).
       this.listenTo(buttonView, 'execute', () => {
-            console.log('button execution');
             this.openEditingDialog();
           }
       );
@@ -42,7 +41,6 @@ export default class VideoEmbedUI extends Plugin {
    * Opens video embed form when the editing button is clicked.
    */
   openEditingDialog() {
-    console.log('dialog opening');
     const {editor} = this;
 
     // If the selected element while we click the button is an instance
@@ -62,7 +60,6 @@ export default class VideoEmbedUI extends Plugin {
         }
       });
     }
-    console.log('calling this._openDialog');
     this._openDialog(
         Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),
         existingValues,
@@ -80,8 +77,6 @@ export default class VideoEmbedUI extends Plugin {
             settingsSummary: newValues.settings_summary[0],
             previewThumbnail: newValues.preview_thumbnail,
           }
-          console.log('attributes:');
-          console.log(attributes);
           editor.execute('insertVideoEmbed', attributes);
         },
         {
@@ -118,7 +113,6 @@ export default class VideoEmbedUI extends Plugin {
    *   An object containing settings to be passed to the jQuery UI.
    */
   _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {
-    console.log('_openDialog');
     // Add a consistent dialog class.
     const classes = dialogSettings.dialogClass
         ? dialogSettings.dialogClass.split(' ')
@@ -139,11 +133,9 @@ export default class VideoEmbedUI extends Plugin {
         editor_object: existingValues,
       },
     });
-    console.log('ckeditorAjaxDialog.execute()');
     ckeditorAjaxDialog.execute();
 
     // Store the save callback to be executed when this dialog is closed.
-    console.log('storing the right callback');
     Drupal.ckeditor5.saveCallback = saveCallback;
   }
 
-- 
GitLab


From 690ba9a16a1f4f6ff4c2fa1d577d89efa3e45bb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 16 Mar 2023 11:26:19 +0100
Subject: [PATCH 10/19] WIP, see @todo for lasting work

---
 .../video_embed_wysiwyg/js/build/videoEmbed.js |  2 +-
 .../videoEmbed/src/videoembedui.js             | 18 +++---------------
 2 files changed, 4 insertions(+), 16 deletions(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index 0040b53..8958a01 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @see\n    // https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html\n    conversion.for('upcast').elementToElement({\n      view: function (element) {\n        if (element.name === 'p') {\n          if (element.getChild(0).is('text')) {\n            let text = element.getChild(0).data;\n            if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n              return {name: true};\n            }\n          }\n        }\n        return null;\n      },\n      model: (viewElement, {writer}) => {\n        let data = JSON.parse(viewElement.getChild(0).data);\n        return writer.createElement('videoEmbed',\n            {\n              'videoUrl': data.video_url,\n              'responsive': !!data.settings.responsive,\n              'width': data.settings.width,\n              'height': data.settings.height,\n              'autoplay': !!data.settings.autoplay,\n              'previewThumbnail': data.preview_thumbnail,\n              'settingsSummary': data.settings_summary[0],\n            });\n      },\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        return writer.createContainerElement('p', {}, [writer.createText(JSON.stringify(data))]);\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()\n    if (selectedVideoEmbedElement) {\n      // @todo ensure this is the right way to implement this (ensure the\n      // element is indeed a model one, not a view one).\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * @todo Return the focused videoEmbed element (the cke5 widget system may\n   * help with that).\n   *\n   * @private\n   */\n  _getSelectedVideoEmbedElement() {\n    return null;\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @see\n    // https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html\n    conversion.for('upcast').elementToElement({\n      view: function (element) {\n        if (element.name === 'p') {\n          if (element.getChild(0).is('text')) {\n            let text = element.getChild(0).data;\n            if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n              return {name: true};\n            }\n          }\n        }\n        return null;\n      },\n      model: (viewElement, {writer}) => {\n        let data = JSON.parse(viewElement.getChild(0).data);\n        return writer.createElement('videoEmbed',\n            {\n              'videoUrl': data.video_url,\n              'responsive': !!data.settings.responsive,\n              'width': data.settings.width,\n              'height': data.settings.height,\n              'autoplay': !!data.settings.autoplay,\n              'previewThumbnail': data.preview_thumbnail,\n              'settingsSummary': data.settings_summary[0],\n            });\n      },\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        return writer.createContainerElement('p', {}, [writer.createText(JSON.stringify(data))]);\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = editor.model.document.selection.getSelectedElement();\n    if (selectedVideoEmbedElement) {\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings[attributeName] = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
index 5554a6c..ecd5411 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedui.js
@@ -47,16 +47,14 @@ export default class VideoEmbedUI extends Plugin {
     // of the video_embed widget, extract its values so they can be
     // sent to the server to prime the configuration form.
     let existingValues = {settings: {}};
-    const selectedVideoEmbedElement = this._getSelectedVideoEmbedElement()
+    const selectedVideoEmbedElement = editor.model.document.selection.getSelectedElement();
     if (selectedVideoEmbedElement) {
-      // @todo ensure this is the right way to implement this (ensure the
-      // element is indeed a model one, not a view one).
       if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {
         existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');
       }
-      ['responsive', 'width', 'height', 'autoplay'].foreach(function (attributeName) {
+      ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {
         if (selectedVideoEmbedElement.hasAttribute(attributeName)) {
-          existingValues.settings.attributeName = selectedVideoEmbedElement.getAttribute(attributeName);
+          existingValues.settings[attributeName] = selectedVideoEmbedElement.getAttribute(attributeName);
         }
       });
     }
@@ -86,16 +84,6 @@ export default class VideoEmbedUI extends Plugin {
     );
   }
 
-  /**
-   * @todo Return the focused videoEmbed element (the cke5 widget system may
-   * help with that).
-   *
-   * @private
-   */
-  _getSelectedVideoEmbedElement() {
-    return null;
-  }
-
   /**
    * This method is adapted from drupal's ckeditor5.js file due to an issue
    * where the "editor_object" isn't passed to the ajax request.
-- 
GitLab


From abb6ee35f659820f34497abf0310bd6a10341dd4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 16 Mar 2023 17:17:52 +0100
Subject: [PATCH 11/19] WIP, see @todo for lasting work

---
 .../schema/video_embed_wysiwyg.schema.yml     | 25 ++++++
 .../CKEditor5Plugin/VideoEmbedWysiwyg.php     | 79 ++++++++++++++-----
 .../video_embed_wysiwyg.module                |  3 +-
 3 files changed, 85 insertions(+), 22 deletions(-)

diff --git a/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml b/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml
index f571d64..ee27f6b 100644
--- a/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml
+++ b/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml
@@ -22,3 +22,28 @@ ckeditor.plugin.video_embed:
             height:
               label: 'Height'
               type: string
+
+ckeditor5.plugin.video_embed_wysiwyg_video_embed:
+  label: 'Video Embed'
+  type: mapping
+  mapping:
+      defaults:
+        label: 'Defaults'
+        type: mapping
+        mapping:
+          children:
+            label: 'Children'
+            type: mapping
+            mapping:
+              autoplay:
+                label: 'Autoplay'
+                type: boolean
+              responsive:
+                label: 'Responsive'
+                type: boolean
+              width:
+                label: 'Width'
+                type: string
+              height:
+                label: 'Height'
+                type: string
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
index 13f1f19..5335f2b 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
@@ -4,40 +4,79 @@ declare(strict_types=1);
 
 namespace Drupal\video_embed_wysiwyg\Plugin\CKEditor5Plugin;
 
+use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableInterface;
 use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableTrait;
 use Drupal\ckeditor5\Plugin\CKEditor5PluginDefault;
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\EditorInterface;
+use Drupal\video_embed_field\Plugin\Field\FieldFormatter\Video;
 
-/**
- * This class transmits the Drupal config to the javascript plugin.
- *
- * @todo Add the settings form for the plugin.
- */
-class VideoEmbedWysiwyg extends CKEditor5PluginDefault {
+class VideoEmbedWysiwyg extends CKEditor5PluginDefault implements CKEditor5PluginConfigurableInterface {
 
   use CKEditor5PluginConfigurableTrait;
 
   /**
-   * @param mixed[] $static_plugin_config
-   * @param \Drupal\editor\EditorInterface $editor
-   *
-   * @return mixed[]
+   * @inheritDoc
    */
   public function getDynamicPluginConfig(array $static_plugin_config, EditorInterface $editor): array {
-    $plugin_config = [
-      'format' => $editor->id(),
-    ];
-    $format = $editor->getFilterFormat();
-    /** @var \Drupal\filter\Plugin\FilterInterface $filter */
-    $filter = $format->filters('video_embed_wysiwyg');
-    $filter_config = $filter->getConfiguration();
-    $plugin_config += $filter_config['settings'];
+    // Transmit some useful Drupal data to the javascript plugin.
     $parent_config = parent::getDynamicPluginConfig($static_plugin_config, $editor);
-    // @todo Ensure this is the info the plugin needs.
     return array_merge_recursive($parent_config,
       [
-        'videoEmbed' => $plugin_config,
+        'videoEmbed' => [
+          // Used by VideoEmbedUi.openEditingDialog().
+          'format' => $editor->id(),
+        ],
       ]);
   }
 
+  /**
+   * @inheritDoc
+   */
+  public function defaultConfiguration(): array {
+    return [
+      'defaults' => [
+        'children' => [
+          'autoplay' => FALSE,
+          'responsive' => FALSE,
+          'width' => '',
+          'height' => '',
+        ],
+      ],
+    ];
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
+    $form['defaults'] = [
+      '#title' => $this->t('Default Settings'),
+      '#type' => 'fieldset',
+      '#tree' => TRUE,
+      'children' => Video::mockInstance($this->configuration['defaults']['children'])
+        ->settingsForm([], new FormState()),
+    ];
+    return $form;
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void {
+    $value = $form_state->getValue('defaults');
+    $value['children']['autoplay'] = (bool) $value['children']['autoplay'];
+    $value['children']['responsive'] = (bool) $value['children']['responsive'];
+    $form_state->setValue('defaults', $value);
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
+    $this->configuration['defaults'] = $form_state->getValue('defaults');
+  }
+
+
 }
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
index 223cc9a..a79ca60 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
@@ -3,8 +3,7 @@
 /**
  * @file
  * Module file for video_embed_wysiwyg.
- * @todo test and fix CKE5 plugin.
- * @todo CKE5 upgrade path if needed.
+ * @todo CKE5 upgrade path for plugin config.
  * @todo Add a comment on code that runs only for CKE4.
  */
 
-- 
GitLab


From 1688efe85c5baa0ede3bbfe392d867307f544c6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 16 Mar 2023 17:25:02 +0100
Subject: [PATCH 12/19] Add comments on code parts that run only for CKE4

---
 .../config/schema/video_embed_wysiwyg.schema.yml               | 2 ++
 modules/video_embed_wysiwyg/plugin/README.md                   | 1 +
 .../src/Plugin/CKEditorPlugin/VideoEmbedWysiwyg.php            | 2 +-
 modules/video_embed_wysiwyg/video_embed_wysiwyg.module         | 3 ++-
 4 files changed, 6 insertions(+), 2 deletions(-)
 create mode 100644 modules/video_embed_wysiwyg/plugin/README.md

diff --git a/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml b/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml
index ee27f6b..117c374 100644
--- a/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml
+++ b/modules/video_embed_wysiwyg/config/schema/video_embed_wysiwyg.schema.yml
@@ -1,3 +1,4 @@
+# CKE4
 ckeditor.plugin.video_embed:
   label: 'Video Embed'
   type: mapping
@@ -23,6 +24,7 @@ ckeditor.plugin.video_embed:
               label: 'Height'
               type: string
 
+# CKE5
 ckeditor5.plugin.video_embed_wysiwyg_video_embed:
   label: 'Video Embed'
   type: mapping
diff --git a/modules/video_embed_wysiwyg/plugin/README.md b/modules/video_embed_wysiwyg/plugin/README.md
new file mode 100644
index 0000000..fa35e60
--- /dev/null
+++ b/modules/video_embed_wysiwyg/plugin/README.md
@@ -0,0 +1 @@
+This folder contains the CKE4 plugin.
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditorPlugin/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditorPlugin/VideoEmbedWysiwyg.php
index 7cb37ea..6c84502 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/CKEditorPlugin/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditorPlugin/VideoEmbedWysiwyg.php
@@ -11,7 +11,7 @@ use Drupal\editor\Entity\Editor;
 use Drupal\video_embed_field\Plugin\Field\FieldFormatter\Video;
 
 /**
- * The media_entity plugin for video_embed_field.
+ * The CKE4 plugin for video_embed_field.
  *
  * @CKEditorPlugin(
  *   id = "video_embed",
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
index a79ca60..2409951 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
@@ -4,7 +4,6 @@
  * @file
  * Module file for video_embed_wysiwyg.
  * @todo CKE5 upgrade path for plugin config.
- * @todo Add a comment on code that runs only for CKE4.
  */
 
 use Drupal\editor\Entity\Editor;
@@ -17,6 +16,7 @@ define('VIDEO_EMBED_WYSIWYG_DOCUMENTATION_URL', 'https://www.drupal.org/node/280
  * Implements hook_ckeditor_css_alter().
  */
 function video_embed_wysiwyg_ckeditor_css_alter(array &$css, Editor $editor) {
+  // For CKE4.
   $css[] = \Drupal::service('extension.list.module')->getPath('video_embed_wysiwyg') . '/plugin/plugin.css';
 }
 
@@ -30,6 +30,7 @@ function video_embed_wysiwyg_form_filter_format_form_alter(&$form, $form_state,
 
 /**
  * Validate callback to check if the filter and button are both enabled.
+ * For CKE4.
  */
 function video_embed_wysiwyg_toolbar_filter_validate($form, FormStateInterface $form_state) {
   $filter_enabled = !empty($form_state->getValue(['filters', 'video_embed_wysiwyg', 'status']));
-- 
GitLab


From b0e758544d13aab0175cac0ceb2473900838ecdd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABlG?= <ggosset@insite.coop>
Date: Thu, 16 Mar 2023 17:39:13 +0100
Subject: [PATCH 13/19] Upgrade path from CKE4

---
 .../Plugin/CKEditor4To5Upgrade/VideoEmbed.php | 66 +++++++++++++++++++
 .../video_embed_wysiwyg.module                |  1 -
 2 files changed, 66 insertions(+), 1 deletion(-)
 create mode 100644 modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php

diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php
new file mode 100644
index 0000000..038c63f
--- /dev/null
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php
@@ -0,0 +1,66 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\video_embed_wysiwyg\Plugin\CKEditor4To5Upgrade;
+
+use Drupal\ckeditor5\HTMLRestrictions;
+use Drupal\ckeditor5\Plugin\CKEditor4To5UpgradePluginInterface;
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\filter\FilterFormatInterface;
+
+/**
+ * Provides the CKEditor 4 to 5 upgrade for the CKEditor plugin.
+ *
+ * @CKEditor4To5Upgrade(
+ *   id = "video_embed_wysiwyg",
+ *   cke4_buttons = {
+ *     "video_embed",
+ *   },
+ *   cke4_plugin_settings = {
+ *     "video_embed",
+ *   }
+ * )
+ *
+ * @internal
+ *   Plugin classes are internal.
+ */
+class VideoEmbed extends PluginBase implements CKEditor4To5UpgradePluginInterface {
+
+  // @todo Test this upgrade path.
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mapCKEditor4ToolbarButtonToCKEditor5ToolbarItem(string $cke4_button, HTMLRestrictions $text_format_html_restrictions): ?array {
+    switch ($cke4_button) {
+      case 'video_embed':
+        return ['videoEmbed'];
+
+      default:
+        throw new \OutOfBoundsException();
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mapCKEditor4SettingsToCKEditor5Configuration(string $cke4_plugin_id, array $cke4_plugin_settings): ?array {
+    switch ($cke4_plugin_id) {
+      case 'video_embed':
+        // Identical configuration.
+        return ['video_embed_wysiwyg_video_embed' => $cke4_plugin_settings];
+
+      default:
+        throw new \OutOfBoundsException();
+    }
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function computeCKEditor5PluginSubsetConfiguration(string $cke5_plugin_id, FilterFormatInterface $text_format): ?array {
+    throw new \OutOfBoundsException();
+  }
+
+}
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
index 2409951..7c8c350 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.module
@@ -3,7 +3,6 @@
 /**
  * @file
  * Module file for video_embed_wysiwyg.
- * @todo CKE5 upgrade path for plugin config.
  */
 
 use Drupal\editor\Entity\Editor;
-- 
GitLab


From e97538c76e0731b2649a72ac7edf7fd1b88f1075 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABl=20Gosset?=
 <14850-gaelg@users.noreply.drupalcode.org>
Date: Thu, 16 Mar 2023 17:00:18 +0000
Subject: [PATCH 14/19] Upgrade path sucessfully tested :)

---
 .../src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php             | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php
index 038c63f..d9c9d90 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditor4To5Upgrade/VideoEmbed.php
@@ -27,8 +27,6 @@ use Drupal\filter\FilterFormatInterface;
  */
 class VideoEmbed extends PluginBase implements CKEditor4To5UpgradePluginInterface {
 
-  // @todo Test this upgrade path.
-
   /**
    * {@inheritdoc}
    */
@@ -63,4 +61,4 @@ class VideoEmbed extends PluginBase implements CKEditor4To5UpgradePluginInterfac
     throw new \OutOfBoundsException();
   }
 
-}
\ No newline at end of file
+}
-- 
GitLab


From c58a73a53ab08b505cee98e26563ba1f30f72799 Mon Sep 17 00:00:00 2001
From: Barbara Bombachini <bbombachini@northern.co>
Date: Fri, 19 May 2023 10:54:46 -0400
Subject: [PATCH 15/19] Add default value to height and width as ckeditor was
 erroring out with missing required field.

---
 .../CKEditor5Plugin/VideoEmbedWysiwyg.php     | 20 ++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
index 5335f2b..c97962e 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/CKEditor5Plugin/VideoEmbedWysiwyg.php
@@ -12,12 +12,15 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\editor\EditorInterface;
 use Drupal\video_embed_field\Plugin\Field\FieldFormatter\Video;
 
+/**
+ * CKEditor 5 VideoEmbedWysiwyg plugin configuration.
+ */
 class VideoEmbedWysiwyg extends CKEditor5PluginDefault implements CKEditor5PluginConfigurableInterface {
 
   use CKEditor5PluginConfigurableTrait;
 
   /**
-   * @inheritDoc
+   * {@inheritDoc}
    */
   public function getDynamicPluginConfig(array $static_plugin_config, EditorInterface $editor): array {
     // Transmit some useful Drupal data to the javascript plugin.
@@ -32,7 +35,7 @@ class VideoEmbedWysiwyg extends CKEditor5PluginDefault implements CKEditor5Plugi
   }
 
   /**
-   * @inheritDoc
+   * {@inheritDoc}
    */
   public function defaultConfiguration(): array {
     return [
@@ -40,15 +43,15 @@ class VideoEmbedWysiwyg extends CKEditor5PluginDefault implements CKEditor5Plugi
         'children' => [
           'autoplay' => FALSE,
           'responsive' => FALSE,
-          'width' => '',
-          'height' => '',
+          'width' => '42',
+          'height' => '42',
         ],
       ],
     ];
   }
 
   /**
-   * @inheritDoc
+   * {@inheritDoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
     $form['defaults'] = [
@@ -62,7 +65,7 @@ class VideoEmbedWysiwyg extends CKEditor5PluginDefault implements CKEditor5Plugi
   }
 
   /**
-   * @inheritDoc
+   * {@inheritDoc}
    */
   public function validateConfigurationForm(array &$form, FormStateInterface $form_state): void {
     $value = $form_state->getValue('defaults');
@@ -72,11 +75,10 @@ class VideoEmbedWysiwyg extends CKEditor5PluginDefault implements CKEditor5Plugi
   }
 
   /**
-   * @inheritDoc
+   * {@inheritDoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
     $this->configuration['defaults'] = $form_state->getValue('defaults');
   }
 
-
-}
\ No newline at end of file
+}
-- 
GitLab


From a55fb9e1d3fb8940954affaa00f76643d129fdd6 Mon Sep 17 00:00:00 2001
From: Barbara Bombachini <bbombachini@northern.co>
Date: Fri, 19 May 2023 11:11:48 -0400
Subject: [PATCH 16/19] Run webpack build and remove debug from file.

---
 modules/video_embed_wysiwyg/js/build/videoEmbed.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index 8958a01..d7fba87 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var __webpack_modules__={"./js/ckeditor5_plugins/videoEmbed/src/index.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _videoembed__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembed */ "./js/ckeditor5_plugins/videoEmbed/src/videoembed.js");\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n  VideoEmbed: _videoembed__WEBPACK_IMPORTED_MODULE_0__["default"],\n});\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/index.js?')},"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ InsertVideoEmbedCommand)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/**\n * @file defines InsertVideoEmbedCommand, which is executed when the videoEmbed\n * toolbar button is pressed.\n */\n\n\n\nclass InsertVideoEmbedCommand extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Command {\n  execute(attributes) {\n    const {model} = this.editor;\n\n    model.change((writer) => {\n      // Insert <videoEmbed *></videoEmbed> at the current selection position\n      // in a way that will result in creating a valid model structure.\n      model.insertContent(createVideoEmbed(writer, attributes));\n    });\n  }\n\n  refresh() {\n    const {model} = this.editor;\n    const {selection} = model.document;\n\n    // Determine if the cursor (selection) is in a position where adding a\n    // videoEmbed is permitted. This is based on the schema of the model(s)\n    // currently containing the cursor.\n    const allowedIn = model.schema.findAllowedParent(\n        selection.getFirstPosition(),\n        'videoEmbed',\n    );\n\n    // If the cursor is not in a location where a videoEmbed can be added,\n    // return null so the addition doesn't happen.\n    this.isEnabled = allowedIn !== null;\n  }\n}\n\nfunction createVideoEmbed(writer, attributes) {\n  // Create instances of the element registered with the editor in\n  // videoembedediting.js.\n  const videoEmbed = writer.createElement('videoEmbed', attributes);\n\n  // Return the element to be added to the editor.\n  return videoEmbed;\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembed.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (/* binding */ VideoEmbed)\n/* harmony export */ });\n/* harmony import */ var _videoembedediting__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./videoembedediting */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js");\n/* harmony import */ var _videoembedui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoembedui */ "./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js");\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ckeditor5/src/core */ "ckeditor5/src/core.js");\n\n\n\n\nclass VideoEmbed extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_2__.Plugin {\n\nstatic get requires() {\n    return [_videoembedediting__WEBPACK_IMPORTED_MODULE_0__["default"], _videoembedui__WEBPACK_IMPORTED_MODULE_1__["default"]];\n  }\n}\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembed.js?')},"./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedEditing)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/widget */ \"ckeditor5/src/widget.js\");\n/* harmony import */ var _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./insertvideoembedcommand */ \"./js/ckeditor5_plugins/videoEmbed/src/insertvideoembedcommand.js\");\n\n\n\n\n\n\n/**\n * CKEditor 5 plugins do not work directly with the DOM. They are defined as\n * plugin-specific data models that are then converted to markup that\n * is inserted in the DOM.\n *\n * CKEditor 5 internally interacts with videoEmbed as this model:\n * <videoEmbed videoUrl=\"https://some.video.url\" responsive=\"trueorfalse\"\n * width=\"42\" height=\"42\" autoplay=\"trueorfalse\"\n * previewThumbnail=\"/some/image/path.jpg\" settingsSummary=\"Some help\n * text.\"></videoEmbed>\n *\n * Which is converted in database (dataDowncast) as this:\n * <p>{\"preview_thumbnail\":\"/some/image/path.jpg\",\n * \"video_url\":\"https://some.video.url\",\"settings\":{\"responsive\":0or1,\"width\":\"42\",\"height\":\"42\",\"autoplay\":0or1}\",\n * settings_summary\":[\"Some help text.\"]}</p>\n *\n * The Drupal video_embed_wysiwyg format filter will then convert this into a\n * real HTML video embed, on PHP frontend rendering.\n *\n * videoEmbed model elements are also converted to HTML for preview in CKE5 UI\n * (editingDowncast).\n *\n * And the database markup can be converted back to model (upcast).\n *\n * This file has the logic for defining the videoEmbed model, and for how it is\n * converted from/to standard DOM markup for database/UI.\n */\nclass VideoEmbedEditing extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  static get requires() {\n    return [ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.Widget];\n  }\n\n  init() {\n    this._defineSchema();\n    this._defineConverters();\n    this.editor.commands.add(\n        'insertVideoEmbed',\n        new _insertvideoembedcommand__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.editor),\n    );\n  }\n\n  /*\n   * This registers the structure that will be seen by CKEditor 5 as\n   * <videoEmbed *></videoEmbed>\n   *\n   * The logic in _defineConverters() will determine how this is converted to\n   * markup.\n   */\n  _defineSchema() {\n    // Schemas are registered via the central `editor` object.\n    const schema = this.editor.model.schema;\n\n\n    schema.register('videoEmbed', {\n      inheritAllFrom: '$blockObject',\n      allowAttributes: ['videoUrl', 'responsive', 'width', 'height', 'autoplay', 'previewThumbnail', 'settingsSummary']\n    });\n  }\n\n  /**\n   * Converters determine how CKEditor 5 models are converted into markup and\n   * vice-versa.\n   */\n  _defineConverters() {\n    // Converters are registered via the central editor object.\n    const {conversion} = this.editor;\n\n    // Upcast Converters: determine how existing HTML is interpreted by the\n    // editor. These trigger when an editor instance loads.\n    //\n    // If <p>{\"preview_thumbnail\":......}</p> is present in the existing markup\n    // processed by CKEditor, then CKEditor recognizes and loads it as a\n    // <videoEmbed> model.\n    // @see\n    // https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html\n    conversion.for('upcast').elementToElement({\n      view: function (element) {\n        if (element.name === 'p') {\n          if (element.getChild(0).is('text')) {\n            let text = element.getChild(0).data;\n            if (text.match(/^({(?=.*preview_thumbnail\\b)(?=.*settings\\b)(?=.*video_url\\b)(?=.*settings_summary)(.*)})$/)) {\n              return {name: true};\n            }\n          }\n        }\n        return null;\n      },\n      model: (viewElement, {writer}) => {\n        let data = JSON.parse(viewElement.getChild(0).data);\n        return writer.createElement('videoEmbed',\n            {\n              'videoUrl': data.video_url,\n              'responsive': !!data.settings.responsive,\n              'width': data.settings.width,\n              'height': data.settings.height,\n              'autoplay': !!data.settings.autoplay,\n              'previewThumbnail': data.preview_thumbnail,\n              'settingsSummary': data.settings_summary[0],\n            });\n      },\n      // Avoid it's converted to a normal paragraph.\n      converterPriority: 'high'\n    });\n\n\n    // Data Downcast Converters: converts stored model data into HTML.\n    // These trigger when content is saved.\n    //\n    // Instances of <videoEmbed> are saved as\n    // <p>{\"preview_thumbnail\":......}</p>.\n    conversion.for('dataDowncast').elementToElement({\n      model: 'videoEmbed',\n      view: (modelElement, {writer}) => {\n        const data = {};\n        data.preview_thumbnail = modelElement.getAttribute('previewThumbnail');\n        data.video_url = modelElement.getAttribute('videoUrl');\n        data.settings = {};\n        ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n          data.settings[attributeName] = modelElement.getAttribute(attributeName);\n        });\n        data.settings_summary = [modelElement.getAttribute('settingsSummary')];\n        return writer.createContainerElement('p', {}, [writer.createText(JSON.stringify(data))]);\n      }\n    });\n\n\n    // Editing Downcast Converters. These render the content to the user for\n    // editing, i.e. this determines what gets seen in the editor. These trigger\n    // after the Data Upcast Converters, and are re-triggered any time there\n    // are changes to any of the models' properties.\n    //\n    // Convert the <videoEmbed> model into a container widget in the editor UI.\n    conversion.for('editingDowncast').elementToElement({\n          model: 'videoEmbed',\n          view: (modelElement, {writer}) => {\n            const preview = writer.createContainerElement('span', {class: 'video-embed-widget'}, [\n              writer.createEmptyElement('img', {\n                class: 'video-embed-widget__image',\n                src: modelElement.getAttribute('previewThumbnail')\n              }),\n              writer.createContainerElement('span', {class: 'video-embed-widget__summary'}, [\n                writer.createText(modelElement.getAttribute('settingsSummary'))\n              ])\n            ]);\n            return (0,ckeditor5_src_widget__WEBPACK_IMPORTED_MODULE_1__.toWidget)(preview, writer, {label: Drupal.t('Video Embed')});\n          }\n        }\n    );\n  }\n}\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js?")},"./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ VideoEmbedUI)\n/* harmony export */ });\n/* harmony import */ var ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ckeditor5/src/core */ \"ckeditor5/src/core.js\");\n/* harmony import */ var ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ckeditor5/src/ui */ \"ckeditor5/src/ui.js\");\n/* harmony import */ var _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../../icons/play-circle.svg */ \"./icons/play-circle.svg\");\n/**\n * @file registers the videoEmbed toolbar button and binds functionality to it.\n */\n\n\n\n\n/* @todo Choose the best icon and remove others. */\n\n\nclass VideoEmbedUI extends ckeditor5_src_core__WEBPACK_IMPORTED_MODULE_0__.Plugin {\n  init() {\n    const editor = this.editor;\n\n    // This will register the videoEmbed toolbar button.\n    editor.ui.componentFactory.add('videoEmbed', (locale) => {\n      const command = editor.commands.get('insertVideoEmbed');\n      const buttonView = new ckeditor5_src_ui__WEBPACK_IMPORTED_MODULE_1__.ButtonView(locale);\n\n      // Create the toolbar button.\n      buttonView.set({\n        label: editor.t('Video Embed'),\n        icon: _icons_play_circle_svg__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n        tooltip: true,\n      });\n\n      // Bind the state of the button to the command.\n      buttonView.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');\n\n      // Execute the command when the button is clicked (executed).\n      this.listenTo(buttonView, 'execute', () => {\n            this.openEditingDialog();\n          }\n      );\n\n      return buttonView;\n    });\n  }\n\n  /**\n   * Opens video embed form when the editing button is clicked.\n   */\n  openEditingDialog() {\n    const {editor} = this;\n\n    // If the selected element while we click the button is an instance\n    // of the video_embed widget, extract its values so they can be\n    // sent to the server to prime the configuration form.\n    let existingValues = {settings: {}};\n    const selectedVideoEmbedElement = editor.model.document.selection.getSelectedElement();\n    if (selectedVideoEmbedElement) {\n      if (selectedVideoEmbedElement.hasAttribute('videoUrl')) {\n        existingValues.video_url = selectedVideoEmbedElement.getAttribute('videoUrl');\n      }\n      ['responsive', 'width', 'height', 'autoplay'].forEach(function (attributeName) {\n        if (selectedVideoEmbedElement.hasAttribute(attributeName)) {\n          existingValues.settings[attributeName] = selectedVideoEmbedElement.getAttribute(attributeName);\n        }\n      });\n    }\n    this._openDialog(\n        Drupal.url('video-embed-wysiwyg/dialog/' + editor.config.get('videoEmbed').format),\n        existingValues,\n        (newValues) => {\n\n          const attributes = {\n            videoUrl: newValues.video_url,\n            responsive: newValues.settings.responsive,\n            width: newValues.settings.width,\n            height: newValues.settings.height,\n            autoplay: newValues.settings.autoplay,\n            // These attributes are useful only for editor preview, but are\n            // keeped on dataDowncast so that they can be retrieved on later\n            // upcast+editingDowncast.\n            settingsSummary: newValues.settings_summary[0],\n            previewThumbnail: newValues.preview_thumbnail,\n          }\n          editor.execute('insertVideoEmbed', attributes);\n        },\n        {\n          title: Drupal.t('Video Embed'),\n          dialogClass: 'video-embed-dialog'\n        }\n    );\n  }\n\n  /**\n   * This method is adapted from drupal's ckeditor5.js file due to an issue\n   * where the \"editor_object\" isn't passed to the ajax request.\n   *\n   * See https://www.drupal.org/project/drupal/issues/3303191\n   *\n   * @param {string} url\n   *   The URL that contains the contents of the dialog.\n   * @param {object} existingValues\n   *   Existing values that will be sent via POST to the url for the dialog\n   *   contents.\n   * @param {function} saveCallback\n   *   A function to be called upon saving the dialog.\n   * @param {object} dialogSettings\n   *   An object containing settings to be passed to the jQuery UI.\n   */\n  _openDialog(url, existingValues, saveCallback, dialogSettings = {}) {\n    // Add a consistent dialog class.\n    const classes = dialogSettings.dialogClass\n        ? dialogSettings.dialogClass.split(' ')\n        : [];\n    classes.push('ui-dialog--narrow');\n    dialogSettings.dialogClass = classes.join(' ');\n    dialogSettings.autoResize =\n        window.matchMedia('(min-width: 600px)').matches;\n    dialogSettings.width = 'auto';\n\n    const ckeditorAjaxDialog = Drupal.ajax({\n      dialog: dialogSettings,\n      dialogType: 'modal',\n      selector: '.ckeditor5-dialog-loading-link',\n      url,\n      progress: {type: 'fullscreen'},\n      submit: {\n        editor_object: existingValues,\n      },\n    });\n    ckeditorAjaxDialog.execute();\n\n    // Store the save callback to be executed when this dialog is closed.\n    Drupal.ckeditor5.saveCallback = saveCallback;\n  }\n\n}\n\n\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./js/ckeditor5_plugins/videoEmbed/src/videoembedui.js?")},"./icons/play-circle.svg":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("<svg xmlns=\\"http://www.w3.org/2000/svg\\" viewBox=\\"0 0 512 512\\">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d=\\"M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z\\"/></svg>");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/./icons/play-circle.svg?')},"ckeditor5/src/core.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/core.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./core.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/ui.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/ui.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./ui.js_from_dll-reference_CKEditor5.dll?')},"ckeditor5/src/widget.js":(module,__unused_webpack_exports,__webpack_require__)=>{eval('module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ "dll-reference CKEditor5.dll"))("./src/widget.js");\n\n//# sourceURL=webpack://CKEditor5.videoEmbed/delegated_./widget.js_from_dll-reference_CKEditor5.dll?')},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__("./js/ckeditor5_plugins/videoEmbed/src/index.js");return __webpack_exports__=__webpack_exports__.default,__webpack_exports__})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/widget.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/widget.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(o){var s=t[o];if(void 0!==s)return s.exports;var r=t[o]={exports:{}};return e[o](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>a});var e=i("ckeditor5/src/core.js"),t=i("ckeditor5/src/widget.js");class s extends e.Command{execute(e){const{model:t}=this.editor;t.change((i=>{t.insertContent(function(e,t){return e.createElement("videoEmbed",t)}(i,e))}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=e.schema.findAllowedParent(t.getFirstPosition(),"videoEmbed");this.isEnabled=null!==i}}class r extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("insertVideoEmbed",new s(this.editor))}_defineSchema(){this.editor.model.schema.register("videoEmbed",{inheritAllFrom:"$blockObject",allowAttributes:["videoUrl","responsive","width","height","autoplay","previewThumbnail","settingsSummary"]})}_defineConverters(){const{conversion:e}=this.editor;e.for("upcast").elementToElement({view:function(e){if("p"===e.name&&e.getChild(0).is("text")){if(e.getChild(0).data.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/))return{name:!0}}return null},model:(e,{writer:t})=>{let i=JSON.parse(e.getChild(0).data);return t.createElement("videoEmbed",{videoUrl:i.video_url,responsive:!!i.settings.responsive,width:i.settings.width,height:i.settings.height,autoplay:!!i.settings.autoplay,previewThumbnail:i.preview_thumbnail,settingsSummary:i.settings_summary[0]})},converterPriority:"high"}),e.for("dataDowncast").elementToElement({model:"videoEmbed",view:(e,{writer:t})=>{const i={};return i.preview_thumbnail=e.getAttribute("previewThumbnail"),i.video_url=e.getAttribute("videoUrl"),i.settings={},["responsive","width","height","autoplay"].forEach((function(t){i.settings[t]=e.getAttribute(t)})),i.settings_summary=[e.getAttribute("settingsSummary")],t.createContainerElement("p",{},[t.createText(JSON.stringify(i))])}}),e.for("editingDowncast").elementToElement({model:"videoEmbed",view:(e,{writer:i})=>{const o=i.createContainerElement("span",{class:"video-embed-widget"},[i.createEmptyElement("img",{class:"video-embed-widget__image",src:e.getAttribute("previewThumbnail")}),i.createContainerElement("span",{class:"video-embed-widget__summary"},[i.createText(e.getAttribute("settingsSummary"))])]);return(0,t.toWidget)(o,i,{label:Drupal.t("Video Embed")})}})}}var n=i("ckeditor5/src/ui.js");class d extends e.Plugin{init(){const e=this.editor;e.ui.componentFactory.add("videoEmbed",(t=>{const i=e.commands.get("insertVideoEmbed"),o=new n.ButtonView(t);return o.set({label:e.t("Video Embed"),icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>',tooltip:!0}),o.bind("isOn","isEnabled").to(i,"value","isEnabled"),this.listenTo(o,"execute",(()=>{this.openEditingDialog()})),o}))}openEditingDialog(){const{editor:e}=this;let t={settings:{}};const i=e.model.document.selection.getSelectedElement();i&&(i.hasAttribute("videoUrl")&&(t.video_url=i.getAttribute("videoUrl")),["responsive","width","height","autoplay"].forEach((function(e){i.hasAttribute(e)&&(t.settings[e]=i.getAttribute(e))}))),this._openDialog(Drupal.url("video-embed-wysiwyg/dialog/"+e.config.get("videoEmbed").format),t,(t=>{const i={videoUrl:t.video_url,responsive:t.settings.responsive,width:t.settings.width,height:t.settings.height,autoplay:t.settings.autoplay,settingsSummary:t.settings_summary[0],previewThumbnail:t.preview_thumbnail};e.execute("insertVideoEmbed",i)}),{title:Drupal.t("Video Embed"),dialogClass:"video-embed-dialog"})}_openDialog(e,t,i,o={}){const s=o.dialogClass?o.dialogClass.split(" "):[];s.push("ui-dialog--narrow"),o.dialogClass=s.join(" "),o.autoResize=window.matchMedia("(min-width: 600px)").matches,o.width="auto";Drupal.ajax({dialog:o,dialogType:"modal",selector:".ckeditor5-dialog-loading-link",url:e,progress:{type:"fullscreen"},submit:{editor_object:t}}).execute(),Drupal.ckeditor5.saveCallback=i}}class l extends e.Plugin{static get requires(){return[r,d]}}const a={VideoEmbed:l}})(),o=o.default})()));
\ No newline at end of file
-- 
GitLab


From e1038c49a36116ca67a8d97c7c87ad9c2dbddb2c Mon Sep 17 00:00:00 2001
From: Pierre Rudloff <prudloff@insite.coop>
Date: Wed, 7 Jun 2023 16:52:02 +0200
Subject: [PATCH 17/19] Error when getChild() returns NULL

---
 modules/video_embed_wysiwyg/js/build/videoEmbed.js             | 2 +-
 .../js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js   | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/modules/video_embed_wysiwyg/js/build/videoEmbed.js b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
index d7fba87..3acf181 100644
--- a/modules/video_embed_wysiwyg/js/build/videoEmbed.js
+++ b/modules/video_embed_wysiwyg/js/build/videoEmbed.js
@@ -1 +1 @@
-!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/widget.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/widget.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(o){var s=t[o];if(void 0!==s)return s.exports;var r=t[o]={exports:{}};return e[o](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>a});var e=i("ckeditor5/src/core.js"),t=i("ckeditor5/src/widget.js");class s extends e.Command{execute(e){const{model:t}=this.editor;t.change((i=>{t.insertContent(function(e,t){return e.createElement("videoEmbed",t)}(i,e))}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=e.schema.findAllowedParent(t.getFirstPosition(),"videoEmbed");this.isEnabled=null!==i}}class r extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("insertVideoEmbed",new s(this.editor))}_defineSchema(){this.editor.model.schema.register("videoEmbed",{inheritAllFrom:"$blockObject",allowAttributes:["videoUrl","responsive","width","height","autoplay","previewThumbnail","settingsSummary"]})}_defineConverters(){const{conversion:e}=this.editor;e.for("upcast").elementToElement({view:function(e){if("p"===e.name&&e.getChild(0).is("text")){if(e.getChild(0).data.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/))return{name:!0}}return null},model:(e,{writer:t})=>{let i=JSON.parse(e.getChild(0).data);return t.createElement("videoEmbed",{videoUrl:i.video_url,responsive:!!i.settings.responsive,width:i.settings.width,height:i.settings.height,autoplay:!!i.settings.autoplay,previewThumbnail:i.preview_thumbnail,settingsSummary:i.settings_summary[0]})},converterPriority:"high"}),e.for("dataDowncast").elementToElement({model:"videoEmbed",view:(e,{writer:t})=>{const i={};return i.preview_thumbnail=e.getAttribute("previewThumbnail"),i.video_url=e.getAttribute("videoUrl"),i.settings={},["responsive","width","height","autoplay"].forEach((function(t){i.settings[t]=e.getAttribute(t)})),i.settings_summary=[e.getAttribute("settingsSummary")],t.createContainerElement("p",{},[t.createText(JSON.stringify(i))])}}),e.for("editingDowncast").elementToElement({model:"videoEmbed",view:(e,{writer:i})=>{const o=i.createContainerElement("span",{class:"video-embed-widget"},[i.createEmptyElement("img",{class:"video-embed-widget__image",src:e.getAttribute("previewThumbnail")}),i.createContainerElement("span",{class:"video-embed-widget__summary"},[i.createText(e.getAttribute("settingsSummary"))])]);return(0,t.toWidget)(o,i,{label:Drupal.t("Video Embed")})}})}}var n=i("ckeditor5/src/ui.js");class d extends e.Plugin{init(){const e=this.editor;e.ui.componentFactory.add("videoEmbed",(t=>{const i=e.commands.get("insertVideoEmbed"),o=new n.ButtonView(t);return o.set({label:e.t("Video Embed"),icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>',tooltip:!0}),o.bind("isOn","isEnabled").to(i,"value","isEnabled"),this.listenTo(o,"execute",(()=>{this.openEditingDialog()})),o}))}openEditingDialog(){const{editor:e}=this;let t={settings:{}};const i=e.model.document.selection.getSelectedElement();i&&(i.hasAttribute("videoUrl")&&(t.video_url=i.getAttribute("videoUrl")),["responsive","width","height","autoplay"].forEach((function(e){i.hasAttribute(e)&&(t.settings[e]=i.getAttribute(e))}))),this._openDialog(Drupal.url("video-embed-wysiwyg/dialog/"+e.config.get("videoEmbed").format),t,(t=>{const i={videoUrl:t.video_url,responsive:t.settings.responsive,width:t.settings.width,height:t.settings.height,autoplay:t.settings.autoplay,settingsSummary:t.settings_summary[0],previewThumbnail:t.preview_thumbnail};e.execute("insertVideoEmbed",i)}),{title:Drupal.t("Video Embed"),dialogClass:"video-embed-dialog"})}_openDialog(e,t,i,o={}){const s=o.dialogClass?o.dialogClass.split(" "):[];s.push("ui-dialog--narrow"),o.dialogClass=s.join(" "),o.autoResize=window.matchMedia("(min-width: 600px)").matches,o.width="auto";Drupal.ajax({dialog:o,dialogType:"modal",selector:".ckeditor5-dialog-loading-link",url:e,progress:{type:"fullscreen"},submit:{editor_object:t}}).execute(),Drupal.ckeditor5.saveCallback=i}}class l extends e.Plugin{static get requires(){return[r,d]}}const a={VideoEmbed:l}})(),o=o.default})()));
\ No newline at end of file
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.videoEmbed=t())}(self,(()=>(()=>{var e={"ckeditor5/src/core.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/ui.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/ui.js")},"ckeditor5/src/widget.js":(e,t,i)=>{e.exports=i("dll-reference CKEditor5.dll")("./src/widget.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function i(o){var s=t[o];if(void 0!==s)return s.exports;var r=t[o]={exports:{}};return e[o](r,r.exports,i),r.exports}i.d=(e,t)=>{for(var o in t)i.o(t,o)&&!i.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var o={};return(()=>{"use strict";i.d(o,{default:()=>a});var e=i("ckeditor5/src/core.js"),t=i("ckeditor5/src/widget.js");class s extends e.Command{execute(e){const{model:t}=this.editor;t.change((i=>{t.insertContent(function(e,t){return e.createElement("videoEmbed",t)}(i,e))}))}refresh(){const{model:e}=this.editor,{selection:t}=e.document,i=e.schema.findAllowedParent(t.getFirstPosition(),"videoEmbed");this.isEnabled=null!==i}}class r extends e.Plugin{static get requires(){return[t.Widget]}init(){this._defineSchema(),this._defineConverters(),this.editor.commands.add("insertVideoEmbed",new s(this.editor))}_defineSchema(){this.editor.model.schema.register("videoEmbed",{inheritAllFrom:"$blockObject",allowAttributes:["videoUrl","responsive","width","height","autoplay","previewThumbnail","settingsSummary"]})}_defineConverters(){const{conversion:e}=this.editor;e.for("upcast").elementToElement({view:function(e){const t=e.getChild(0);if("p"===e.name&&t&&t.is("text")){if(e.getChild(0).data.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/))return{name:!0}}return null},model:(e,{writer:t})=>{let i=JSON.parse(e.getChild(0).data);return t.createElement("videoEmbed",{videoUrl:i.video_url,responsive:!!i.settings.responsive,width:i.settings.width,height:i.settings.height,autoplay:!!i.settings.autoplay,previewThumbnail:i.preview_thumbnail,settingsSummary:i.settings_summary[0]})},converterPriority:"high"}),e.for("dataDowncast").elementToElement({model:"videoEmbed",view:(e,{writer:t})=>{const i={};return i.preview_thumbnail=e.getAttribute("previewThumbnail"),i.video_url=e.getAttribute("videoUrl"),i.settings={},["responsive","width","height","autoplay"].forEach((function(t){i.settings[t]=e.getAttribute(t)})),i.settings_summary=[e.getAttribute("settingsSummary")],t.createContainerElement("p",{},[t.createText(JSON.stringify(i))])}}),e.for("editingDowncast").elementToElement({model:"videoEmbed",view:(e,{writer:i})=>{const o=i.createContainerElement("span",{class:"video-embed-widget"},[i.createEmptyElement("img",{class:"video-embed-widget__image",src:e.getAttribute("previewThumbnail")}),i.createContainerElement("span",{class:"video-embed-widget__summary"},[i.createText(e.getAttribute("settingsSummary"))])]);return(0,t.toWidget)(o,i,{label:Drupal.t("Video Embed")})}})}}var n=i("ckeditor5/src/ui.js");class d extends e.Plugin{init(){const e=this.editor;e.ui.componentFactory.add("videoEmbed",(t=>{const i=e.commands.get("insertVideoEmbed"),o=new n.ButtonView(t);return o.set({label:e.t("Video Embed"),icon:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">\x3c!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --\x3e<path d="M371.7 238l-176-107c-15.8-8.8-35.7 2.5-35.7 21v208c0 18.4 19.8 29.8 35.7 21l176-101c16.4-9.1 16.4-32.8 0-42zM504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256z"/></svg>',tooltip:!0}),o.bind("isOn","isEnabled").to(i,"value","isEnabled"),this.listenTo(o,"execute",(()=>{this.openEditingDialog()})),o}))}openEditingDialog(){const{editor:e}=this;let t={settings:{}};const i=e.model.document.selection.getSelectedElement();i&&(i.hasAttribute("videoUrl")&&(t.video_url=i.getAttribute("videoUrl")),["responsive","width","height","autoplay"].forEach((function(e){i.hasAttribute(e)&&(t.settings[e]=i.getAttribute(e))}))),this._openDialog(Drupal.url("video-embed-wysiwyg/dialog/"+e.config.get("videoEmbed").format),t,(t=>{const i={videoUrl:t.video_url,responsive:t.settings.responsive,width:t.settings.width,height:t.settings.height,autoplay:t.settings.autoplay,settingsSummary:t.settings_summary[0],previewThumbnail:t.preview_thumbnail};e.execute("insertVideoEmbed",i)}),{title:Drupal.t("Video Embed"),dialogClass:"video-embed-dialog"})}_openDialog(e,t,i,o={}){const s=o.dialogClass?o.dialogClass.split(" "):[];s.push("ui-dialog--narrow"),o.dialogClass=s.join(" "),o.autoResize=window.matchMedia("(min-width: 600px)").matches,o.width="auto";Drupal.ajax({dialog:o,dialogType:"modal",selector:".ckeditor5-dialog-loading-link",url:e,progress:{type:"fullscreen"},submit:{editor_object:t}}).execute(),Drupal.ckeditor5.saveCallback=i}}class l extends e.Plugin{static get requires(){return[r,d]}}const a={VideoEmbed:l}})(),o=o.default})()));
\ No newline at end of file
diff --git a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
index 38918a9..c940c6c 100644
--- a/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
+++ b/modules/video_embed_wysiwyg/js/ckeditor5_plugins/videoEmbed/src/videoembedediting.js
@@ -81,8 +81,9 @@ export default class VideoEmbedEditing extends Plugin {
     // https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_conversion_conversion-ConverterDefinition.html
     conversion.for('upcast').elementToElement({
       view: function (element) {
+        const child = element.getChild(0);
         if (element.name === 'p') {
-          if (element.getChild(0).is('text')) {
+          if (child && child.is('text')) {
             let text = element.getChild(0).data;
             if (text.match(/^({(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})$/)) {
               return {name: true};
-- 
GitLab


From a7f1359aab554455d44073afd7b813ddd527529d Mon Sep 17 00:00:00 2001
From: Adam Fasoldt <adamvincent.fasoldt@its.ny.gov>
Date: Wed, 5 Jul 2023 13:02:37 -0400
Subject: [PATCH 18/19] 3311063: set ckeditor 5 dependencies

---
 composer.json                                            | 1 -
 modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/composer.json b/composer.json
index 2ac92ff..aec2a55 100644
--- a/composer.json
+++ b/composer.json
@@ -11,7 +11,6 @@
     }
   },
   "require-dev": {
-    "drupal/ckeditor": "^1",
     "drupal/colorbox": "^2"
   }
 }
diff --git a/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml b/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml
index c2a6ac5..bd4a2f6 100644
--- a/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml
+++ b/modules/video_embed_wysiwyg/video_embed_wysiwyg.info.yml
@@ -4,6 +4,7 @@ description: 'Integrates video_embed_field directly into ckeditor. Useful for we
 package: Video Embed Field
 core_version_requirement: ^9.2 || ^10
 dependencies:
+  - drupal:ckeditor5
   - drupal:field
   - drupal:editor
   - video_embed_field:video_embed_field
-- 
GitLab


From ae2757a6be5b18492871509ca867a49a0ecddd6c Mon Sep 17 00:00:00 2001
From: Nicolas Haase <nicolas@aussieangels.com>
Date: Thu, 7 Sep 2023 16:49:31 +1000
Subject: [PATCH 19/19] Applied change from
 https://www.drupal.org/project/video_embed_field/issues/3371353 to fix
 rendering more than one video per field.

---
 .../video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php b/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
index 4486bc0..6bcdd8f 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
@@ -130,7 +130,7 @@ class VideoEmbedWysiwyg extends FilterBase implements ContainerFactoryPluginInte
    */
   protected function getValidMatches($text) {
     // Use a look ahead to match the capture groups in any order.
-    if (!preg_match_all('/(<p>)?(?<json>{(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})(<\/p>)?/', $text, $matches)) {
+      if (!preg_match_all('/(<p>)?(?<json>{(?=.*preview_thumbnail\b)(?=.*settings\b)(?=.*video_url\b)(?=.*settings_summary)(.*)})(<\/p>)/U', $text, $matches)) {
       return [];
     }
     $valid_matches = [];
-- 
GitLab

