diff --git a/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php b/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php index e3af421ff4a08233a172e203ff76f191c3144243..22cd0d9ac678c71f7b904d3fe01c551656fe18e5 100644 --- a/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php +++ b/core/modules/options/src/Plugin/Field/FieldType/ListStringItem.php @@ -100,6 +100,10 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state // Workaround for https://drupal.org/i/1300290#comment-12873635. \Drupal::service('plugin.manager.element_info')->getInfoProperty('machine_name', '#process', []), ); + // Remove #element_validate from the machine name so that any value can be + // used as a key, while keeping the widget's behavior for generating + // defaults the same. + $element['allowed_values']['table'][$delta]['item']['key']['#element_validate'] = []; } return $element; @@ -113,6 +117,14 @@ public static function processAllowedValuesKey(array &$element): array { array_pop($parents); $parents[] = 'label'; $element['#machine_name']['source'] = $parents; + + // Override the default description which is not applicable to this use of + // the machine name element given that it allows users to manually enter + // characters usually not allowed in machine names. + if (!isset($element['#description'])) { + $element['#description'] = ''; + } + return $element; } diff --git a/core/modules/options/tests/src/Functional/OptionsFieldUITest.php b/core/modules/options/tests/src/Functional/OptionsFieldUITest.php index c56f2f37d14b9f5c40319d7e8243f5651c08bfb7..ad83c71e98a4935f185d59cfec65a266bd784db1 100644 --- a/core/modules/options/tests/src/Functional/OptionsFieldUITest.php +++ b/core/modules/options/tests/src/Functional/OptionsFieldUITest.php @@ -306,14 +306,15 @@ public function testOptionsAllowedValuesText() { $field_storage = FieldStorageConfig::loadByName('node', $this->fieldName); $this->assertSame($field_storage->getSetting('allowed_values'), ['zero' => 'Zero']); - // Check that string values with dots can not be used. + // Check that string values with special characters can be used. $input = [ 'field_storage[subform][settings][allowed_values][table][0][item][key]' => 'zero', 'field_storage[subform][settings][allowed_values][table][0][item][label]' => 'Zero', - 'field_storage[subform][settings][allowed_values][table][1][item][key]' => 'example.com', + 'field_storage[subform][settings][allowed_values][table][1][item][key]' => '.example #example', 'field_storage[subform][settings][allowed_values][table][1][item][label]' => 'Example', ]; - $this->assertAllowedValuesInput($input, 'The machine-readable name must contain only lowercase letters, numbers, and underscores.', 'String value with dot is not supported.'); + $array = ['zero' => 'Zero', '.example #example' => 'Example']; + $this->assertAllowedValuesInput($input, $array, ''); // Check that the same key can only be used once. $input = [ diff --git a/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php b/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php index 02c099fcbe50853ce3f5d99d2c88e43ca15e3069..61df5dd91af00df994700b011dcb8ac4c34a4f48 100644 --- a/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php +++ b/core/modules/options/tests/src/FunctionalJavascript/OptionsFieldUITest.php @@ -375,6 +375,37 @@ public function providerTestOptionsAllowedValues() { return $test_cases; } + /** + * Tests `list_string` machine name with special characters. + */ + public function testMachineNameSpecialCharacters() { + $this->fieldName = 'field_options_text'; + $this->createOptionsField('list_string'); + $this->drupalGet($this->adminPath); + + $label_element_name = "field_storage[subform][settings][allowed_values][table][0][item][label]"; + $this->getSession()->getPage()->fillField($label_element_name, 'Hello world'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->exposeOptionMachineName(1); + + $key_element_name = "field_storage[subform][settings][allowed_values][table][0][item][key]"; + + // Ensure that the machine name was generated correctly. + $this->assertSession()->fieldValueEquals($key_element_name, 'hello_world'); + + // Ensure that the machine name can be overridden with a value that includes + // special characters. + $this->getSession()->getPage()->fillField($key_element_name, '.hello #world'); + $this->assertSession()->assertWaitOnAjaxRequest(); + $this->getSession()->getPage()->pressButton('Save settings'); + $this->assertSession()->statusMessageContains("Saved {$this->fieldName} configuration."); + + // Ensure that the machine name was saved correctly. + $allowed_values = FieldStorageConfig::loadByName('node', $this->fieldName) + ->getSetting('allowed_values'); + $this->assertSame(['.hello #world'], array_keys($allowed_values)); + } + /** * Assert the count of the allowed values rows. *