Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 6.0.x
  • 6.1.x
  • 6.x-1.x
  • 7.1.x
  • 7.x
  • 7.x-1.x
  • 7.x-2.x
  • 7.x-3.x
  • 8.x-4.x
  • 8.x-5.x
  • 6.0.0
  • 6.0.0-beta1
  • 6.0.0-beta2
  • 6.0.0-beta3
  • 6.0.0-beta4
  • 6.0.0-rc1
  • 6.0.0-rc2
  • 6.0.1
  • 6.0.2
  • 6.1.0
  • 6.1.0-rc1
  • 6.1.0-rc2
  • 6.1.1
  • 6.1.2
  • 6.1.3
  • 6.1.4
  • 6.1.5
  • 6.1.6
  • 6.1.7
  • 6.1.8
  • 6.x-1.0
  • 6.x-1.0-alpha1
  • 6.x-1.0-beta1
  • 6.x-1.1
  • 6.x-1.10
  • 6.x-1.11
  • 6.x-1.12
  • 6.x-1.2
  • 6.x-1.3
  • 6.x-1.4
  • 6.x-1.5
  • 6.x-1.6
  • 6.x-1.7
  • 6.x-1.8
  • 6.x-1.9
  • 7.0.0
  • 7.0.0-alpha1
  • 7.0.0-alpha2
  • 7.0.1
  • 7.0.2
  • 7.0.3
  • 7.0.4
  • 7.0.5
  • 7.0.6
  • 7.0.7
  • 7.0.8
  • 7.0.9
  • 7.x-1.0
  • 7.x-1.1
  • 7.x-1.2
  • 7.x-1.3
  • 7.x-2.0
  • 7.x-2.0-beta1
  • 7.x-2.0-beta2
  • 7.x-2.1
  • 7.x-2.2
  • 7.x-2.3
  • 7.x-2.4
  • 7.x-2.5
  • 7.x-2.6
  • 7.x-2.7
  • 7.x-3.0
  • 7.x-3.1
  • 7.x-3.2
  • 7.x-3.3
  • 7.x-3.4
  • 7.x-3.5
  • 7.x-3.6
  • 7.x-3.7
  • 7.x-3.8
  • 8.x-4.0
  • 8.x-4.1
  • 8.x-4.2
  • 8.x-4.3
  • 8.x-4.4
  • 8.x-5.0-alpha1
  • 8.x-5.0-beta1
  • 8.x-5.0-beta10
  • 8.x-5.0-beta11
  • 8.x-5.0-beta12
  • 8.x-5.0-beta13
  • 8.x-5.0-beta2
  • 8.x-5.0-beta3
  • 8.x-5.0-beta4
  • 8.x-5.0-beta5
  • 8.x-5.0-beta6
  • 8.x-5.0-beta7
  • 8.x-5.0-beta8
  • 8.x-5.0-beta9
99 results

Target

Select target project
No results found
Select Git revision
  • 6.0.x
  • 6.1.x
  • 6.x-1.x
  • 7.1.x
  • 7.x
  • 7.x-1.x
  • 7.x-2.x
  • 7.x-3.x
  • 8.x-4.x
  • 8.x-5.x
  • 6.0.0
  • 6.0.0-beta1
  • 6.0.0-beta2
  • 6.0.0-beta3
  • 6.0.0-beta4
  • 6.0.0-rc1
  • 6.0.0-rc2
  • 6.0.1
  • 6.0.2
  • 6.1.0
  • 6.1.0-rc1
  • 6.1.0-rc2
  • 6.1.1
  • 6.1.2
  • 6.1.3
  • 6.1.4
  • 6.1.5
  • 6.1.6
  • 6.1.7
  • 6.1.8
  • 6.x-1.0
  • 6.x-1.0-alpha1
  • 6.x-1.0-beta1
  • 6.x-1.1
  • 6.x-1.10
  • 6.x-1.11
  • 6.x-1.12
  • 6.x-1.2
  • 6.x-1.3
  • 6.x-1.4
  • 6.x-1.5
  • 6.x-1.6
  • 6.x-1.7
  • 6.x-1.8
  • 6.x-1.9
  • 7.0.0
  • 7.0.0-alpha1
  • 7.0.0-alpha2
  • 7.0.1
  • 7.0.2
  • 7.0.3
  • 7.0.4
  • 7.0.5
  • 7.0.6
  • 7.0.7
  • 7.0.8
  • 7.0.9
  • 7.x-1.0
  • 7.x-1.1
  • 7.x-1.2
  • 7.x-1.3
  • 7.x-2.0
  • 7.x-2.0-beta1
  • 7.x-2.0-beta2
  • 7.x-2.1
  • 7.x-2.2
  • 7.x-2.3
  • 7.x-2.4
  • 7.x-2.5
  • 7.x-2.6
  • 7.x-2.7
  • 7.x-3.0
  • 7.x-3.1
  • 7.x-3.2
  • 7.x-3.3
  • 7.x-3.4
  • 7.x-3.5
  • 7.x-3.6
  • 7.x-3.7
  • 7.x-3.8
  • 8.x-4.0
  • 8.x-4.1
  • 8.x-4.2
  • 8.x-4.3
  • 8.x-4.4
  • 8.x-5.0-alpha1
  • 8.x-5.0-beta1
  • 8.x-5.0-beta10
  • 8.x-5.0-beta11
  • 8.x-5.0-beta12
  • 8.x-5.0-beta13
  • 8.x-5.0-beta2
  • 8.x-5.0-beta3
  • 8.x-5.0-beta4
  • 8.x-5.0-beta5
  • 8.x-5.0-beta6
  • 8.x-5.0-beta7
  • 8.x-5.0-beta8
  • 8.x-5.0-beta9
99 results
Show changes

Commits on Source 6

9 files
+ 198
11
Compare changes
  • Side-by-side
  • Inline

Files

Original line number Original line Diff line number Diff line
@@ -98,6 +98,9 @@ filter_settings.linkit:
    title:
    title:
      type: boolean
      type: boolean
      label: 'Automatically set the "title" attribute'
      label: 'Automatically set the "title" attribute'
    media_substitution:
      type: string
      label: 'Media entity URL substitution'


# Plugin \Drupal\ckeditor\Plugin\CKEditorPlugin\DrupalLink
# Plugin \Drupal\ckeditor\Plugin\CKEditorPlugin\DrupalLink
# Linkit alters the plugin to save Linkit specific information used by the
# Linkit alters the plugin to save Linkit specific information used by the
Original line number Original line Diff line number Diff line
@@ -28,10 +28,13 @@
  max-height: calc((100vh - 80px) / 2);
  max-height: calc((100vh - 80px) / 2);
}
}


.linkit-ui-autocomplete.ui-widget {
:not(.ck) > .linkit-ui-autocomplete.ui-widget {
  position: absolute;
  position: absolute;
  max-width: inherit;
  max-width: inherit;
  font-size: 0.9em;
  font-size: 0.9em;
  &.ck-reset_all-excluded {
    white-space: break-spaces;
  }
}
}


.linkit-ui-autocomplete.ui-menu .linkit-result-line-wrapper {
.linkit-ui-autocomplete.ui-menu .linkit-result-line-wrapper {
@@ -89,3 +92,9 @@
.linkit-result-line--description img {
.linkit-result-line--description img {
  display: block;
  display: block;
}
}

/* Required to accommodate CKEditor v45 UI changes. See #3532814 */
.ck.ck-form.ck-link-form.ck-vertical-form {
  width: fit-content;
  min-width: 340px;
}
+24 −0
Original line number Original line Diff line number Diff line
.linkit-widget-container .fieldset__wrapper,
.linkit-widget-container .fieldset-wrapper {
  display: flex;
  flex-flow: row wrap;
  column-gap: var(--space-l, 10px);
  > * {
    width: 100%;
    /* Fix none collapsing margins (caused by flex) */
    margin-bottom: 0;
  }
  > .form-item--linkit-widget-uri,
  > .form-item--linkit-widget-title {
    flex: 1 1 auto;
    width: calc(50% - var(--space-l, 10px));
    min-width: 20em;
    input {
      width: 100%;
    }
  }
  /* Claro specific fixes */
  .claro-autocomplete {
    width: 100%;
  }
}
Original line number Original line Diff line number Diff line
@@ -3,6 +3,11 @@ linkit.admin:
    theme:
    theme:
      css/linkit.admin.theme.css: {}
      css/linkit.admin.theme.css: {}


linkit.widget:
  css:
    theme:
      css/linkit.widget.theme.css: {}

linkit.base:
linkit.base:
  js:
  js:
    js/linkit.js: {}
    js/linkit.js: {}
Original line number Original line Diff line number Diff line
@@ -60,7 +60,7 @@ class AutocompleteController implements ContainerInjectionInterface {
    // The erroneous variable name $linkit_profile_id is to avoid BC breaks.
    // The erroneous variable name $linkit_profile_id is to avoid BC breaks.
    $string = $request->query->get('q');
    $string = $request->query->get('q');


    $suggestionCollection = $this->suggestionManager->getSuggestions($linkit_profile_id, mb_strtolower($string));
    $suggestionCollection = $this->suggestionManager->getSuggestions($linkit_profile_id, $string);


    /*
    /*
     * If there are no suggestions from the matcher plugins, we have to add a
     * If there are no suggestions from the matcher plugins, we have to add a
Original line number Original line Diff line number Diff line
@@ -130,8 +130,14 @@ class LinkitWidget extends LinkWidget {
    $item = $items[$delta];
    $item = $items[$delta];
    $uri = $item->uri ?? NULL;
    $uri = $item->uri ?? NULL;


    try {
      // Try to fetch entity information from the URI.
      // Try to fetch entity information from the URI.
      $default_allowed = !$item->isEmpty() && ($this->currentUser->hasPermission('link to any page') || $item->getUrl()->access());
      $default_allowed = !$item->isEmpty() && ($this->currentUser->hasPermission('link to any page') || $item->getUrl()->access());
    }
    catch (\InvalidArgumentException $e) {
      // Make sure we render the form if InvalidArgumentException is thrown.
    }

    if (!empty($item->options['data-entity-type']) && !empty($item->options['data-entity-uuid'])) {
    if (!empty($item->options['data-entity-type']) && !empty($item->options['data-entity-uuid'])) {
      $entity = $this->entityRepository->loadEntityByUuid($item->options['data-entity-type'], $item->options['data-entity-uuid']);
      $entity = $this->entityRepository->loadEntityByUuid($item->options['data-entity-type'], $item->options['data-entity-uuid']);
    }
    }
@@ -165,8 +171,13 @@ class LinkitWidget extends LinkWidget {
      'linkit_profile_id' => $this->getSetting('linkit_profile'),
      'linkit_profile_id' => $this->getSetting('linkit_profile'),
    ];
    ];


    // Add a class to the title field.
    // Add class to the URI fields item wrapper.
    $element['uri']['#wrapper_attributes']['class'][] = 'form-item--linkit-widget-uri';

    // Add a class to the title field and its item wrapper.
    $element['title']['#attributes']['class'][] = 'linkit-widget-title';
    $element['title']['#attributes']['class'][] = 'linkit-widget-title';
    $element['title']['#wrapper_attributes']['class'][] = 'form-item--linkit-widget-title';

    if ($this->getSetting('linkit_auto_link_text')) {
    if ($this->getSetting('linkit_auto_link_text')) {
      $element['title']['#attributes']['data-linkit-widget-title-autofill-enabled'] = TRUE;
      $element['title']['#attributes']['data-linkit-widget-title-autofill-enabled'] = TRUE;
    }
    }
@@ -189,6 +200,10 @@ class LinkitWidget extends LinkWidget {
      '#default_value' => $entity ? ($entity->getEntityTypeId() === 'file' ? 'file' : 'canonical') : '',
      '#default_value' => $entity ? ($entity->getEntityTypeId() === 'file' ? 'file' : 'canonical') : '',
    ];
    ];


    // Add custom css for the widget representation:
    $element['#attached']['library'][] = 'linkit/linkit.widget';
    // Add a custom class to the parent container:
    $element['#attributes']['class'][] = 'linkit-widget-container';
    return $element;
    return $element;
  }
  }


Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 *   description = @Translation("Updates links inserted by Linkit to point to entity URL aliases."),
 *   description = @Translation("Updates links inserted by Linkit to point to entity URL aliases."),
 *   settings = {
 *   settings = {
 *     "title" = TRUE,
 *     "title" = TRUE,
 *     "media_substitution" = "metadata",
 *   },
 *   },
 *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
 *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
 * )
 * )
@@ -116,6 +117,12 @@ class LinkitFilter extends FilterBase implements ContainerFactoryPluginInterface
          if (!$substitution_type = $element->getAttribute('data-entity-substitution')) {
          if (!$substitution_type = $element->getAttribute('data-entity-substitution')) {
            $substitution_type = $entity_type === 'file' ? 'file' : SubstitutionManagerInterface::DEFAULT_SUBSTITUTION;
            $substitution_type = $entity_type === 'file' ? 'file' : SubstitutionManagerInterface::DEFAULT_SUBSTITUTION;
          }
          }
          if ($entity_type === 'media') {
            $substitution_options = $this->substitutionManager->getApplicablePluginsOptionList('media');
            if (in_array($this->settings['media_substitution'], array_keys($substitution_options))) {
              $substitution_type = $this->settings['media_substitution'];
            }
          }


          $entity = $this->entityRepository->loadEntityByUuid($entity_type, $uuid);
          $entity = $this->entityRepository->loadEntityByUuid($entity_type, $uuid);
          if ($entity) {
          if ($entity) {
@@ -188,6 +195,17 @@ class LinkitFilter extends FilterBase implements ContainerFactoryPluginInterface
      '#title' => $this->t('Automatically set the <code>title</code> attribute to that of the (translated) referenced content'),
      '#title' => $this->t('Automatically set the <code>title</code> attribute to that of the (translated) referenced content'),
      '#default_value' => $this->settings['title'],
      '#default_value' => $this->settings['title'],
    ];
    ];
    if (\Drupal::moduleHandler()->moduleExists('media')) {
      $substitution_options = $this->substitutionManager->getApplicablePluginsOptionList('media');
      $form['media_substitution'] = [
        '#type' => 'select',
        '#title' => $this->t('Media entity URL substitution'),
        '#options' => [
          'metadata' => $this->t('Use metadata from when the link was created'),
        ] + $substitution_options,
        '#default_value' => $this->settings['media_substitution'] ?? 'metadata',
      ];
    }
    return $form;
    return $form;
  }
  }


Original line number Original line Diff line number Diff line
@@ -3,6 +3,7 @@
namespace Drupal\linkit\Plugin\Linkit\Matcher;
namespace Drupal\linkit\Plugin\Linkit\Matcher;


use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Query\QueryInterface;
use Drupal\Core\Entity\Query\QueryInterface;
@@ -104,6 +105,13 @@ class EntityMatcher extends ConfigurableMatcherBase {
   */
   */
  protected $configFactory;
  protected $configFactory;


  /**
   * The request context.
   *
   * @var \Drupal\Core\Routing\RequestContext
   */
  protected $requestContext;

  /**
  /**
   * {@inheritdoc}
   * {@inheritdoc}
   */
   */
@@ -123,6 +131,7 @@ class EntityMatcher extends ConfigurableMatcherBase {
    $instance->substitutionManager = $container->get('plugin.manager.linkit.substitution');
    $instance->substitutionManager = $container->get('plugin.manager.linkit.substitution');
    $instance->token = $container->get('token');
    $instance->token = $container->get('token');
    $instance->configFactory = $container->get('config.factory');
    $instance->configFactory = $container->get('config.factory');
    $instance->requestContext = $container->get('router.request_context');
    return $instance;
    return $instance;
  }
  }


@@ -523,18 +532,31 @@ class EntityMatcher extends ConfigurableMatcherBase {
   *
   *
   * @param string $user_input
   * @param string $user_input
   *   The string to url parse.
   *   The string to url parse.
   * @param string $base_url
   *   The site base url. Typically this is only used for testing.
   *
   *
   * @return array
   * @return array
   *   An array with an entity id if the input can be parsed as an internal url
   *   An array with an entity id if the input can be parsed as an internal url
   *   and a match is found, otherwise an empty array.
   *   and a match is found, otherwise an empty array.
   */
   */
  protected function findEntityIdByUrl($user_input) {
  public function findEntityIdByUrl($user_input, $base_url = '') {
    $result = [];
    if (empty($base_url)) {
      $base_url = $this->requestContext->getCompleteBaseUrl();
    }
    $is_absolute_local_url = UrlHelper::isExternal($user_input)
      && UrlHelper::isValid($user_input, TRUE)
      && UrlHelper::externalIsLocal($user_input, $base_url);


    if ($is_absolute_local_url) {
      // The link points to this domain. Make it relative so it can be
      // matched in Url::fromUserInput().
      $user_input = substr($user_input, strlen($base_url));
    }
    $result = [];
    try {
    try {
      $params = Url::fromUserInput($user_input)->getRouteParameters();
      $params = Url::fromUserInput($user_input)->getRouteParameters();
      if (key($params) === $this->targetType) {
      if (!empty($params[$this->targetType])) {
        $result = [end($params)];
        $result = [$params[$this->targetType]];
      }
      }
    }
    }
    catch (\Exception $e) {
    catch (\Exception $e) {
Original line number Original line Diff line number Diff line
@@ -4,6 +4,7 @@ declare(strict_types=1);


namespace Drupal\Tests\linkit\Kernel\Matchers;
namespace Drupal\Tests\linkit\Kernel\Matchers;


use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
use Drupal\Tests\linkit\Kernel\LinkitKernelTestBase;
@@ -20,7 +21,15 @@ class NodeMatcherTest extends LinkitKernelTestBase {
   *
   *
   * @var array
   * @var array
   */
   */
  protected static $modules = ['field', 'node', 'content_moderation', 'workflows'];
  protected static $modules = [
    'field',
    'node',
    'content_moderation',
    'workflows',
    'language',
    'path',
    'path_alias',
  ];


  /**
  /**
   * The matcher manager.
   * The matcher manager.
@@ -37,7 +46,7 @@ class NodeMatcherTest extends LinkitKernelTestBase {


    $this->installEntitySchema('node');
    $this->installEntitySchema('node');
    $this->installSchema('node', ['node_access']);
    $this->installSchema('node', ['node_access']);
    $this->installConfig(['field', 'node']);
    $this->installConfig(['field', 'node', 'language']);


    $this->manager = $this->container->get('plugin.manager.linkit.matcher');
    $this->manager = $this->container->get('plugin.manager.linkit.matcher');


@@ -182,4 +191,86 @@ class NodeMatcherTest extends LinkitKernelTestBase {
    }
    }
  }
  }


  /**
   * Test node matches generated from an absolute URL input.
   */
  public function testNodeMatcherFromAbsoluteUrl() {
    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->manager->createInstance('entity:node');

    /** @var \Drupal\node\NodeInterface[] $nodes */
    $nodes = $this->container->get('entity_type.manager')->getStorage('node')->loadByProperties(['title' => 'Lorem Ipsum 1']);
    $node = reset($nodes);

    $suggestions = $plugin->execute($node->toUrl()->setAbsolute()->toString());
    $this->assertEquals(1, count($suggestions->getSuggestions()));

    // Check that URLs that don't match the drupal base URL do not get matched.
    $external_domain_url = $node->toUrl(NULL, ['base_url' => 'https://example.com'])->setAbsolute()->toString();
    $this->assertEquals(0, count($plugin->execute($external_domain_url)->getSuggestions()));
    $base_url = $this->container->get('router.request_context')->getCompleteBaseUrl();
    $non_drupal_base_path = $node->toUrl(NULL, ['base_url' => $base_url . '/some-other-sub-path'])->setAbsolute()->toString();
    $this->assertEquals(0, count($plugin->execute($non_drupal_base_path)->getSuggestions()));
  }

  /**
   * Test node matches generated from an absolute URL input.
   */
  public function testNodeMatcherFromAbsoluteUrlWithLanguagePrefix() {
    /** @var \Drupal\linkit\MatcherInterface $plugin */
    $plugin = $this->manager->createInstance('entity:node');

    $langcode = 'nl';
    ConfigurableLanguage::createFromLangcode($langcode)->save();
    \Drupal::configFactory()->getEditable('language.negotiation')
      ->set('url.prefixes.nl', $langcode)
      ->save();

    // In order to reflect the changes for a multilingual site in the container
    // we have to rebuild it.
    \Drupal::service('kernel')->rebuildContainer();

    /** @var \Drupal\node\NodeInterface[] $nodes */
    $nodes = $this->container->get('entity_type.manager')->getStorage('node')->loadByProperties(['title' => 'Lorem Ipsum 1']);
    $node = reset($nodes);
    $translation = $node->addTranslation($langcode, $node->toArray());
    $translation->save();

    $translated_url = $translation->toUrl()->setAbsolute()->toString();
    // Make sure the translated URL contains our prefix.
    $this->assertStringContainsString('/' . $langcode . '/', (string) $translated_url);
    $suggestions = $plugin->execute($translated_url);
    $this->assertEquals(1, count($suggestions->getSuggestions()));

    $base_urls = [
      'https://domainname/',
      'https://domainname/prefix-a/',
    ];
    foreach ($base_urls as $base_url) {
      // Test that <domainname>/<internal-path> returns a positive match.
      $url = $node->toUrl(NULL, ['base_url' => $base_url])->setAbsolute()->toString();
      $matches = $plugin->findEntityIdByUrl($url, $base_url);
      $this->assertEquals(1, count($matches));
      // Test that <domainname>/<langcode>/<internal-path> returns a positive
      // match.
      $translated_url = $translation->toUrl(NULL, ['base_url' => $base_url])->setAbsolute()->toString();
      $matches = $plugin->findEntityIdByUrl($translated_url, $base_url);
      $this->assertEquals(1, count($matches));
    }
    $node->set('path', '/test-path');
    $node->save();
    $translation->set('path', '/test-pad');
    $translation->save();
    foreach ($base_urls as $base_url) {
      // Test that <domainname>/<alias> returns a positive match.
      $url = $node->toUrl(NULL, ['base_url' => $base_url])->setAbsolute()->toString();
      $matches = $plugin->findEntityIdByUrl($url, $base_url);
      $this->assertEquals(1, count($matches));
      // Test that <domainname>/<langcode>/<alias> returns a positive match.
      $translated_url = $translation->toUrl(NULL, ['base_url' => $base_url])->setAbsolute()->toString();
      $matches = $plugin->findEntityIdByUrl($translated_url, $base_url);
      $this->assertEquals([], $matches);
    }
  }

}
}