diff --git a/composer.json b/composer.json index 32dac173e4581715e23a006c76a84fcd2d1198ad..b425dbbb80aa9a83d33b1b3fc2d782280b9967fb 100644 --- a/composer.json +++ b/composer.json @@ -132,7 +132,7 @@ "drupal/image_popup": "1.1", "drupal/inline_entity_form": "1.0-rc1", "drupal/libraries": "^3.0@alpha", - "drupal/link_attributes": "1.0", + "drupal/link_attributes": "^1.0", "drupal/linkit": "5.0-beta10", "drupal/magnific_popup": "1.3", "drupal/mathjax": "^2.7", diff --git a/composer.lock b/composer.lock index 93e3412a9a32f524379167a4369c9d5a115afb9f..3efcced53ccac12228c45763ce949ba00613c19e 100644 --- a/composer.lock +++ b/composer.lock @@ -5320,20 +5320,20 @@ }, { "name": "drupal/link_attributes", - "version": "1.0.0", + "version": "1.10.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/link_attributes.git", - "reference": "8.x-1.0" + "reference": "8.x-1.10" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/link_attributes-8.x-1.0.zip", - "reference": "8.x-1.0", - "shasum": "8a5851467f17c01b4dcb6e446f00cd7abe116475" + "url": "https://ftp.drupal.org/files/projects/link_attributes-8.x-1.10.zip", + "reference": "8.x-1.10", + "shasum": "3df450b83a05911575aaf9b234a3b43833d3c1c2" }, "require": { - "drupal/core": "*" + "drupal/core": "^8 || ^9" }, "type": "drupal-module", "extra": { @@ -5341,8 +5341,8 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0", - "datestamp": "1500846243", + "version": "8.x-1.10", + "datestamp": "1580259496", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -5362,7 +5362,7 @@ "description": "Provides a widget to allow settings of link attributes for menu links.", "homepage": "https://www.drupal.org/project/link_attributes", "support": { - "source": "http://cgit.drupalcode.org/link_attributes" + "source": "https://git.drupalcode.org/project/link_attributes" } }, { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index e5803b8f435b1f9af2c66846fa36699bd65f144d..740dd72003ab75f1b0f03470d541732d058802b6 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -5484,21 +5484,21 @@ }, { "name": "drupal/link_attributes", - "version": "1.0.0", - "version_normalized": "1.0.0.0", + "version": "1.10.0", + "version_normalized": "1.10.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/link_attributes.git", - "reference": "8.x-1.0" + "reference": "8.x-1.10" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/link_attributes-8.x-1.0.zip", - "reference": "8.x-1.0", - "shasum": "8a5851467f17c01b4dcb6e446f00cd7abe116475" + "url": "https://ftp.drupal.org/files/projects/link_attributes-8.x-1.10.zip", + "reference": "8.x-1.10", + "shasum": "3df450b83a05911575aaf9b234a3b43833d3c1c2" }, "require": { - "drupal/core": "*" + "drupal/core": "^8 || ^9" }, "type": "drupal-module", "extra": { @@ -5506,8 +5506,8 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0", - "datestamp": "1500846243", + "version": "8.x-1.10", + "datestamp": "1580259496", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -5528,7 +5528,7 @@ "description": "Provides a widget to allow settings of link attributes for menu links.", "homepage": "https://www.drupal.org/project/link_attributes", "support": { - "source": "http://cgit.drupalcode.org/link_attributes" + "source": "https://git.drupalcode.org/project/link_attributes" } }, { diff --git a/web/modules/link_attributes/README.md b/web/modules/link_attributes/README.md index 734f823de49f024aa68211f14a5b1216c0885121..64067f2a463f815c76334838e7d2fb15bf2a18a5 100644 --- a/web/modules/link_attributes/README.md +++ b/web/modules/link_attributes/README.md @@ -1,9 +1,57 @@ -## Link attributes +CONTENTS OF THIS FILE +--------------------- -Provides an alternate widget for the link field that allows setting attributes. + * Introduction + * Requirements + * Installation + * Configuration + * Maintainers -By default adds class, rel and target attributes to menu link content entitites. -## Known issues +INTRODUCTION +------------ -You need [this core patch](https://www.drupal.org/files/issues/2760557-link-options.pass_.patch). +The link attributes module provides a widget that allows users to add +attributes to links. It overtakes the core default widget for menu link +content entities, allowing you to set attributes on menu links. + + * For a full description of the module, visit the project page: + https://www.drupal.org/project/link_attributes + + +REQUIREMENTS +------------ + +This module requires no modules outside of Drupal core. + + +INSTALLATION +------------ + + * Install as you would normally install a contributed Drupal module. Visit: + https://www.drupal.org/documentation/install/modules-themes/modules-8 for + further information. + + +CONFIGURATION +------------- + +The module has no menu or modifiable settings. There is no configuration. Once +enabled, the module will add class, rel and target attributes to menu link +content entities by default. + +In order to use this functionality, follow the following steps: + + * Enable the module like normal + * It will immediately take effect on *menu link content* entities. + * For other link fields, edit the widget using 'Manage form display' + and select the 'Link (with attributes)' widget + +You can also follow along with this [screencast](https://vimeo.com/233507094) to +configure the field settings. + + +MAINTAINERS +----------- + + * Lee Rowlands (larowlan) - https://www.drupal.org/u/larowlan diff --git a/web/modules/link_attributes/link_attributes.api.php b/web/modules/link_attributes/link_attributes.api.php new file mode 100644 index 0000000000000000000000000000000000000000..783d616df2192c6b0925f5e85a4905045b38a531 --- /dev/null +++ b/web/modules/link_attributes/link_attributes.api.php @@ -0,0 +1,26 @@ +<?php + +/** + * @file + * Hooks related to the Link Attributes module. + */ + +/** + * @addtogroup hooks + * @{ + */ + +/** + * Modify the definitions of link attribute plugins. + * + * @param array[] $plugins + * Link attribute plugin definitions. + */ +function hook_link_attributes_plugin_alter(array &$plugins) { + // Set a default value for the target attribute. + $plugins['target']['default_value'] = '_blank'; +} + +/** + * @} End of "addtogroup hooks". + */ diff --git a/web/modules/link_attributes/link_attributes.info.yml b/web/modules/link_attributes/link_attributes.info.yml index d0309d7860bd02dba885506ef973a0d3cc390850..4609f004dd3eb629a7ef740cab2e70381f22ff29 100644 --- a/web/modules/link_attributes/link_attributes.info.yml +++ b/web/modules/link_attributes/link_attributes.info.yml @@ -1,13 +1,13 @@ name: Link attributes type: module description: Provides a widget to allow settings of link attributes for menu links. -# core: 8.x +core: 8.x +core_version_requirement: ^8 || ^9 dependencies: - drupal:link - - drupal:menu_link_content + - drupal:system (>=8.4) -# Information added by Drupal.org packaging script on 2016-12-16 -version: '8.x-1.0' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-01-29 +version: '8.x-1.10' project: 'link_attributes' -datestamp: 1481849585 +datestamp: 1580259499 diff --git a/web/modules/link_attributes/link_attributes.link_attributes.yml b/web/modules/link_attributes/link_attributes.link_attributes.yml new file mode 100644 index 0000000000000000000000000000000000000000..0ebe2e7cf1e31a9ced4f6422f63ff32a9ca95b05 --- /dev/null +++ b/web/modules/link_attributes/link_attributes.link_attributes.yml @@ -0,0 +1,21 @@ +id: + title: ID +name: + title: Name +target: + title: Target + type: select + empty_value: '' + options: + _self: Same window (_self) + _blank: New window (_blank) +rel: + title: Rel +class: + title: Class +accesskey: + title: Accesskey +aria-label: + title: ARIA Label +title: + title: Title diff --git a/web/modules/link_attributes/link_attributes.module b/web/modules/link_attributes/link_attributes.module index c98ff917c23b7340a66f4c8442f8a57f183813e7..69acd9ca238b57403b608cd1e224ea602ae9532b 100644 --- a/web/modules/link_attributes/link_attributes.module +++ b/web/modules/link_attributes/link_attributes.module @@ -4,6 +4,7 @@ * @file * Contains main module functions. */ + use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Routing\RouteMatchInterface; diff --git a/web/modules/link_attributes/link_attributes.services.yml b/web/modules/link_attributes/link_attributes.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..8a2e34c48d2f71515e9f62234f3e32b6bc886165 --- /dev/null +++ b/web/modules/link_attributes/link_attributes.services.yml @@ -0,0 +1,4 @@ +services: + plugin.manager.link_attributes: + class: Drupal\link_attributes\LinkAttributesManager + arguments: ['@module_handler', '@cache.discovery'] diff --git a/web/modules/link_attributes/src/LinkAttributesManager.php b/web/modules/link_attributes/src/LinkAttributesManager.php new file mode 100644 index 0000000000000000000000000000000000000000..9fbe801348c85a2476de346a8a7cca4a91b26edf --- /dev/null +++ b/web/modules/link_attributes/src/LinkAttributesManager.php @@ -0,0 +1,66 @@ +<?php + +namespace Drupal\link_attributes; + +use Drupal\Component\Plugin\PluginManagerInterface; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\Plugin\DefaultPluginManager; +use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; +use Drupal\Core\Plugin\Discovery\YamlDiscovery; + +/** + * Provides the link_attributes plugin manager. + */ +class LinkAttributesManager extends DefaultPluginManager implements PluginManagerInterface { + + /** + * Provides default values for all link_attributes plugins. + * + * @var array + */ + protected $defaults = [ + 'title' => '', + 'type' => '', + 'description' => '', + ]; + + /** + * Constructs a LinkAttributesManager object. + * + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend + * Cache backend instance to use. + */ + public function __construct(ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend) { + $this->alterInfo('link_attributes_plugin'); + $this->moduleHandler = $module_handler; + $this->setCacheBackend($cache_backend, 'link_attributes', ['link_attributes']); + } + + /** + * {@inheritdoc} + */ + protected function getDiscovery() { + if (!isset($this->discovery)) { + $this->discovery = new YamlDiscovery('link_attributes', $this->moduleHandler->getModuleDirectories()); + $this->discovery->addTranslatableProperty('title'); + $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); + } + return $this->discovery; + } + + /** + * {@inheritdoc} + */ + public function processDefinition(&$definition, $plugin_id) { + parent::processDefinition($definition, $plugin_id); + + // Make sure each plugin definition had at least a field type. + if (empty($definition['type'])) { + $definition['type'] = 'textfield'; + } + } + +} diff --git a/web/modules/link_attributes/src/Plugin/Field/FieldWidget/LinkWithAttributesWidget.php b/web/modules/link_attributes/src/Plugin/Field/FieldWidget/LinkWithAttributesWidget.php index 3f628a5af36d930baa067e5995faf9d374903482..e298e3d4b7c11c3299d930b146dfd04da0b18c6b 100644 --- a/web/modules/link_attributes/src/Plugin/Field/FieldWidget/LinkWithAttributesWidget.php +++ b/web/modules/link_attributes/src/Plugin/Field/FieldWidget/LinkWithAttributesWidget.php @@ -2,9 +2,13 @@ namespace Drupal\link_attributes\Plugin\Field\FieldWidget; +use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\link\Plugin\Field\FieldWidget\LinkWidget; +use Drupal\link_attributes\LinkAttributesManager; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Plugin implementation of the 'link' widget. @@ -17,13 +21,55 @@ * } * ) */ -class LinkWithAttributesWidget extends LinkWidget { +class LinkWithAttributesWidget extends LinkWidget implements ContainerFactoryPluginInterface { + + /** + * The link attributes manager. + * + * @var \Drupal\link_attributes\LinkAttributesManager + */ + protected $linkAttributesManager; + + /** + * Constructs a LinkWithAttributesWidget object. + * + * @param string $plugin_id + * The plugin_id for the widget. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The definition of the field to which the widget is associated. + * @param array $settings + * The widget settings. + * @param array $third_party_settings + * Any third party settings. + * @param \Drupal\link_attributes\LinkAttributesManager $link_attributes_manager + * The link attributes manager. + */ + public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, LinkAttributesManager $link_attributes_manager) { + parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings); + $this->linkAttributesManager = $link_attributes_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['third_party_settings'], + $container->get('plugin.manager.link_attributes') + ); + } /** * {@inheritdoc} */ public static function defaultSettings() { - return array( + return [ 'placeholder_url' => '', 'placeholder_title' => '', 'enabled_attributes' => [ @@ -34,7 +80,7 @@ public static function defaultSettings() { 'class' => TRUE, 'accesskey' => FALSE, ], - ) + parent::defaultSettings(); + ] + parent::defaultSettings(); } /** @@ -44,7 +90,6 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element = parent::formElement($items, $delta, $element, $form, $form_state); // Add each of the enabled attributes. // @todo move this to plugins that nominate form and label. - $item = $items[$delta]; $options = $item->get('options')->getValue(); @@ -55,13 +100,23 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#tree' => TRUE, '#open' => count($attributes), ]; + $plugin_definitions = $this->linkAttributesManager->getDefinitions(); foreach (array_keys(array_filter($this->getSetting('enabled_attributes'))) as $attribute) { - $element['options']['attributes'][$attribute] = [ - '#type' => 'textfield', - '#title' => $attribute, - '#description' => $this->t('Enter value for the @attribute attribute', ['@attribute' => $attribute]), - '#default_value' => isset($attributes[$attribute]) ? $attributes[$attribute] : '', - ]; + if (isset($plugin_definitions[$attribute])) { + foreach ($plugin_definitions[$attribute] as $property => $value) { + $element['options']['attributes'][$attribute]['#' . $property] = $value; + } + + // Set the default value, in case of a class that is stored as array, + // convert it back to a string. + $default_value = isset($attributes[$attribute]) ? $attributes[$attribute] : NULL; + if ($attribute === 'class' && is_array($default_value)) { + $default_value = implode(' ', $default_value); + } + if (isset($default_value)) { + $element['options']['attributes'][$attribute]['#default_value'] = $default_value; + } + } } return $element; } @@ -71,18 +126,41 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen */ public function settingsForm(array $form, FormStateInterface $form_state) { $element = parent::settingsForm($form, $form_state); - $options = ['id', 'name', 'target', 'rel', 'class', 'accesskey']; + $options = array_map(function ($plugin_definition) { + return $plugin_definition['title']; + }, $this->linkAttributesManager->getDefinitions()); $selected = array_keys(array_filter($this->getSetting('enabled_attributes'))); $element['enabled_attributes'] = [ '#type' => 'checkboxes', '#title' => $this->t('Enabled attributes'), - '#options' => array_combine($options, $options), + '#options' => $options, '#default_value' => array_combine($selected, $selected), '#description' => $this->t('Select the attributes to allow the user to edit.'), ]; return $element; } + /** + * {@inheritdoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + // Convert a class string to an array so that it can be merged reliable. + foreach ($values as $delta => $value) { + if (isset($value['options']['attributes']['class']) && is_string($value['options']['attributes']['class'])) { + $values[$delta]['options']['attributes']['class'] = explode(' ', $value['options']['attributes']['class']); + } + } + + return array_map(function (array $value) { + if (isset($value['options']['attributes'])) { + $value['options']['attributes'] = array_filter($value['options']['attributes'], function ($attribute) { + return $attribute !== ""; + }); + } + return $value; + }, $values); + } + /** * {@inheritdoc} */ @@ -90,7 +168,7 @@ public function settingsSummary() { $summary = parent::settingsSummary(); $enabled_attributes = array_filter($this->getSetting('enabled_attributes')); if ($enabled_attributes) { - $summary[] = $this->t('With attributes: @attributes', array('@attributes' => implode(', ', array_keys($enabled_attributes)))); + $summary[] = $this->t('With attributes: @attributes', ['@attributes' => implode(', ', array_keys($enabled_attributes))]); } return $summary; } diff --git a/web/modules/link_attributes/tests/modules/link_attributes_test_alterinfo/link_attributes_test_alterinfo.info.yml b/web/modules/link_attributes/tests/modules/link_attributes_test_alterinfo/link_attributes_test_alterinfo.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..a449282d9f69e82229349b396f5fc5e78b891c8d --- /dev/null +++ b/web/modules/link_attributes/tests/modules/link_attributes_test_alterinfo/link_attributes_test_alterinfo.info.yml @@ -0,0 +1,12 @@ +name: 'Link attributes alterInfo Test' +description: 'Implements hook_link_attributes_plugin_alter' +type: module +core: 8.x +core_version_requirement: ^8 || ^9 +dependencies: + - link_attributes:link_attributes + +# Information added by Drupal.org packaging script on 2020-01-29 +version: '8.x-1.10' +project: 'link_attributes' +datestamp: 1580259499 diff --git a/web/modules/link_attributes/tests/modules/link_attributes_test_alterinfo/link_attributes_test_alterinfo.module b/web/modules/link_attributes/tests/modules/link_attributes_test_alterinfo/link_attributes_test_alterinfo.module new file mode 100644 index 0000000000000000000000000000000000000000..aff63f3ad952fa27a25a8bafe7344b02cb1369e0 --- /dev/null +++ b/web/modules/link_attributes/tests/modules/link_attributes_test_alterinfo/link_attributes_test_alterinfo.module @@ -0,0 +1,24 @@ +<?php + +/** + * @file + * Link attributes test module. + */ + +/** + * Implements hook_link_attributes_plugin_alter(). + */ +function link_attributes_test_alterinfo_link_attributes_plugin_alter(array &$definitions) { + // Alter only if our state flag is set. + if (\Drupal::state()->get('link_attributes_test_alterinfo.hook_link_attributes_plugin_alter')) { + $definitions['class']['title'] = t('Link style'); + $definitions['class']['description'] = t('Select how the link should be displayed.'); + $definitions['class']['type'] = 'select'; + $definitions['class']['options'] = [ + 'link' => 'Link', + 'button' => 'Button', + ]; + $definitions['class']['default_value'] = 'button'; + $definitions['target']['default_value'] = '_blank'; + } +} diff --git a/web/modules/link_attributes/tests/src/Functional/LinkAttributesFieldTest.php b/web/modules/link_attributes/tests/src/Functional/LinkAttributesFieldTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1a9301f8a4f709d3e231bd123727b309c07f72fe --- /dev/null +++ b/web/modules/link_attributes/tests/src/Functional/LinkAttributesFieldTest.php @@ -0,0 +1,185 @@ +<?php + +namespace Drupal\Tests\link_attributes\Functional; + +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; + +/** + * Tests link attributes functionality. + * + * @group link_attributes + */ +class LinkAttributesFieldTest extends BrowserTestBase { + + use FieldUiTestTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'node', + 'link_attributes', + 'field_ui', + 'block', + 'link_attributes_test_alterinfo', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * A user that can edit content types. + * + * @var \Drupal\user\UserInterface + */ + protected $adminUser; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->adminUser = $this->drupalCreateUser([ + 'administer content types', + 'administer node fields', + 'administer node display', + ]); + $this->drupalLogin($this->adminUser); + // Breadcrumb is required for FieldUiTestTrait::fieldUIAddNewField. + $this->drupalPlaceBlock('system_breadcrumb_block'); + \Drupal::state()->set('link_attributes_test_alterinfo.hook_link_attributes_plugin_alter', TRUE); + } + + /** + * Tests the display of attributes in the widget. + */ + public function testWidget() { + // Add a content type. + $type = $this->drupalCreateContentType(); + $type_path = 'admin/structure/types/manage/' . $type->id(); + $add_path = 'node/add/' . $type->id(); + + // Add a link field to the newly-created type. + $label = $this->randomMachineName(); + $field_name = mb_strtolower($label); + $storage_settings = ['cardinality' => 'number', 'cardinality_number' => 2]; + $this->fieldUIAddNewField($type_path, $field_name, $label, 'link', $storage_settings); + + // Manually clear cache on the tester side. + \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + + // Change the link widget and enable some attributes. + \Drupal::entityTypeManager() + ->getStorage('entity_form_display') + ->load('node.' . $type->id() . '.default') + ->setComponent('field_' . $field_name, [ + 'type' => 'link_attributes', + 'settings' => [ + 'enabled_attributes' => [ + 'rel' => TRUE, + 'class' => TRUE, + 'target' => TRUE, + ], + ], + ]) + ->save(); + + // Check if the link field have the attributes displayed on node add page. + $this->drupalGet($add_path); + $web_assert = $this->assertSession(); + // Link attributes. + $web_assert->elementExists('css', '.field--widget-link-attributes'); + + // Rel attribute. + $attribute_rel = 'field_' . $field_name . '[0][options][attributes][rel]'; + $web_assert->fieldExists($attribute_rel); + + // Class attribute. + $attribute_class = 'field_' . $field_name . '[0][options][attributes][class]'; + $web_assert->fieldExists($attribute_class); + + // Target attribute. + $attribute_target = 'field_' . $field_name . '[0][options][attributes][target]'; + $web_assert->fieldExists($attribute_target); + $web_assert->fieldValueEquals($attribute_target, '_blank'); + + \Drupal::state()->set('link_attributes_test_alterinfo.hook_link_attributes_plugin_alter', FALSE); + \Drupal::service('plugin.manager.link_attributes')->clearCachedDefinitions(); + // Create a node. + $edit = [ + 'title[0][value]' => 'A multi field link test', + 'field_' . $field_name . '[0][title]' => 'Link One', + 'field_' . $field_name . '[0][uri]' => '<front>', + 'field_' . $field_name . '[0][options][attributes][class]' => 'class-one class-two', + 'field_' . $field_name . '[1][title]' => 'Link Two', + 'field_' . $field_name . '[1][uri]' => '<front>', + 'field_' . $field_name . '[1][options][attributes][class]' => 'class-three class-four', + ]; + $this->drupalPostForm($add_path, $edit, t('Save')); + $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); + + // Load the field values. + $field_values = $node->get('field_' . $field_name)->getValue(); + + $expected_link_one = [ + 'class-one', + 'class-two', + ]; + $this->assertEquals($expected_link_one, $field_values[0]['options']['attributes']['class']); + + $expected_link_two = [ + 'class-three', + 'class-four', + ]; + $this->assertEquals($expected_link_two, $field_values[1]['options']['attributes']['class']); + } + + /** + * Tests saving a node without any attributes enabled in the widget settings. + */ + public function testWidgetWithoutAttributes() { + // Add a content type. + $type = $this->drupalCreateContentType(); + $type_path = 'admin/structure/types/manage/' . $type->id(); + $add_path = 'node/add/' . $type->id(); + + // Add a link field to the newly-created type. + $label = $this->randomMachineName(); + $field_name = mb_strtolower($label); + $storage_settings = ['cardinality' => 'number', 'cardinality_number' => 2]; + $this->fieldUIAddNewField($type_path, $field_name, $label, 'link', $storage_settings); + + // Manually clear cache on the tester side. + \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions(); + + \Drupal::entityTypeManager() + ->getStorage('entity_form_display') + ->load('node.' . $type->id() . '.default') + ->setComponent('field_' . $field_name, [ + 'type' => 'link_attributes', + 'settings' => [ + 'enabled_attributes' => [], + ], + ]) + ->save(); + + $this->drupalGet($add_path); + $web_assert = $this->assertSession(); + // Link attributes. + $web_assert->elementExists('css', '.field--widget-link-attributes'); + // Create a node. + $edit = [ + 'title[0][value]' => 'A multi field link test', + 'field_' . $field_name . '[0][title]' => 'Link One', + 'field_' . $field_name . '[0][uri]' => '<front>', + ]; + $this->drupalPostForm($add_path, $edit, t('Save')); + $node = $this->drupalGetNodeByTitle($edit['title[0][value]']); + $this->drupalGet($node->toUrl()->toString()); + $web_assert->linkExists('Link One'); + } + +} diff --git a/web/modules/link_attributes/tests/src/Functional/LinkAttributesMenuTest.php b/web/modules/link_attributes/tests/src/Functional/LinkAttributesMenuTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1f5b599ad916f9dae53e2ae4da45cd08e9876020 --- /dev/null +++ b/web/modules/link_attributes/tests/src/Functional/LinkAttributesMenuTest.php @@ -0,0 +1,103 @@ +<?php + +namespace Drupal\Tests\link_attributes\Functional; + +use Drupal\menu_link_content\Entity\MenuLinkContent; +use Drupal\Tests\block\Traits\BlockCreationTrait; +use Drupal\Tests\BrowserTestBase; + +/** + * Tests link attributes functionality. + * + * @group link_attributes + */ +class LinkAttributesMenuTest extends BrowserTestBase { + + use BlockCreationTrait; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'link_attributes', + 'menu_ui', + 'menu_link_content', + 'block', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + $this->placeBlock('system_menu_block:footer'); + } + + /** + * Test attributes. + */ + public function testMenuLinkAdmin() { + // Login as a super-admin. + $this->drupalLogin($this->drupalCreateUser(array_keys(\Drupal::service('user.permissions')->getPermissions()))); + + $this->drupalGet('admin/structure/menu/manage/footer/add'); + $this->submitForm([ + 'title[0][value]' => 'A menu link', + 'link[0][uri]' => '<front>', + // This is enough to check the fields are there. + 'link[0][options][attributes][target]' => '_blank', + 'link[0][options][attributes][class]' => 'menu__link--really_special menu__link--another-class', + ], t('Save')); + $this->drupalGet('user'); + $page = $this->getSession()->getPage(); + // The link should exist and contain the required attributes. + $link = $page->findLink('A menu link'); + $this->assertNotNull($link); + $this->assertEquals('_blank', $link->getAttribute('target')); + $this->assertEquals('menu__link--really_special menu__link--another-class', $link->getAttribute('class')); + // No rel attribute was added, so none should be present. + $this->assertFalse($link->hasAttribute('rel')); + + // Load the menu link, make sure that the classes were stored as an array. + $id = \Drupal::entityQuery('menu_link_content') + ->condition('title', 'A menu link') + ->execute(); + + /** @var \Drupal\menu_link_content\MenuLinkContentInterface $menu_link */ + $menu_link = MenuLinkContent::load(reset($id)); + + $expected = [ + 'menu__link--really_special', + 'menu__link--another-class', + ]; + $this->assertEquals($expected, $menu_link->getUrlObject()->getOption('attributes')['class']); + + // Edit the link, make sure the default value for class is set correctly. + $this->drupalGet($menu_link->toUrl('edit-form')); + $this->assertSession()->fieldValueEquals('link[0][options][attributes][class]', 'menu__link--really_special menu__link--another-class'); + + // Add another link to assert that the target can be empty. + $this->drupalGet('admin/structure/menu/manage/footer/add'); + $this->submitForm([ + 'title[0][value]' => 'No target menu link', + 'link[0][uri]' => '<front>', + 'link[0][options][attributes][target]' => '', + 'link[0][options][attributes][rel]' => 'author', + ], t('Save')); + $this->drupalGet('user'); + $page = $this->getSession()->getPage(); + // The link should exist and contain the set rel attribute. + $link = $page->findLink('No target menu link'); + $this->assertNotNull($link); + $this->assertEquals('author', $link->getAttribute('rel')); + // No class or target was specified, these shouldn't be rendered. + $this->assertFalse($link->hasAttribute('target')); + $this->assertFalse($link->hasAttribute('class')); + } + +} diff --git a/web/modules/link_attributes/tests/src/Functional/LinkAttributesTest.php b/web/modules/link_attributes/tests/src/Functional/LinkAttributesTest.php deleted file mode 100644 index f6be709a6f50a6dc968646ef7f72b614cbe3cd32..0000000000000000000000000000000000000000 --- a/web/modules/link_attributes/tests/src/Functional/LinkAttributesTest.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php - -namespace Drupal\Tests\link_attributes\Functional; - -use Drupal\simpletest\BlockCreationTrait; -use Drupal\Tests\BrowserTestBase; - -/** - * Tests link attributes functionality. - * - * @group link_attributes - */ -class LinkAttributesTest extends BrowserTestBase { - - use BlockCreationTrait; - - /** - * {@inheritdoc} - */ - public static $modules = [ - 'link', - 'link_attributes', - 'menu_ui', - 'menu_link_content', - 'system', - 'block', - ]; - - /** - * {@inheritdoc} - */ - protected function setUp() { - parent::setUp(); - $this->placeBlock('system_menu_block:footer'); - } - - /** - * Test attributes. - */ - public function testMenuLinkAdmin() { - // Login as a super-admin. - $this->drupalLogin($this->drupalCreateUser(array_keys(\Drupal::service('user.permissions')->getPermissions()))); - - $this->drupalGet('admin/structure/menu/manage/footer/add'); - $this->submitForm([ - 'title[0][value]' => 'A menu link', - 'link[0][uri]' => '<front>', - // This is enough to check the fields are there. - 'link[0][options][attributes][target]' => '_blank', - 'link[0][options][attributes][class]' => 'menu__link--really_special', - ], t('Save')); - $this->drupalGet('user'); - $page = $this->getSession()->getPage(); - // The link should exist and contain the required attributes. - $link = $page->findLink('A menu link'); - $this->assertNotNull($link); - $this->assertEquals('_blank', $link->getAttribute('target')); - $this->assertEquals('menu__link--really_special', $link->getAttribute('class')); - } - -} diff --git a/web/modules/link_attributes/tests/src/Kernel/InfoAlterTest.php b/web/modules/link_attributes/tests/src/Kernel/InfoAlterTest.php new file mode 100644 index 0000000000000000000000000000000000000000..f49bd9e0ab104494c69c256ff40659b502afd19e --- /dev/null +++ b/web/modules/link_attributes/tests/src/Kernel/InfoAlterTest.php @@ -0,0 +1,44 @@ +<?php + +namespace Drupal\Tests\link_attributes\Kernel; + +use Drupal\KernelTests\KernelTestBase; + +/** + * Tests link_attributes_plugin alterInfo. + * + * @group link_attributes + */ +class InfoAlterTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'system', + 'link_attributes', + 'link_attributes_test_alterinfo', + ]; + + /** + * Tests that plugin definition is changed with alterInfo. + * + * Tests that info data is changed after a module that implements + * hook_link_attributes_plugin_alter() is enabled. + */ + public function testLinkAttributesManagerInfoAlter() { + /** @var \Drupal\link_attributes\LinkAttributesManager $linkAttributesManager */ + $linkAttributesManager = $this->container->get('plugin.manager.link_attributes'); + $definition = $linkAttributesManager->getDefinitions(); + $this->assertTrue($definition['class']['type'] == 'textfield', 'Without altering the plugin definition the class attribute is a textfield.'); + + // Set our flag to alter the plugin definition in + // link_attributes_test_alterinfo module. + \Drupal::state()->set('link_attributes_test_alterinfo.hook_link_attributes_plugin_alter', TRUE); + $linkAttributesManager->clearCachedDefinitions(); + $definition = $linkAttributesManager->getDefinitions(); + $this->assertTrue($definition['class']['type'] == 'select', 'After altering the plugin definition the class attribute is a select.'); + $this->assertTrue(isset($definition['class']['options']['button']), 'After altering the plugin definition the class attribute has a "button" option.'); + } + +}