From 3a4430a3229d4ff3855006991f105f0c212880bb Mon Sep 17 00:00:00 2001
From: skaught <skaught@gmail.com>
Date: Tue, 20 Jul 2021 11:28:24 -0400
Subject: [PATCH] 2913598-49 ally fixes to-render-not_container.patch

---
 .../src/Plugin/Filter/VideoEmbedWysiwyg.php   | 24 +++++--
 src/Plugin/Field/FieldFormatter/Video.php     | 12 ++--
 .../video_embed_field/Provider/Vimeo.php      | 39 +++++------
 .../video_embed_field/Provider/YouTube.php    | 55 ++++++++++------
 .../Provider/YouTubePlaylist.php              |  2 +-
 src/ProviderPluginBase.php                    | 66 +++++++++++++++++--
 src/ProviderPluginInterface.php               | 17 ++++-
 templates/video-embed-iframe.html.twig        |  6 +-
 .../Provider/MockProvider.php                 |  2 +-
 tests/src/Unit/ProviderUrlParseTest.php       |  6 +-
 10 files changed, 168 insertions(+), 61 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..61a9532 100644
--- a/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
+++ b/modules/video_embed_wysiwyg/src/Plugin/Filter/VideoEmbedWysiwyg.php
@@ -11,6 +11,7 @@ use Drupal\video_embed_field\Plugin\Field\FieldFormatter\Video;
 use Drupal\video_embed_field\ProviderManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\Path\CurrentPathStack;
 
 /**
  * The filter to turn tokens inserted into the WYSIWYG into videos.
@@ -44,6 +45,12 @@ class VideoEmbedWysiwyg extends FilterBase implements ContainerFactoryPluginInte
    * @var \Drupal\Core\Session\AccountProxyInterface
    */
   protected $currentUser;
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Path\CurrentPathStack
+   */
+  protected $currentPath;
 
   /**
    * VideoEmbedWysiwyg constructor.
@@ -61,18 +68,24 @@ class VideoEmbedWysiwyg extends FilterBase implements ContainerFactoryPluginInte
    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
    *   The current user.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, ProviderManagerInterface $provider_manager, RendererInterface $renderer, AccountProxyInterface $current_user) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ProviderManagerInterface $provider_manager, RendererInterface $renderer, AccountProxyInterface $current_user, CurrentPathStack $currentPath) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->providerManager = $provider_manager;
     $this->renderer = $renderer;
     $this->currentUser = $current_user;
+    $this->currentPath = $currentPath;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('video_embed_field.provider_manager'), $container->get('renderer'), $container->get('current_user'));
+    return new static($configuration, $plugin_id, $plugin_definition,
+      $container->get('video_embed_field.provider_manager'),
+      $container->get('renderer'),
+      $container->get('current_user'),
+      $container->get('path.current'),
+    );
   }
 
   /**
@@ -81,14 +94,15 @@ class VideoEmbedWysiwyg extends FilterBase implements ContainerFactoryPluginInte
   public function process($text, $langcode) {
 
     $response = new FilterProcessResult($text);
-
+    $startUnique = 1;
     foreach ($this->getValidMatches($text) as $source_text => $embed_data) {
       if (!$provider = $this->providerManager->loadProviderFromInput($embed_data['video_url'])) {
         continue;
       }
-
+      $path = \ltrim($this->currentPath->getPath(), '/');
+      $instance_id = 'youtube-' . Html::cleanCssIdentifier($path . '-' . Html::getUniqueId($provider->getVideoId()));
       $autoplay = $this->currentUser->hasPermission('never autoplay videos') ? FALSE : $embed_data['settings']['autoplay'];
-      $embed_code = $provider->renderEmbedCode($embed_data['settings']['width'], $embed_data['settings']['height'], $autoplay);
+      $embed_code = $provider->renderEmbedCode($embed_data['settings']['width'], $embed_data['settings']['height'], $autoplay, $instance_id);
 
       $embed_code = [
         '#type' => 'container',
diff --git a/src/Plugin/Field/FieldFormatter/Video.php b/src/Plugin/Field/FieldFormatter/Video.php
index 361207a..940dc4d 100644
--- a/src/Plugin/Field/FieldFormatter/Video.php
+++ b/src/Plugin/Field/FieldFormatter/Video.php
@@ -92,21 +92,22 @@ class Video extends FormatterBase implements ContainerFactoryPluginInterface {
     $element = [];
     foreach ($items as $delta => $item) {
       $provider = $this->providerManager->loadProviderFromInput($item->value);
-
       if (!$provider) {
         $element[$delta] = ['#theme' => 'video_embed_field_missing_provider'];
       }
       else {
         $autoplay = $this->currentUser->hasPermission('never autoplay videos') ? FALSE : $this->getSetting('autoplay');
-        $element[$delta] = $provider->renderEmbedCode($this->getSetting('width'), $this->getSetting('height'), $autoplay);
-        $element[$delta]['#cache']['contexts'][] = 'user.permissions';
+        $instance_id = 'youtube-embed-filter-'.$item->getEntity()->id().'-'.$delta;
+        $element[$delta] = $provider->renderEmbedCode($this->getSetting('width'), $this->getSetting('height'), $autoplay, $instance_id);
+   		  $element[$delta]['#cache']['max-age'] = 0;
 
         $element[$delta] = [
           '#type' => 'container',
-          '#attributes' => ['class' => [Html::cleanCssIdentifier(sprintf('video-embed-field-provider-%s', $provider->getPluginId()))]],
+          '#attributes' => [
+            'class' => [Html::cleanCssIdentifier(sprintf('video-embed-field-provider-%s', $provider->getPluginId()))],
+          ],
           'children' => $element[$delta],
         ];
-
         // For responsive videos, wrap each field item in it's own container.
         if ($this->getSetting('responsive')) {
           $element[$delta]['#attached']['library'][] = 'video_embed_field/responsive-video';
@@ -115,6 +116,7 @@ class Video extends FormatterBase implements ContainerFactoryPluginInterface {
       }
 
     }
+
     return $element;
   }
 
diff --git a/src/Plugin/video_embed_field/Provider/Vimeo.php b/src/Plugin/video_embed_field/Provider/Vimeo.php
index 70c7f6b..799934b 100644
--- a/src/Plugin/video_embed_field/Provider/Vimeo.php
+++ b/src/Plugin/video_embed_field/Provider/Vimeo.php
@@ -17,25 +17,14 @@ class Vimeo extends ProviderPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function renderEmbedCode($width, $height, $autoplay) {
-    $iframe = [
-      '#type' => 'video_embed_iframe',
-      '#provider' => 'vimeo',
-      '#url' => sprintf('https://player.vimeo.com/video/%s', $this->getVideoId()),
-      '#query' => [
-        'autoplay' => $autoplay,
-      ],
-      '#attributes' => [
-        'width' => $width,
-        'height' => $height,
-        'frameborder' => '0',
-        'allowfullscreen' => 'allowfullscreen',
-      ],
-    ];
+  public function renderEmbedCode($width, $height, $autoplay, $instance_id) {
+    $embed_code = parent::renderEmbedCode($width, $height, $autoplay, $instance_id);
+    $embed_code['#provider'] = 'vimeo';
+    $embed_code['#url'] = $this->getProtocol() . '://player.vimeo.com/video/' . $this->getVideoId();
     if ($time_index = $this->getTimeIndex()) {
-      $iframe['#fragment'] = sprintf('t=%s', $time_index);
+      $embed_code['#fragment'] = 't=' . $time_index;
     }
-    return $iframe;
+    return $embed_code;
   }
 
   /**
@@ -48,11 +37,17 @@ class Vimeo extends ProviderPluginBase {
   /**
    * Get the vimeo oembed data.
    *
-   * @return array
+   * @return array|false
    *   An array of data from the oembed endpoint.
    */
   protected function oEmbedData() {
-    return json_decode(file_get_contents('http://vimeo.com/api/oembed.json?url=' . $this->getInput()));
+    $protocol = $this->getProtocol();
+    $requestOembed = $this->httpClient->request('GET', $this->getProtocol() . '://vimeo.com/api/oembed.json?url=' . $this->getInput());
+    if ($requestOembed->getStatusCode() != 200) {
+      return FALSE;
+    }
+    $data = \json_decode($requestOembed->getBody()->getContents());
+    return $data;
   }
 
   /**
@@ -66,7 +61,7 @@ class Vimeo extends ProviderPluginBase {
   /**
    * Get the time index from the URL.
    *
-   * @return string|FALSE
+   * @return string|false
    *   A time index parameter to pass to the frame or FALSE if none is found.
    */
   protected function getTimeIndex() {
@@ -78,7 +73,9 @@ class Vimeo extends ProviderPluginBase {
    * {@inheritdoc}
    */
   public function getName() {
-    return $this->oEmbedData()->title;
+    $stub = parent::getName();
+    $title = (($this->oEmbedData() !== FALSE) ? $this->filterCharaters($this->oEmbedData()->title) . ' | ' : '');
+    return $title . $stub;
   }
 
 }
diff --git a/src/Plugin/video_embed_field/Provider/YouTube.php b/src/Plugin/video_embed_field/Provider/YouTube.php
index 224edd2..39bf688 100644
--- a/src/Plugin/video_embed_field/Provider/YouTube.php
+++ b/src/Plugin/video_embed_field/Provider/YouTube.php
@@ -3,6 +3,7 @@
 namespace Drupal\video_embed_field\Plugin\video_embed_field\Provider;
 
 use Drupal\video_embed_field\ProviderPluginBase;
+use Drupal\Component\Utility\Html;
 
 /**
  * A YouTube provider plugin.
@@ -17,23 +18,13 @@ class YouTube extends ProviderPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function renderEmbedCode($width, $height, $autoplay) {
-    $embed_code = [
-      '#type' => 'video_embed_iframe',
-      '#provider' => 'youtube',
-      '#url' => sprintf('https://www.youtube.com/embed/%s', $this->getVideoId()),
-      '#query' => [
-        'autoplay' => $autoplay,
-        'start' => $this->getTimeIndex(),
-        'rel' => '0',
-      ],
-      '#attributes' => [
-        'width' => $width,
-        'height' => $height,
-        'frameborder' => '0',
-        'allowfullscreen' => 'allowfullscreen',
-      ],
-    ];
+  public function renderEmbedCode($width, $height, $autoplay, $instance_id) {
+    $embed_code = parent::renderEmbedCode($width, $height, $autoplay, $instance_id);
+    $yid = $this->getVideoId();
+    $embed_code['#provider'] = 'youtube';
+    $embed_code['#url'] = $this->getProtocol() . '://www.youtube.com/embed/' . $yid;
+    $embed_code['#query']['start'] = $this->getTimeIndex();
+    $embed_code['#query']['rel'] = 0;
     if ($language = $this->getLanguagePreference()) {
       $embed_code['#query']['cc_lang_pref'] = $language;
     }
@@ -59,7 +50,7 @@ class YouTube extends ProviderPluginBase {
   /**
    * Extract the language preference from the URL for use in closed captioning.
    *
-   * @return string|FALSE
+   * @return string|false
    *   The language preference if one exists or FALSE if one could not be found.
    */
   protected function getLanguagePreference() {
@@ -71,7 +62,7 @@ class YouTube extends ProviderPluginBase {
    * {@inheritdoc}
    */
   public function getRemoteThumbnailUrl() {
-    $url = 'http://img.youtube.com/vi/%s/%s.jpg';
+    $url = $this->getProtocol() . '://img.youtube.com/vi/%s/%s.jpg';
     $high_resolution = sprintf($url, $this->getVideoId(), 'maxresdefault');
     $backup = sprintf($url, $this->getVideoId(), 'mqdefault');
     try {
@@ -91,4 +82,30 @@ class YouTube extends ProviderPluginBase {
     return isset($matches['id']) ? $matches['id'] : FALSE;
   }
 
+  /**
+   * Get the Youtube oEmbed data.
+   *
+   * @return array|false
+   *   An array of data from the oEmbed endpoint.
+   */
+  protected function oEmbedData() {
+    $protocol = $this->getProtocol();
+    $requestOembed = $this->httpClient->request('GET', $protocol . '://www.youtube.com/oembed?url=' . $protocol . '://www.youtube.com/watch?v=' . $this->getVideoId() . '&format=json');
+    if ($requestOembed->getStatusCode() != 200) {
+      return FALSE;
+    }
+    $data = \json_decode($requestOembed->getBody()->getContents());
+    return $data;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getName() {
+    $stub = parent::getName();
+    $title = (($this->oEmbedData() !== FALSE) ? $this->filterCharaters($this->oEmbedData()->title) . ' | ' : '');
+    return $title . $stub;
+  }
+
 }
diff --git a/src/Plugin/video_embed_field/Provider/YouTubePlaylist.php b/src/Plugin/video_embed_field/Provider/YouTubePlaylist.php
index 1043c5a..52b3be1 100644
--- a/src/Plugin/video_embed_field/Provider/YouTubePlaylist.php
+++ b/src/Plugin/video_embed_field/Provider/YouTubePlaylist.php
@@ -17,7 +17,7 @@ class YouTubePlaylist extends ProviderPluginBase {
   /**
    * {@inheritdoc}
    */
-  public function renderEmbedCode($width, $height, $autoplay) {
+  public function renderEmbedCode($width, $height, $autoplay, $instance_id) {
     return [
       '#type' => 'video_embed_iframe',
       '#provider' => 'youtube_playlist',
diff --git a/src/ProviderPluginBase.php b/src/ProviderPluginBase.php
index c3c4b0d..2d790a9 100644
--- a/src/ProviderPluginBase.php
+++ b/src/ProviderPluginBase.php
@@ -7,6 +7,7 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
 use GuzzleHttp\ClientInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Component\Utility\Html;
 
 /**
  * A base for the provider plugins.
@@ -50,17 +51,17 @@ abstract class ProviderPluginBase extends PluginBase implements ProviderPluginIn
    * Create a plugin with the given input.
    *
    * @param array $configuration
-   *   The configuration of the plugin.
+   *   A configuration array containing information about the plugin instance.
    * @param string $plugin_id
    *   The plugin id.
    * @param array $plugin_definition
    *   The plugin definition.
    * @param \GuzzleHttp\ClientInterface $http_client
-   *    An HTTP client.
+   *   An HTTP client.
    *
    * @throws \Exception
    */
-  public function __construct($configuration, $plugin_id, $plugin_definition, ClientInterface $http_client) {
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ClientInterface $http_client) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     if (!static::isApplicable($configuration['input'])) {
       throw new \Exception('Tried to create a video provider plugin with invalid input.');
@@ -76,7 +77,7 @@ abstract class ProviderPluginBase extends PluginBase implements ProviderPluginIn
    * @return string
    *   The video ID.
    */
-  protected function getVideoId() {
+  public function getVideoId() {
     return $this->videoId;
   }
 
@@ -93,6 +94,39 @@ abstract class ProviderPluginBase extends PluginBase implements ProviderPluginIn
     return $this->fileSystem;
   }
 
+  /**
+   * Determine Protocol site is currenly using from server var.
+   *
+   * @return bool
+   */
+  private function isSecure() {
+    return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443;
+  }
+
+  /**
+   * Request Protocol site is currenly using.
+   *
+   * @return string
+   *   The protocol currently used.
+   */
+  public function getProtocol() {
+    return $this->isSecure() ? 'https' : 'http';
+  }
+
+  /**
+   * Transliterate and reduce (assuming Title) string from video provider data
+   * to html output.
+   *
+   * @return string
+   *   an attribute ready string of text.
+   */
+  public static function filterCharaters($str = '') {
+    $trans = \Drupal::transliteration();
+    $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
+    $transformed = $trans->transliterate($str, $langcode);
+    return preg_replace('/[^a-zA-Z0-9_ -]/s', '', $transformed);
+  }
+
   /**
    * Get the input which caused this plugin to be selected.
    *
@@ -151,6 +185,30 @@ abstract class ProviderPluginBase extends PluginBase implements ProviderPluginIn
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function renderEmbedCode($width, $height, $autoplay, $instance_id) {
+    $embed_code = [
+      '#type' => 'video_embed_iframe',
+      '#provider' => '',
+      '#url' => '',
+      '#query' => [
+        'autoplay' => $autoplay,
+      ],
+      '#attributes' => [
+        'width' => $width,
+        'height' => $height,
+        'title' => $this->getName(),
+        'name' => $instance_id,
+        'id' => $instance_id,
+        'frameborder' => '0',
+        'allowfullscreen' => 'allowfullscreen',
+      ],
+    ];
+    return $embed_code;
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/src/ProviderPluginInterface.php b/src/ProviderPluginInterface.php
index 863feeb..b093c5c 100644
--- a/src/ProviderPluginInterface.php
+++ b/src/ProviderPluginInterface.php
@@ -1,6 +1,7 @@
 <?php
 
 namespace Drupal\video_embed_field;
+
 use Drupal\Component\Plugin\PluginInspectionInterface;
 
 /**
@@ -72,11 +73,13 @@ interface ProviderPluginInterface extends PluginInspectionInterface {
    *   The height of the video player.
    * @param bool $autoplay
    *   If the video should autoplay.
+   * @param string $instance_id
+   *   An instance_id to be used for name and id attributes of iframe.
    *
    * @return mixed
    *   A renderable array of the embed code.
    */
-  public function renderEmbedCode($width, $height, $autoplay);
+  public function renderEmbedCode($width, $height, $autoplay, $instance_id);
 
   /**
    * Get the ID of the video from user input.
@@ -89,6 +92,18 @@ interface ProviderPluginInterface extends PluginInspectionInterface {
    */
   public static function getIdFromInput($input);
 
+  /**
+   * Transliterate and reduce (assuming Title) string from video provider data
+   * to html output.
+   *
+   * @param string $input
+   *   the input string (dirty)
+   *
+   * @return string
+   *   an attribute ready string of text (clean)
+   */
+  public static function filterCharaters($str);
+
   /**
    * Get the name of the video.
    *
diff --git a/templates/video-embed-iframe.html.twig b/templates/video-embed-iframe.html.twig
index 353e0db..deac65a 100644
--- a/templates/video-embed-iframe.html.twig
+++ b/templates/video-embed-iframe.html.twig
@@ -4,4 +4,8 @@
  * Display an iframe with alterable components.
  */
 #}
-<iframe{{ attributes }}{% if url is not empty %} src="{{ url }}{% if query is not empty %}?{{ query | url_encode }}{% endif %}{% if fragment is not empty %}#{{ fragment }}{% endif %}"{% endif %}></iframe>
+{% spaceless %}
+<iframe{{ attributes }}{% if url is not empty %} src="{{ url }}{% if query is not empty %}?{{ query | url_encode }}{% endif %}{% if fragment is not empty %}#{{ fragment }}{% endif %}"{% endif %}>{% if url is not empty %}
+  <a href={{ url }}{% if query is not empty %}?{{ query | url_encode }}{% endif %}{% if fragment is not empty %}#{{ fragment }}{% endif %}" target="_blank">{{ attributes.title }}</a>
+{% endif %}</iframe>
+{% endspaceless %}
diff --git a/tests/modules/video_embed_field_mock_provider/src/Plugin/video_embed_field/Provider/MockProvider.php b/tests/modules/video_embed_field_mock_provider/src/Plugin/video_embed_field/Provider/MockProvider.php
index da282f7..36b596d 100644
--- a/tests/modules/video_embed_field_mock_provider/src/Plugin/video_embed_field/Provider/MockProvider.php
+++ b/tests/modules/video_embed_field_mock_provider/src/Plugin/video_embed_field/Provider/MockProvider.php
@@ -33,7 +33,7 @@ class MockProvider implements ProviderPluginInterface {
   /**
    * {@inheritdoc}
    */
-  public function renderEmbedCode($width, $height, $autoplay) {
+  public function renderEmbedCode($width, $height, $autoplay, $instance_id) {
     return [
       '#markup' => 'Mock provider embed code.',
     ];
diff --git a/tests/src/Unit/ProviderUrlParseTest.php b/tests/src/Unit/ProviderUrlParseTest.php
index 6f64b97..b79b265 100644
--- a/tests/src/Unit/ProviderUrlParseTest.php
+++ b/tests/src/Unit/ProviderUrlParseTest.php
@@ -199,7 +199,7 @@ class ProviderUrlParseTest extends UnitTestCase {
     $provider = new YouTube([
       'input' => $url,
     ], '', [], new MockHttpClient());
-    $embed = $provider->renderEmbedCode(100, 100, TRUE);
+    $embed = $provider->renderEmbedCode(100, 100, TRUE, 'youtube-video');
     $language = isset($embed['#query']['cc_lang_pref']) ? $embed['#query']['cc_lang_pref'] : FALSE;
     $this->assertEquals($expected, $language);
   }
@@ -240,7 +240,7 @@ class ProviderUrlParseTest extends UnitTestCase {
     $provider = new YouTube([
       'input' => $url,
     ], '', [], new MockHttpClient());
-    $embed = $provider->renderEmbedCode(100, 100, TRUE);
+    $embed = $provider->renderEmbedCode(100, 100, TRUE, 'youtube-video');
     $this->assertEquals($expected, $embed['#query']['start']);
   }
 
@@ -302,7 +302,7 @@ class ProviderUrlParseTest extends UnitTestCase {
     $this->assertEquals($exception_expected, $exception_triggered);
 
     if (!$exception_triggered) {
-      $embed = $provider->renderEmbedCode(100, 100, TRUE);
+      $embed = $provider->renderEmbedCode(100, 100, TRUE, 'youtube-video');
       $this->assertEquals($expected, isset($embed['#fragment']) ? $embed['#fragment'] : FALSE);
     }
   }
-- 
2.20.1