diff --git a/composer.json b/composer.json index 93286f7b32bfc0464bbcb18dd8f06cbf2d91ec40..f57f2699fedb12e579b9ea5c621281633526df32 100644 --- a/composer.json +++ b/composer.json @@ -283,7 +283,7 @@ }, "drupal/entity_embed": { "2881745": "patches/entity_embed_2881745-22.patch", - "2511404": "https://www.drupal.org/files/issues/2018-09-17/entity-embed-link-2511404-68.patch" + "2511404": "patches/entity-embed-img-link-2511404-68.patch" }, "drupal/smtp": { "2781157": "https://www.drupal.org/files/issues/2018-11-07/2781157-n10.patch" diff --git a/patches/entity-embed-img-link-2511404-68.patch b/patches/entity-embed-img-link-2511404-68.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce5434d988da6aec0065aade86d3958fc5d391c8 --- /dev/null +++ b/patches/entity-embed-img-link-2511404-68.patch @@ -0,0 +1,202 @@ +diff --git a/entity_embed.module b/entity_embed.module +index fbdd994..ee8fbae 100644 +--- a/entity_embed.module ++++ b/entity_embed.module +@@ -6,6 +6,9 @@ + * format. + */ + ++use Drupal\Component\Utility\UrlHelper; ++use Drupal\Core\Url; ++ + /** + * Implements hook_theme(). + */ +@@ -31,6 +34,25 @@ function template_preprocess_entity_embed_container(&$variables) { + $variables['element'] += ['#attributes' => []]; + $variables['attributes'] = $variables['element']['#attributes']; + $variables['children'] = $variables['element']['#children']; ++ if (!empty($variables['element']['#context']['data-entity-embed-display-settings']['link_url'])) { ++ $link = UrlHelper::filterBadProtocol($variables['element']['#context']['data-entity-embed-display-settings']['link_url']); ++ if (!UrlHelper::isExternal($link)) { ++ $link = 'internal:/' . ltrim($link, '/'); ++ } ++ $link = Url::fromUri($link); ++ $attributes = []; ++ if (!empty($variables['element']['#context']['data-entity-embed-display-settings']['link_url_target']) && $variables['element']['#context']['data-entity-embed-display-settings']['link_url_target'] == 1) { ++ $attributes = ['attributes' => ['target' => '_blank']]; ++ } ++ $variables['children'] = [ ++ [ ++ '#type' => 'link', ++ '#title' => $variables['children'], ++ '#options' => $attributes, ++ '#url' => $link, ++ ] ++ ]; ++ } + } + + /** +diff --git a/src/Form/EntityEmbedDialog.php b/src/Form/EntityEmbedDialog.php +index ae0194b..fe16bd9 100644 +--- a/src/Form/EntityEmbedDialog.php ++++ b/src/Form/EntityEmbedDialog.php +@@ -8,6 +8,7 @@ use Drupal\Core\Ajax\AjaxResponse; + use Drupal\Core\Ajax\CloseModalDialogCommand; + use Drupal\Core\Ajax\HtmlCommand; + use Drupal\Core\Ajax\SetDialogTitleCommand; ++use Drupal\Core\Entity\Element\EntityAutocomplete; + use Drupal\Core\Entity\EntityFieldManagerInterface; + use Drupal\Core\Entity\EntityInterface; + use Drupal\Core\Entity\EntityTypeManagerInterface; +@@ -434,6 +435,27 @@ class EntityEmbedDialog extends FormBase { + if (is_string($entity_element['data-entity-embed-display-settings'])) { + $entity_element['data-entity-embed-display-settings'] = Json::decode($entity_element['data-entity-embed-display-settings']); + } ++ ++ // Supress Drupal's "Link image to" dropdown when embedding an image, ++ // since the 'Link to' option provides this functionality. ++ if (isset($form['attributes']['data-entity-embed-display-settings']['image_link'])) { ++ $form['attributes']['data-entity-embed-display-settings']['image_link']['#type'] = 'hidden'; ++ $form['attributes']['data-entity-embed-display-settings']['image_link']['#value'] = ''; ++ } ++ $form['attributes']['data-entity-embed-display-settings']['link_url'] = [ ++ '#title' => t('Link to'), ++ '#type' => 'entity_autocomplete', ++ '#target_type' => 'node', ++ '#attributes' => [ ++ 'data-autocomplete-first-character-blacklist' => '/#?' ++ ], ++ '#element_validate' => [[get_called_class(), 'validateUriElement']], ++ '#process_default_value' => FALSE, ++ '#description' => $this->t('Start typing the title of a piece of content to select it. You can also enter an internal path such as %add-node or an external URL such as %url. Enter %front to link to the front page.', ['%front' => '<front>', '%add-node' => '/node/add', '%url' => 'http://example.com']), ++ '#default_value' => isset($entity_element['data-entity-embed-display-settings']['link_url']) ? $this->getUriAsDisplayableString($entity_element['data-entity-embed-display-settings']['link_url']) : '', ++ '#maxlength' => 2048, ++ ]; ++ + $display = $this->entityEmbedDisplayManager->createInstance($plugin_id, $entity_element['data-entity-embed-display-settings']); + $display->setContextValue('entity', $entity); + $display->setAttributes($entity_element); +@@ -498,8 +520,120 @@ class EntityEmbedDialog extends FormBase { + } + + /** +- * {@inheritdoc} ++ * Gets the URI without the 'internal:' or 'entity:' scheme. ++ * ++ * The following two forms of URIs are transformed: ++ * - 'entity:' URIs: to entity autocomplete ("label (entity id)") strings; ++ * - 'internal:' URIs: the scheme is stripped. ++ * ++ * This method is the inverse of ::getUserEnteredStringAsUri(). ++ * ++ * @param string $uri ++ * The URI to get the displayable string for. ++ * ++ * @return string ++ * ++ * @see static::getUserEnteredStringAsUri() + */ ++ protected function getUriAsDisplayableString($uri) { ++ $uri = Html::decodeEntities($uri); ++ $scheme = parse_url($uri, PHP_URL_SCHEME); ++ ++ // By default, the displayable string is the URI. ++ $displayable_string = $uri; ++ ++ // A different displayable string may be chosen in case of the 'internal:' ++ // or 'entity:' built-in schemes. ++ if ($scheme === 'internal') { ++ $uri_reference = explode(':', $uri, 2)[1]; ++ ++ // @todo '<front>' is valid input for BC reasons, may be removed by ++ // https://www.drupal.org/node/2421941 ++ $path = parse_url($uri, PHP_URL_PATH); ++ if ($path === '/') { ++ $uri_reference = '<front>' . substr($uri_reference, 1); ++ } ++ ++ $displayable_string = $uri_reference; ++ } ++ elseif ($scheme === 'entity') { ++ list($entity_type, $entity_id) = explode('/', substr($uri, 7), 2); ++ // Show the 'entity:' URI as the entity autocomplete would. ++ // @todo Support entity types other than 'node'. Will be fixed in ++ // https://www.drupal.org/node/2423093. ++ if ($entity_type == 'node' && $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id)) { ++ $displayable_string = EntityAutocomplete::getEntityLabels([$entity]); ++ } ++ } ++ ++ return $displayable_string; ++ } ++ ++ /** ++ * Gets the user-entered string as a URI. ++ * ++ * The following two forms of input are mapped to URIs: ++ * - entity autocomplete ("label (entity id)") strings: to 'entity:' URIs; ++ * - strings without a detectable scheme: to 'internal:' URIs. ++ * ++ * This method is the inverse of ::getUriAsDisplayableString(). ++ * ++ * @param string $string ++ * The user-entered string. ++ * ++ * @return string ++ * The URI, if a non-empty $uri was passed. ++ * ++ * @see static::getUriAsDisplayableString() ++ */ ++ protected static function getUserEnteredStringAsUri($string) { ++ // By default, assume the entered string is an URI. ++ $uri = $string; ++ ++ // Detect entity autocomplete string, map to 'entity:' URI. ++ $entity_id = EntityAutocomplete::extractEntityIdFromAutocompleteInput($string); ++ if ($entity_id !== NULL) { ++ // @todo Support entity types other than 'node'. Will be fixed in ++ // https://www.drupal.org/node/2423093. ++ $uri = 'entity:node/' . $entity_id; ++ } ++ // Detect a schemeless string, map to 'internal:' URI. ++ elseif (!empty($string) && parse_url($string, PHP_URL_SCHEME) === NULL) { ++ // @todo '<front>' is valid input for BC reasons, may be removed by ++ // https://www.drupal.org/node/2421941 ++ // - '<front>' -> '/' ++ // - '<front>#foo' -> '/#foo' ++ if (strpos($string, '<front>') === 0) { ++ $string = '/' . substr($string, strlen('<front>')); ++ } ++ $uri = 'internal:' . $string; ++ } ++ ++ return $uri; ++ } ++ ++ /** ++ * Form element validation handler for the 'uri' element. ++ * ++ * Disallows saving inaccessible or untrusted URLs. ++ */ ++ public static function validateUriElement($element, FormStateInterface $form_state, $form) { ++ $uri = static::getUserEnteredStringAsUri($element['#value']); ++ $form_state->setValueForElement($element, $uri); ++ ++ // If getUserEnteredStringAsUri() mapped the entered value to a 'internal:' ++ // URI , ensure the raw value begins with '/', '?' or '#'. ++ // @todo '<front>' is valid input for BC reasons, may be removed by ++ // https://www.drupal.org/node/2421941 ++ if (parse_url($uri, PHP_URL_SCHEME) === 'internal' && !in_array($element['#value'][0], ['/', '?', '#'], TRUE) && substr($element['#value'], 0, 7) !== '<front>') { ++ $form_state->setError($element, t('Manually entered paths should start with /, ? or #.')); ++ return; ++ } ++ } ++ ++ /** ++ * {@inheritdoc} ++ */ + public function validateForm(array &$form, FormStateInterface $form_state) { + parent::validateForm($form, $form_state); + diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index e6b913873ab99a0682be9b6c470c80d2694645f2..e4c2e2ded332cec32be9c212ef5ef88967e69c99 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -3870,7 +3870,7 @@ }, "patches_applied": { "2881745": "patches/entity_embed_2881745-22.patch", - "2511404": "https://www.drupal.org/files/issues/2018-09-17/entity-embed-link-2511404-68.patch" + "2511404": "patches/entity-embed-img-link-2511404-68.patch" } }, "installation-source": "dist", diff --git a/web/modules/entity_embed/entity_embed.module b/web/modules/entity_embed/entity_embed.module index 079bc82a615f91877bcebe32b70ca5a75521940c..ee8fbaee840f24a6ef98274ef7f42dcd1887b8b1 100644 --- a/web/modules/entity_embed/entity_embed.module +++ b/web/modules/entity_embed/entity_embed.module @@ -34,7 +34,7 @@ function template_preprocess_entity_embed_container(&$variables) { $variables['element'] += ['#attributes' => []]; $variables['attributes'] = $variables['element']['#attributes']; $variables['children'] = $variables['element']['#children']; - if (!empty($variables['element']['#context']['data-entity-embed-display-settings']['link_url'])) { + if (!empty($variables['element']['#context']['data-entity-embed-display-settings']['link_url'])) { $link = UrlHelper::filterBadProtocol($variables['element']['#context']['data-entity-embed-display-settings']['link_url']); if (!UrlHelper::isExternal($link)) { $link = 'internal:/' . ltrim($link, '/'); diff --git a/web/modules/entity_embed/src/Form/EntityEmbedDialog.php b/web/modules/entity_embed/src/Form/EntityEmbedDialog.php index a26cbc2ece691f22ad55c9098a25ffa4a128d059..fe16bd97c8c6cb090eaaed6521762067c23814f4 100644 --- a/web/modules/entity_embed/src/Form/EntityEmbedDialog.php +++ b/web/modules/entity_embed/src/Form/EntityEmbedDialog.php @@ -455,11 +455,7 @@ public function buildEmbedStep(array $form, FormStateInterface $form_state) { '#default_value' => isset($entity_element['data-entity-embed-display-settings']['link_url']) ? $this->getUriAsDisplayableString($entity_element['data-entity-embed-display-settings']['link_url']) : '', '#maxlength' => 2048, ]; - $form['attributes']['data-entity-embed-display-settings']['link_url_target'] = [ - '#title' => t('Open in a new window?'), - '#type' => 'checkbox', - '#default_value' => isset($entity_element['data-entity-embed-display-settings']['link_url_target']) ? Html::decodeEntities($entity_element['data-entity-embed-display-settings']['link_url_target']) : '', - ]; + $display = $this->entityEmbedDisplayManager->createInstance($plugin_id, $entity_element['data-entity-embed-display-settings']); $display->setContextValue('entity', $entity); $display->setAttributes($entity_element); @@ -635,9 +631,9 @@ public static function validateUriElement($element, FormStateInterface $form_sta } } - /** - * {@inheritdoc} - */ + /** + * {@inheritdoc} + */ public function validateForm(array &$form, FormStateInterface $form_state) { parent::validateForm($form, $form_state);