diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js index 9acc98f..0839833 100644 --- a/core/modules/field_ui/field_ui.js +++ b/core/modules/field_ui/field_ui.js @@ -11,49 +11,41 @@ attach: function (context) { var $newFieldType = $(context).find('select[name="new_field_type"]').once('new-field-type'); var $existingStorageName = $(context).find('select[name="existing_storage_name"]').once('existing-storage-name'); - var $fieldLabel = $(context).find('input[name="label"]'); - var $machineName = $(context).find('.form-item-label .field-suffix'); - var labelValue; - // When the user selects a new field type, clear the "existing field" - // selection and re-populate the label if we have something in the cache. if ($newFieldType.length) { + // Add the 'form-required' css class here. We can not use the Form API + // '#required' property because both label elements for "add new" and + // "re-use existing" can never be filled and submitted at the same time. + // The actual validation will happen server-side. + $(context).find('.form-item-label label').addClass('form-required'); + $(context).find('.form-item-field-name label').addClass('form-required'); + + // When the user selects a new field type, clear the "existing field" + // selection. $newFieldType.change(function () { if ($(this).val() != '') { + // Reset the "existing storage name" selection. $existingStorageName.val('').change(); - - if (labelValue != null) { - $fieldLabel.val(labelValue).trigger('keyup'); - $machineName.show(); - labelValue = null; - } } }); } - // When the user selects an existing field, clear the "new field type" - // selection and populate the 'label' element. if ($existingStorageName.length) { - $existingStorageName.change(function (event) { - if ($(this).val() != '') { - // Keep the current label value (if any) in a static cache so we can - // re-use it if the user decides to select a new field type again. - if ($newFieldType.val()) { - labelValue = $fieldLabel.val(); - } + // Add the 'form-required' css class to the label of the form element. + // The actual validation will happen server-side. + $(context).find('.form-item-existing-storage-label label').addClass('form-required'); - // Reset the field type selection. - $newFieldType.val(''); + // When the user selects an existing storage name, clear the "new field + // type" selection and populate the 'existing_storage_label' element. + $existingStorageName.change(function () { + if ($(this).val() != '') { + // Reset the "new field type" selection. + $newFieldType.val('').change(); - // Pre-populate the label and hide the machine name (field_name). - $fieldLabel.val(drupalSettings.existingFieldLabels[$(this).val()]); - $machineName.hide(); - } - // Reset the auto-populated label value if this is a user-initiated - // event (i.e. changing the value of the "existing field" element). - else if (event.originalEvent !== undefined && labelValue == null) { - $fieldLabel.val(''); - $machineName.show(); + // Pre-populate the "existing storage label" element. + if (drupalSettings.existingFieldLabels[$(this).val()] !== undefined) { + $(context).find('input[name="existing_storage_label"]').val(drupalSettings.existingFieldLabels[$(this).val()]); + } } }); } diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php index 5a265a4..cc5c7e7 100644 --- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php +++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php @@ -175,25 +175,22 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t } // Field label and field_name. - $form['name_wrapper'] = array( + $form['add_storage_wrapper'] = array( '#type' => 'container', '#states' => array( '!visible' => array( ':input[name="new_field_type"]' => array('value' => ''), - ':input[name="existing_storage_name"]' => array('value' => ''), ), ), ); - - $form['name_wrapper']['label'] = array( + $form['add_storage_wrapper']['label'] = array( '#type' => 'textfield', '#title' => $this->t('Label'), '#size' => 15, - '#required' => TRUE, ); $field_prefix = $this->config('field_ui.settings')->get('field_prefix'); - $form['name_wrapper']['field_name'] = array( + $form['add_storage_wrapper']['field_name'] = array( '#type' => 'machine_name', // This field should stay LTR even for RTL languages. '#field_prefix' => '' . $field_prefix, @@ -204,12 +201,28 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t // setting. Maximum length is 32. '#maxlength' => FieldStorageConfig::NAME_MAX_LENGTH - strlen($field_prefix), '#machine_name' => array( - 'source' => array('name_wrapper', 'label'), + 'source' => array('add_storage_wrapper', 'label'), 'exists' => array($this, 'fieldNameExists'), ), '#required' => FALSE, ); + // Provide a separate label element for the "Re-use existing field" case + // and place it outside the $form['add'] wrapper because those elements + // are displayed inline. + if ($existing_field_storage_options) { + $form['existing_storage_label'] = array( + '#type' => 'textfield', + '#title' => $this->t('Label'), + '#size' => 15, + '#states' => array( + '!visible' => array( + ':input[name="existing_storage_name"]' => array('value' => ''), + ), + ), + ); + } + // Place the 'translatable' property as an explicit value so that // contrib modules can form_alter() the value for newly created fields. $form['translatable'] = array( @@ -261,6 +274,11 @@ public function validateForm(array &$form, FormStateInterface $form_state) { protected function validateAddNew(array $form, FormStateInterface $form_state) { // Validate if any information was provided in the 'add new field' case. if ($form_state->getValue('new_field_type')) { + // Missing label. + if (!$form_state->getValue('label')) { + $form_state->setErrorByName('label', $this->t('Add new field: you need to provide a label.')); + } + // Missing field name. if (!$form_state->getValue('field_name')) { $form_state->setErrorByName('field_name', $this->t('Add new field: you need to provide a machine name for the field.')); @@ -271,7 +289,7 @@ protected function validateAddNew(array $form, FormStateInterface $form_state) { // Add the field prefix. $field_name = $this->configFactory->get('field_ui.settings')->get('field_prefix') . $field_name; - $form_state->setValueForElement($form['name_wrapper']['field_name'], $field_name); + $form_state->setValueForElement($form['add_storage_wrapper']['field_name'], $field_name); } } } @@ -288,8 +306,10 @@ protected function validateAddNew(array $form, FormStateInterface $form_state) { */ protected function validateAddExisting(array $form, FormStateInterface $form_state) { if ($form_state->getValue('existing_storage_name')) { - // Discard any value that might be set for the field name. - $form_state->setValueForElement($form['name_wrapper']['field_name'], ''); + // Missing label. + if (!$form_state->getValue('existing_storage_label')) { + $form_state->setErrorByName('existing_storage_label', $this->t('Re-use existing field: you need to provide a label.')); + } } } @@ -352,7 +372,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) { 'field_name' => $field_name, 'entity_type' => $this->entityTypeId, 'bundle' => $this->bundle, - 'label' => $values['label'], + 'label' => $values['existing_storage_label'], )); $field->save(); diff --git a/core/modules/field_ui/src/Tests/FieldUiTestTrait.php b/core/modules/field_ui/src/Tests/FieldUiTestTrait.php index a597b97..ccb8751 100644 --- a/core/modules/field_ui/src/Tests/FieldUiTestTrait.php +++ b/core/modules/field_ui/src/Tests/FieldUiTestTrait.php @@ -81,7 +81,7 @@ public function fieldUIAddExistingField($bundle_path, $existing_storage_name, $l $label = $label ?: $this->randomString(); $initial_edit = array( 'existing_storage_name' => $existing_storage_name, - 'label' => $label, + 'existing_storage_label' => $label, ); // First step: 'Re-use existing field' on the 'Add field' page.