diff --git a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php index db00fedc97a98afa0aa2f52b81d038d298942ae4..278e8010a22f0a49666e7992dc1ff2afb263522d 100644 --- a/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php +++ b/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php @@ -79,6 +79,9 @@ protected static function getUriAsDisplayableString($uri) { $displayable_string = EntityAutocomplete::getEntityLabels([$entity]); } } + elseif ($scheme === 'route') { + $displayable_string = ltrim($displayable_string, 'route:'); + } return $displayable_string; } @@ -111,6 +114,10 @@ protected static function getUserEnteredStringAsUri($string) { // https://www.drupal.org/node/2423093. $uri = 'entity:node/' . $entity_id; } + // Support linking to nothing. + elseif (in_array($string, ['<nolink>', '<none>'], TRUE)) { + $uri = 'route:' . $string; + } // 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 @@ -209,12 +216,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen // element prefix and description. if (!$this->supportsExternalLinks()) { $element['uri']['#field_prefix'] = rtrim(Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(), '/'); - $element['uri']['#description'] = $this->t('This must be an internal path such as %add-node. You can also start typing the title of a piece of content to select it. Enter %front to link to the front page.', ['%add-node' => '/node/add', '%front' => '<front>']); + $element['uri']['#description'] = $this->t('This must be an internal path such as %add-node. You can also start typing the title of a piece of content to select it. Enter %front to link to the front page. Enter %nolink to display link text only.', ['%add-node' => '/node/add', '%front' => '<front>', '%nolink' => '<nolink>']); } // If the field is configured to allow both internal and external links, // show a useful description. elseif ($this->supportsExternalLinks() && $this->supportsInternalLinks()) { - $element['uri']['#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']); + $element['uri']['#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. Enter %nolink to display link text only.', ['%front' => '<front>', '%add-node' => '/node/add', '%url' => 'http://example.com', '%nolink' => '<nolink>']); } // If the field is configured to allow only external links, show a useful // description. diff --git a/core/modules/link/tests/src/Functional/LinkFieldTest.php b/core/modules/link/tests/src/Functional/LinkFieldTest.php index d377888f683b787ba17c163425626cf245395b75..5035e749038ced8f60720677118433cdc947c07c 100644 --- a/core/modules/link/tests/src/Functional/LinkFieldTest.php +++ b/core/modules/link/tests/src/Functional/LinkFieldTest.php @@ -4,6 +4,7 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Unicode; +use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Url; use Drupal\entity_test\Entity\EntityTest; use Drupal\field\Entity\FieldConfig; @@ -133,6 +134,11 @@ public function testURLValidation() { '<front>#example' => '<front>#example', '<front>?example=llama' => '<front>?example=llama', + // Text-only links. + '<nolink>' => '<nolink>', + 'route:<nolink>' => '<nolink>', + '<none>' => '<none>', + // Query string and fragment. '?example=llama' => '?example=llama', '#example' => '#example', @@ -734,6 +740,73 @@ public function testEditNonNodeEntityLink() { $this->assertEquals($correct_link, $entity_test->get('field_link')->uri); } + /** + * Test <nolink> and <none> as link uri. + */ + public function testNoLinkUri() { + $field_name = mb_strtolower($this->randomMachineName()); + $this->fieldStorage = FieldStorageConfig::create([ + 'field_name' => $field_name, + 'entity_type' => 'entity_test', + 'type' => 'link', + 'cardinality' => 1, + ]); + $this->fieldStorage->save(); + FieldConfig::create([ + 'field_storage' => $this->fieldStorage, + 'label' => 'Read more about this entity', + 'bundle' => 'entity_test', + 'settings' => [ + 'title' => DRUPAL_OPTIONAL, + 'link_type' => LinkItemInterface::LINK_INTERNAL, + ], + ])->save(); + + $this->container->get('entity_type.manager') + ->getStorage('entity_form_display') + ->load('entity_test.entity_test.default') + ->setComponent($field_name, [ + 'type' => 'link_default', + ]) + ->save(); + + EntityViewDisplay::create([ + 'targetEntityType' => 'entity_test', + 'bundle' => 'entity_test', + 'mode' => 'full', + 'status' => TRUE, + ])->setComponent($field_name, [ + 'type' => 'link', + ]) + ->save(); + + // Test a link with <nolink> uri. + $edit = [ + "{$field_name}[0][title]" => 'Title, no link', + "{$field_name}[0][uri]" => '<nolink>', + ]; + + $this->drupalPostForm('/entity_test/add', $edit, t('Save')); + preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); + $id = $match[1]; + $output = $this->renderTestEntity($id); + $expected_link = (string) $this->container->get('link_generator')->generate('Title, no link', Url::fromUri('route:<nolink>')); + $this->assertContains($expected_link, $output); + + // Test a link with <none> uri. + $edit = [ + "{$field_name}[0][title]" => 'Title, none', + "{$field_name}[0][uri]" => '<none>', + ]; + + $this->drupalPostForm('/entity_test/add', $edit, t('Save')); + preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); + $id = $match[1]; + $output = $this->renderTestEntity($id); + $expected_link = (string) $this->container->get('link_generator')->generate('Title, none', Url::fromUri('route:<none>')); + $this->assertContains($expected_link, $output); + } + /** * Renders a test_entity and returns the output. * diff --git a/core/modules/link/tests/src/Functional/LinkFieldUITest.php b/core/modules/link/tests/src/Functional/LinkFieldUITest.php index 69a47b18bbe35d978db926bdf1db7a869384ef0a..2768770665221722370d375e10ee1a4eac2d0cd5 100644 --- a/core/modules/link/tests/src/Functional/LinkFieldUITest.php +++ b/core/modules/link/tests/src/Functional/LinkFieldUITest.php @@ -197,7 +197,7 @@ public function runFieldUIItem($cardinality, $link_type, $title, $label, $field_ $expected_help_texts = [ LinkItemInterface::LINK_EXTERNAL => 'This must be an external URL such as <em class="placeholder">http://example.com</em>.', - LinkItemInterface::LINK_GENERIC => 'You can also enter an internal path such as <em class="placeholder">/node/add</em> or an external URL such as <em class="placeholder">http://example.com</em>. Enter <em class="placeholder"><front></em> to link to the front page.', + LinkItemInterface::LINK_GENERIC => 'You can also enter an internal path such as <em class="placeholder">/node/add</em> or an external URL such as <em class="placeholder">http://example.com</em>. Enter <em class="placeholder"><front></em> to link to the front page. Enter <em class="placeholder"><nolink></em> to display link text only', LinkItemInterface::LINK_INTERNAL => rtrim(Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(), '/'), ];