diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml index c88ca10bd3..953dae9632 100644 --- a/core/config/schema/core.entity.schema.yml +++ b/core/config/schema/core.entity.schema.yml @@ -257,6 +257,9 @@ field.widget.settings.entity_reference_autocomplete_tags: placeholder: type: label label: 'Placeholder' + show_id: + type: boolean + label: 'Show ID' field.widget.settings.entity_reference_autocomplete: type: mapping @@ -274,6 +277,9 @@ field.widget.settings.entity_reference_autocomplete: placeholder: type: label label: 'Placeholder' + show_id: + type: boolean + label: 'Show ID' field.formatter.settings.boolean: type: mapping diff --git a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php index 2cb823aaed..1f2f0a492a 100644 --- a/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php +++ b/core/lib/Drupal/Core/Entity/Element/EntityAutocomplete.php @@ -116,7 +116,7 @@ public static function valueCallback(&$element, $input, FormStateInterface $form // Extract the labels from the passed-in entity objects, taking access // checks into account. - return static::getEntityLabels($element['#default_value']); + return static::getEntityLabels($element['#default_value'], $element['#show_id'] ?? TRUE); } } @@ -365,15 +365,18 @@ protected static function matchEntityByTitle(SelectionInterface $handler, $input * * @param \Drupal\Core\Entity\EntityInterface[] $entities * An array of entity objects. + * @param bool $show_id + * If the label should show the entity id. * * @return string * A string of entity labels separated by commas. */ - public static function getEntityLabels(array $entities) { + public static function getEntityLabels(array $entities, $show_id = TRUE) { /** @var \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository */ $entity_repository = \Drupal::service('entity.repository'); $entity_labels = []; + $entity_ids = []; foreach ($entities as $entity) { // Set the entity in the correct language for display. $entity = $entity_repository->getTranslationFromContext($entity); @@ -383,12 +386,22 @@ public static function getEntityLabels(array $entities) { $label = ($entity->access('view label')) ? $entity->label() : t('- Restricted access -'); // Take into account "autocreated" entities. - if (!$entity->isNew()) { + if (!$entity->isNew() && $show_id) { $label .= ' (' . $entity->id() . ')'; } // Labels containing commas or quotes must be wrapped in quotes. $entity_labels[] = Tags::encode($label); + $entity_ids[] = ($entity->access('view label')) ? $entity->id() : -1; + } + + $duplicates = array_diff_assoc($entity_labels, array_unique($entity_labels)); + if (!$show_id && count($duplicates) > 0) { + foreach ($entity_labels as $key => $value) { + if (in_array($value, $duplicates) && $entity_ids[$key] > 0) { + $entity_labels[$key] .= ' (' . $entity_ids[$key] . ')'; + } + } } return implode(', ', $entity_labels); diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php index 68885f24df..b5af9e1859 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldWidget/EntityReferenceAutocompleteWidget.php @@ -31,6 +31,7 @@ public static function defaultSettings() { 'match_limit' => 10, 'size' => 60, 'placeholder' => '', + 'show_id' => TRUE, ] + parent::defaultSettings(); } @@ -65,6 +66,12 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#default_value' => $this->getSetting('placeholder'), '#description' => $this->t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'), ]; + $element['show_id'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Show Entity ID'), + '#default_value' => $this->getSetting('show_id') ?? TRUE, + '#description' => $this->t('Will display the entity id of the selection. When disabled, the entity id will still be shown for items with duplicate titles.'), + ]; return $element; } @@ -87,6 +94,8 @@ public function settingsSummary() { $summary[] = $this->t('No placeholder'); } + $summary[] = $this->t('Show entity IDs: @show', ['@show' => $this->getSetting('match_operator') ? 'Yes' : 'No']); + return $summary; } @@ -120,8 +129,13 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#default_value' => $referenced_entities[$delta] ?? NULL, '#size' => $this->getSetting('size'), '#placeholder' => $this->getSetting('placeholder'), + '#show_id' => $this->getSetting('show_id'), ]; + if (empty($this->getSetting('show_id'))) { + $element['#attributes']['data-drupal-autocomplete-hide-ids'] = ''; + } + if ($bundle = $this->getAutocreateBundle()) { $element['#autocreate'] = [ 'bundle' => $bundle, diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js index 74ca14e33e..b6b6664188 100644 --- a/core/misc/autocomplete.js +++ b/core/misc/autocomplete.js @@ -120,7 +120,19 @@ suggestions.splice(index, 1); } } - response(suggestions); + + const labels = suggestions.map((item) => item.label); + const duplicates = new Set( + labels.filter( + (item) => labels.indexOf(item) !== labels.lastIndexOf(item), + ), + ); + + response( + suggestions.map((item) => + duplicates.has(item.label) ? { ...item, showId: true } : item, + ), + ); } // Get the desired term and construct the autocomplete URL for it. @@ -177,7 +189,12 @@ // Remove the current input. terms.pop(); // Add the selected item. - terms.push(ui.item.value); + // @todo this should be dynamic based on the formatter show_id setting. Use + // the value property to display entity ids and use the label property to + // not display them. + const hideIds = this.hasAttribute('data-drupal-autocomplete-hide-ids'); + + terms.push(hideIds && !ui.item.showId ? ui.item.label : ui.item.value); event.target.value = terms.join(', '); // Return false to tell jQuery UI that we've filled in the value already. @@ -196,7 +213,9 @@ * jQuery collection of the ul element. */ function renderItem(ul, item) { - return $('