diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index 0c212ce..3908c80 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -102,7 +102,7 @@ drupal.autocomplete:
- core/drupal
- core/drupalSettings
- core/drupal.ajax
- - core/jquery.ui.autocomplete
+ - core/select2
drupal.batch:
version: VERSION
@@ -808,3 +808,19 @@ underscore:
gpl-compatible: true
js:
assets/vendor/underscore/underscore.js: { weight: -20 }
+
+select2:
+ remote: https://github.com/ivaynberg/select2
+ version: 3.5.2
+ license:
+ name: GNU-GPL-2.0-or-later
+ url: https://github.com/ivaynberg/select2/blob/master/LICENSE
+ gpl-compatible: true
+ js:
+ assets/vendor/select2/select2.js: {}
+ misc/select2.js: {}
+ css:
+ theme:
+ assets/vendor/select2/select2.css: {}
+ dependencies:
+ - core/jquery
diff --git a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
index 79d9082..0e67b5e 100644
--- a/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SelectLanguageForm.php
@@ -67,6 +67,8 @@ public function buildForm(array $form, FormStateInterface $form_state, $install_
'#options' => $select_options,
// Use the browser detected language as default or English if nothing found.
'#default_value' => !empty($browser_langcode) ? $browser_langcode : 'en',
+ // Use the Select2 library.
+ '#select2' => TRUE,
);
$form['help'] = array(
'#type' => 'item',
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
index 750e967..146ee97 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
@@ -199,6 +199,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#description' => $this->t('By default, dates in this site will be displayed in the chosen time zone.'),
'#weight' => 5,
'#attributes' => array('class' => array('timezone-detect')),
+ // Use the Select2 library.
+ '#select2' => TRUE,
);
$form['update_notifications'] = array(
diff --git a/core/lib/Drupal/Core/Render/Element/FormElement.php b/core/lib/Drupal/Core/Render/Element/FormElement.php
index 401c850..b6d1789 100644
--- a/core/lib/Drupal/Core/Render/Element/FormElement.php
+++ b/core/lib/Drupal/Core/Render/Element/FormElement.php
@@ -7,6 +7,7 @@
namespace Drupal\Core\Render\Element;
+use Drupal\Component\Serialization\Json;
use Drupal\Core\Form\FormStateInterface;
/**
@@ -123,6 +124,49 @@ public static function processAutocomplete(&$element, FormStateInterface $form_s
$element['#attached']['library'][] = 'core/drupal.autocomplete';
// Provide a data attribute for the JavaScript behavior to bind to.
$element['#attributes']['data-autocomplete-path'] = $path;
+
+ // Provide a data attribute which stores extra Select2 configuration.
+ $options = isset($element['#autocomplete_options']) ? $element['#autocomplete_options'] : array();
+ $element['#attributes']['data-autocomplete-options'] = Json::encode($options);
+ }
+
+ return $element;
+ }
+
+ /**
+ * Integrates form elements with the Select2 JavaScript library.
+ *
+ * @param array $element
+ * The form element to process. Properties used:
+ * - #select2: Whether to use the Select2 library for this form element. If
+ * the value is TRUE, the Select2 library is initialized with its default
+ * options. If the value is an array, each key and value will map to the
+ * corresponding Select2 configuration.
+ * @see http://ivaynberg.github.io/select2/#documentation for the list of
+ * possible configuration options.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The current state of the form.
+ * @param array $complete_form
+ * The complete form structure.
+ *
+ * @return array
+ * The form element.
+ */
+ public static function processSelect2(&$element, FormStateInterface $form_state, &$complete_form) {
+ if (!empty($element['#select2'])) {
+ // Provide some default options.
+ // @todo Figure out if we need more defaults here.
+ $configuration = array(
+ 'width' => 'resolve',
+ );
+ if (is_array($element['#select2'])) {
+ $configuration = $element['#select2'] + $configuration;
+ }
+
+ $element['#attributes']['class'][] = 'form-select2';
+ $element['#attached']['library'][] = 'core/select2';
+ // Provide a data attribute which stores the Select2 configuration array.
+ $element['#attributes']['data-drupal-select2'] = Json::encode($configuration);
}
return $element;
diff --git a/core/lib/Drupal/Core/Render/Element/Select.php b/core/lib/Drupal/Core/Render/Element/Select.php
index 70f14d6..4507fdb 100644
--- a/core/lib/Drupal/Core/Render/Element/Select.php
+++ b/core/lib/Drupal/Core/Render/Element/Select.php
@@ -31,6 +31,9 @@ public function getInfo() {
'#process' => array(
array($class, 'processSelect'),
array($class, 'processAjaxForm'),
+ // Not to be confused with the processor above, this one is about the
+ // Select2 Javascript library.
+ array($class, 'processSelect2'),
),
'#pre_render' => array(
array($class, 'preRenderSelect'),
diff --git a/core/misc/autocomplete.js b/core/misc/autocomplete.js
index af64521..35df8bd 100644
--- a/core/misc/autocomplete.js
+++ b/core/misc/autocomplete.js
@@ -2,16 +2,14 @@
"use strict";
- var autocomplete;
-
/**
- * Helper splitting terms from the autocomplete value.
+ * Helper for splitting terms from the autocomplete value.
*
* @param {String} value
*
* @return {Array}
*/
- function autocompleteSplitValues(value) {
+ function splitValues(value) {
// We will match the value against comma-separated terms.
var result = [];
var quote = false;
@@ -41,132 +39,46 @@
}
/**
- * Returns the last value of an multi-value textfield.
- *
- * @param {String} terms
- *
- * @return {String}
+ * Sanitizes and splits the initial value of an autocomplete form element in
+ * the form required by Select2.
*/
- function extractLastTerm(terms) {
- return autocomplete.splitValues(terms).pop();
+ function prepareInitialValue(element, callback) {
+ var idInText = element.data('autocompleteOptions')['id_in_text'] || false;
+
+ var data = splitValues(element.val()).map(function (value) {
+ // Strip the identifier from the default value of an autocomplete
+ // element. The value is expected to be in the form "text (id)".
+ var textValue = idInText ? value.match(/"?(.+) \(\d+|[\w.]+\)"?/)[1] : value;
+ return {id: value, text: window.Select2.util.escapeMarkup(textValue.replace('""', '"', 'g'))};
+ });
+ callback(data);
}
- /**
- * The search handler is called before a search is performed.
- *
- * @param {Object} event
- *
- * @return {Boolean}
- */
- function searchHandler(event) {
- // Only search when the term is two characters or larger.
- var term = autocomplete.extractLastTerm(event.target.value);
- return term.length >= autocomplete.minLength;
- }
-
- /**
- * jQuery UI autocomplete source callback.
- *
- * @param {Object} request
- * @param {Function} response
- */
- function sourceData(request, response) {
- /*jshint validthis:true */
- var elementId = this.element.attr('id');
-
- if (!(elementId in autocomplete.cache)) {
- autocomplete.cache[elementId] = {};
- }
-
- /**
- * Filter through the suggestions removing all terms already tagged and
- * display the available terms to the user.
- *
- * @param {Object} suggestions
- */
- function showSuggestions(suggestions) {
- var tagged = autocomplete.splitValues(request.term);
- for (var i = 0, il = tagged.length; i < il; i++) {
- var index = suggestions.indexOf(tagged[i]);
- if (index >= 0) {
- suggestions.splice(index, 1);
- }
+ // Generic Select2 options that do not depend on any autocomplete element
+ // specific configuration.
+ var select2Options = {
+ tokenSeparators: [","],
+ tags: [],
+ minimumInputLength: 1,
+ cache: true,
+ width: 'resolve',
+ createSearchChoice: function (term) {
+ return {id: term, text: term};
+ },
+ initSelection: prepareInitialValue,
+ ajax: {
+ dataType: 'json',
+ quietMillis: 200,
+ data: function (term, page) {
+ return {q: term};
+ },
+ results: function (data, page) {
+ return {results: data};
}
- response(suggestions);
- }
-
- /**
- * Transforms the data object into an array and update autocomplete results.
- *
- * @param {Object} data
- */
- function sourceCallbackHandler(data) {
- autocomplete.cache[elementId][term] = data;
-
- // Send the new string array of terms to the jQuery UI list.
- showSuggestions(data);
- }
-
- // Get the desired term and construct the autocomplete URL for it.
- var term = autocomplete.extractLastTerm(request.term);
-
- // Check if the term is already cached.
- if (autocomplete.cache[elementId].hasOwnProperty(term)) {
- showSuggestions(autocomplete.cache[elementId][term]);
- }
- else {
- var options = $.extend({ success: sourceCallbackHandler, data: { q: term } }, autocomplete.ajax);
- /*jshint validthis:true */
- $.ajax(this.element.attr('data-autocomplete-path'), options);
- }
- }
-
- /**
- * Handles an autocompletefocus event.
- *
- * @return {Boolean}
- */
- function focusHandler() {
- return false;
- }
-
- /**
- * Handles an autocompleteselect event.
- *
- * @param {Object} event
- * @param {Object} ui
- *
- * @return {Boolean}
- */
- function selectHandler(event, ui) {
- var terms = autocomplete.splitValues(event.target.value);
- // Remove the current input.
- terms.pop();
- // Add the selected item.
- if (ui.item.value.search(",") > 0) {
- terms.push('"' + ui.item.value + '"');
- }
- else {
- terms.push(ui.item.value);
- }
- event.target.value = terms.join(', ');
- // Return false to tell jQuery UI that we've filled in the value already.
- return false;
- }
-
- /**
- * Override jQuery UI _renderItem function to output HTML by default.
- *
- * @param {Object} ul
- * @param {Object} item
- *
- * @return {Object}
- */
- function renderItem(ul, item) {
- return $("
")
- .append($("").html(item.label))
- .appendTo(ul);
- }
+ },
+ // We do not want to escape markup since we are displaying html.
+ escapeMarkup: function (markup) { return markup; }
+ };
/**
* Attaches the autocomplete behavior to all required fields.
@@ -174,45 +86,17 @@
Drupal.behaviors.autocomplete = {
attach: function (context) {
// Act on textfields with the "form-autocomplete" class.
- var $autocomplete = $(context).find('input.form-autocomplete').once('autocomplete');
- if ($autocomplete.length) {
- // Use jQuery UI Autocomplete on the textfield.
- $autocomplete.autocomplete(autocomplete.options)
- .data("ui-autocomplete")
- ._renderItem = autocomplete.options.renderItem;
- }
- },
- detach: function (context, settings, trigger) {
- if (trigger === 'unload') {
- $(context).find('input.form-autocomplete')
- .removeOnce('autocomplete')
- .autocomplete('destroy');
- }
- }
- };
+ $(context).find('input.form-autocomplete').once('autocomplete')
+ .each(function () {
+ // Merge the default options with the user-defined ones.
+ var autocompleteOptions = $.extend({}, select2Options, JSON.parse(this.getAttribute('data-autocomplete-options')));
- /**
- * Autocomplete object implementation.
- */
- autocomplete = {
- cache: {},
- // Exposes methods to allow overriding by contrib.
- minLength: 1,
- splitValues: autocompleteSplitValues,
- extractLastTerm: extractLastTerm,
- // jQuery UI autocomplete options.
- options: {
- source: sourceData,
- focus: focusHandler,
- search: searchHandler,
- select: selectHandler,
- renderItem: renderItem
- },
- ajax: {
- dataType: 'json'
+ // Set the element-specific AJAX url.
+ autocompleteOptions.ajax.url = this.getAttribute('data-autocomplete-path');
+
+ $(this).select2(autocompleteOptions);
+ });
}
};
- Drupal.autocomplete = autocomplete;
-
})(jQuery, Drupal);
diff --git a/core/misc/select2.js b/core/misc/select2.js
new file mode 100644
index 0000000..db320ec
--- /dev/null
+++ b/core/misc/select2.js
@@ -0,0 +1,17 @@
+(function ($, Drupal) {
+
+ "use strict";
+
+ /**
+ * Attaches the Select2 behavior to all form elements that requested it.
+ */
+ Drupal.behaviors.select2 = {
+ attach: function (context) {
+ $(context).find('[data-drupal-select2]').once('drupal-select2')
+ .each(function () {
+ $(this).select2(JSON.parse(this.getAttribute('data-drupal-select2')));
+ });
+ }
+ };
+
+})(jQuery, Drupal);
diff --git a/core/modules/entity_reference/src/EntityReferenceAutocomplete.php b/core/modules/entity_reference/src/EntityReferenceAutocomplete.php
index ffc9995..f93e144 100644
--- a/core/modules/entity_reference/src/EntityReferenceAutocomplete.php
+++ b/core/modules/entity_reference/src/EntityReferenceAutocomplete.php
@@ -62,8 +62,6 @@ public function __construct(EntityManagerInterface $entity_manager, SelectionPlu
* @param string $entity_id
* (optional) The entity ID the entity reference field is attached to.
* Defaults to ''.
- * @param string $prefix
- * (optional) A prefix for all the keys returned by this function.
* @param string $string
* (optional) The label of the entity to query by.
*
@@ -75,7 +73,7 @@ public function __construct(EntityManagerInterface $entity_manager, SelectionPlu
*
* @see \Drupal\entity_reference\EntityReferenceController
*/
- public function getMatches(FieldDefinitionInterface $field_definition, $entity_type, $bundle, $entity_id = '', $prefix = '', $string = '') {
+ public function getMatches(FieldDefinitionInterface $field_definition, $entity_type, $bundle, $entity_id = '', $string = '') {
$matches = array();
$entity = NULL;
@@ -102,7 +100,7 @@ public function getMatches(FieldDefinitionInterface $field_definition, $entity_t
$key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(String::decodeEntities(strip_tags($key)))));
// Names containing commas or quotes must be wrapped in quotes.
$key = Tags::encode($key);
- $matches[] = array('value' => $prefix . $key, 'label' => $label);
+ $matches[] = array('id' => $key, 'text' => $label);
}
}
}
diff --git a/core/modules/entity_reference/src/EntityReferenceController.php b/core/modules/entity_reference/src/EntityReferenceController.php
index afc4cc0..c83d74c 100644
--- a/core/modules/entity_reference/src/EntityReferenceController.php
+++ b/core/modules/entity_reference/src/EntityReferenceController.php
@@ -86,16 +86,9 @@ public function handleAutocomplete(Request $request, $type, $field_name, $entity
// Get the typed string, if exists from the URL.
$items_typed = $request->query->get('q');
$items_typed = Tags::explode($items_typed);
- $last_item = Unicode::strtolower(array_pop($items_typed));
+ $typed_string = Unicode::strtolower(array_pop($items_typed));
- $prefix = '';
- // The user entered a comma-separated list of entity labels, so we generate
- // a prefix.
- if ($type == 'tags' && !empty($last_item)) {
- $prefix = count($items_typed) ? Tags::implode($items_typed) . ', ' : '';
- }
-
- $matches = $this->entityReferenceAutocomplete->getMatches($field_definition, $entity_type, $bundle_name, $entity_id, $prefix, $last_item);
+ $matches = $this->entityReferenceAutocomplete->getMatches($field_definition, $entity_type, $bundle_name, $entity_id, $typed_string);
return new JsonResponse($matches);
}
diff --git a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
index 40d0aaf..b392f45 100644
--- a/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
+++ b/core/modules/entity_reference/src/Plugin/Field/FieldWidget/AutocompleteWidgetBase.php
@@ -93,6 +93,9 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
'#default_value' => implode(', ', $this->getLabels($items, $delta)),
'#autocomplete_route_name' => 'entity_reference.autocomplete',
'#autocomplete_route_parameters' => $autocomplete_route_parameters,
+ '#autocomplete_options' => array(
+ 'id_in_text' => TRUE,
+ ),
'#size' => $this->getSetting('size'),
'#placeholder' => $this->getSetting('placeholder'),
'#element_validate' => array(array($this, 'elementValidate')),
diff --git a/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php b/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php
index ae9ac0c..11673ee 100644
--- a/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php
+++ b/core/modules/entity_reference/src/Tests/EntityReferenceAutocompleteTest.php
@@ -76,25 +76,19 @@ function testEntityReferenceAutocompletion() {
// We should get both entities in a JSON encoded string.
$input = '10/';
$data = $this->getAutocompleteResult('single', $input);
- $this->assertIdentical($data[0]['label'], String::checkPlain($entity_1->name->value), 'Autocomplete returned the first matching entity');
- $this->assertIdentical($data[1]['label'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
+ $this->assertIdentical($data[0]['text'], String::checkPlain($entity_1->name->value), 'Autocomplete returned the first matching entity');
+ $this->assertIdentical($data[1]['text'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
// Try to autocomplete a entity label that matches the first entity.
// We should only get the first entity in a JSON encoded string.
$input = '10/16';
$data = $this->getAutocompleteResult('single', $input);
$target = array(
- 'value' => $entity_1->name->value . ' (1)',
- 'label' => String::checkPlain($entity_1->name->value),
+ 'id' => $entity_1->name->value . ' (1)',
+ 'text' => String::checkPlain($entity_1->name->value),
);
$this->assertIdentical(reset($data), $target, 'Autocomplete returns only the expected matching entity.');
- // Try to autocomplete a entity label that matches the second entity, and
- // the first entity is already typed in the autocomplete (tags) widget.
- $input = $entity_1->name->value . ' (1), 10/17';
- $data = $this->getAutocompleteResult('tags', $input);
- $this->assertIdentical($data[0]['label'], String::checkPlain($entity_2->name->value), 'Autocomplete returned the second matching entity');
-
// Try to autocomplete a entity label with both a comma and a slash.
$input = '"label with, and / t';
$data = $this->getAutocompleteResult('single', $input);
@@ -102,8 +96,8 @@ function testEntityReferenceAutocompletion() {
// Entity labels containing commas or quotes must be wrapped in quotes.
$n = Tags::encode($n);
$target = array(
- 'value' => $n,
- 'label' => String::checkPlain($entity_3->name->value),
+ 'id' => $n,
+ 'text' => String::checkPlain($entity_3->name->value),
);
$this->assertIdentical(reset($data), $target, 'Autocomplete returns an entity label containing a comma and a slash.');
}
@@ -146,8 +140,8 @@ public function testBaseField() {
$result = $entity_reference_controller->handleAutocomplete($request, 'single', 'user_id', 'entity_test', 'entity_test', 'NULL')->getContent();
$data = Json::decode($result);
- $this->assertIdentical($data[0]['label'], String::checkPlain($user_1->getUsername()), 'Autocomplete returned the first matching entity');
- $this->assertIdentical($data[1]['label'], String::checkPlain($user_2->getUsername()), 'Autocomplete returned the second matching entity');
+ $this->assertIdentical($data[0]['text'], String::checkPlain($user_1->getUsername()), 'Autocomplete returned the first matching entity');
+ $this->assertIdentical($data[1]['text'], String::checkPlain($user_2->getUsername()), 'Autocomplete returned the second matching entity');
// Checks that exception thrown for unknown field.
try {
diff --git a/core/modules/system/css/system.module.css b/core/modules/system/css/system.module.css
index cea7a25..07f9cf3 100644
--- a/core/modules/system/css/system.module.css
+++ b/core/modules/system/css/system.module.css
@@ -4,29 +4,6 @@
*/
/**
- * Autocomplete.
- *
- * @see autocomplete.js
- */
-
-/* Animated throbber */
-.js input.form-autocomplete {
- background-image: url(../../../misc/throbber-inactive.png);
- background-position: 100% center; /* LTR */
- background-repeat: no-repeat;
-}
-.js[dir="rtl"] input.form-autocomplete {
- background-position: 0% center;
-}
-.js input.form-autocomplete.ui-autocomplete-loading {
- background-image: url(../../../misc/throbber-active.gif);
- background-position: 100% center; /* LTR */
-}
-.js[dir="rtl"] input.form-autocomplete.ui-autocomplete-loading {
- background-position: 0% center;
-}
-
-/**
* Unboxed fieldsets for grouping form elements.
*/
.fieldgroup {
diff --git a/core/modules/system/css/system.theme.css b/core/modules/system/css/system.theme.css
index 48fc3dd..964f0c8 100644
--- a/core/modules/system/css/system.theme.css
+++ b/core/modules/system/css/system.theme.css
@@ -195,18 +195,6 @@ label button.link {
font-weight: bold;
}
-/*
- * Autocomplete.
- *
- * @see autocomplete.js
- */
-/* Suggestion list */
-.ui-autocomplete li.ui-menu-item a.ui-state-focus, .autocomplete li.ui-menu-item a.ui-state-hover {
- background: #0072b9;
- color: #fff;
- margin: 0;
-}
-
/**
* Collapsible details.
*
diff --git a/core/modules/system/src/Form/RegionalForm.php b/core/modules/system/src/Form/RegionalForm.php
index 2d3934f..0550370 100644
--- a/core/modules/system/src/Form/RegionalForm.php
+++ b/core/modules/system/src/Form/RegionalForm.php
@@ -98,6 +98,8 @@ public function buildForm(array $form, FormStateInterface $form_state) {
'#title' => t('Default time zone'),
'#default_value' => $system_date->get('timezone.default') ?: date_default_timezone_get(),
'#options' => $zones,
+ // Use the Select2 library.
+ '#select2' => TRUE,
);
$configurable_timezones = $system_date->get('timezone.user.configurable');
diff --git a/core/modules/taxonomy/src/Controller/TermAutocompleteController.php b/core/modules/taxonomy/src/Controller/TermAutocompleteController.php
index d701c90..de5d207 100644
--- a/core/modules/taxonomy/src/Controller/TermAutocompleteController.php
+++ b/core/modules/taxonomy/src/Controller/TermAutocompleteController.php
@@ -182,13 +182,12 @@ protected function getMatchingTerms($tags_typed, array $vids, $tag_last) {
->range(0, 10)
->execute();
- $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : '';
if (!empty($tids)) {
$terms = $this->entityManager->getStorage('taxonomy_term')->loadMultiple(array_keys($tids));
foreach ($terms as $term) {
// Term names containing commas or quotes must be wrapped in quotes.
$name = Tags::encode($term->getName());
- $matches[] = array('value' => $prefix . $name, 'label' => String::checkPlain($term->getName()));
+ $matches[] = array('id' => $name, 'text' => String::checkPlain($term->getName()));
}
return $matches;
}
diff --git a/core/modules/taxonomy/src/Tests/TermTest.php b/core/modules/taxonomy/src/Tests/TermTest.php
index 72694c0..7169d6b 100644
--- a/core/modules/taxonomy/src/Tests/TermTest.php
+++ b/core/modules/taxonomy/src/Tests/TermTest.php
@@ -272,13 +272,13 @@ function testNodeTermCreationAndDeletion() {
// The term will be quoted, and the " will be encoded in unicode (\u0022).
$input = substr($term_objects['term3']->getName(), 0, 3);
$json = $this->drupalGet('taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(), array('query' => array('q' => $input)));
- $this->assertEqual($json, '[{"value":"\u0022' . $term_objects['term3']->getName() . '\u0022","label":"' . $term_objects['term3']->getName() . '"}]', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term3']->getName())));
+ $this->assertEqual($json, '[{"id":"\u0022' . $term_objects['term3']->getName() . '\u0022","text":"' . $term_objects['term3']->getName() . '"}]', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term3']->getName())));
// Test autocomplete on term 4 - it is alphanumeric only, so no extra
// quoting.
$input = substr($term_objects['term4']->getName(), 0, 3);
$this->drupalGet('taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(), array('query' => array('q' => $input)));
- $this->assertRaw('[{"value":"' . $term_objects['term4']->getName() . '","label":"' . $term_objects['term4']->getName() . '"}', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term4']->getName())));
+ $this->assertRaw('[{"id":"' . $term_objects['term4']->getName() . '","text":"' . $term_objects['term4']->getName() . '"}', format_string('Autocomplete returns term %term_name after typing the first 3 letters.', array('%term_name' => $term_objects['term4']->getName())));
// Test taxonomy autocomplete with a nonexistent field.
$field_name = $this->randomMachineName();
@@ -315,7 +315,7 @@ function testTermAutocompletion() {
// Pull the label properties from the array of arrays.
$data = Json::decode($result);
$data = array_map(function ($item) {
- return $item['label'];
+ return $item['text'];
}, $data);
$this->assertTrue(in_array(String::checkPlain($first_term->getName()), $data), 'Autocomplete returned the first matching term');
@@ -327,8 +327,8 @@ function testTermAutocompletion() {
$path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id();
$this->drupalGet($path, array('query' => array('q' => $input)));
$target = array(array(
- 'value' => String::checkPlain($first_term->getName()),
- 'label' => $first_term->getName(),
+ 'id' => String::checkPlain($first_term->getName()),
+ 'text' => $first_term->getName(),
));
$this->assertRaw(Json::encode($target), 'Autocomplete returns only the expected matching term.');
@@ -339,8 +339,8 @@ function testTermAutocompletion() {
// Term names containing commas or quotes must be wrapped in quotes.
$n = Tags::encode($third_term->getName());
$target = array(array(
- 'value' => $n,
- 'label' => String::checkPlain($third_term->getName()),
+ 'id' => $n,
+ 'text' => String::checkPlain($third_term->getName()),
));
$this->assertRaw(Json::encode($target), 'Autocomplete returns a term containing a comma and a slash.');
}
diff --git a/core/modules/user/src/Tests/UserAutocompleteTest.php b/core/modules/user/src/Tests/UserAutocompleteTest.php
index a56c33c..dc97721 100644
--- a/core/modules/user/src/Tests/UserAutocompleteTest.php
+++ b/core/modules/user/src/Tests/UserAutocompleteTest.php
@@ -49,7 +49,7 @@ function testUserAutocomplete() {
// Test that anonymous username is in the result when requested and escaped
// with \Drupal\Component\Utility\String::checkPlain().
$users = $this->drupalGetJSON('user/autocomplete/anonymous', array('query' => array('q' => Unicode::substr($anonymous_name, 0, 4))));
- $this->assertEqual(String::checkPlain($anonymous_name), $users[0]['label'], 'The anonymous name found in autocompletion results.');
+ $this->assertEqual(String::checkPlain($anonymous_name), $users[0]['text'], 'The anonymous name found in autocompletion results.');
$users = $this->drupalGetJSON('user/autocomplete', array('query' => array('q' => Unicode::substr($anonymous_name, 0, 4))));
$this->assertTrue(empty($users), 'The anonymous name not found in autocompletion results without enabling anonymous username.');
}
diff --git a/core/modules/user/src/UserAutocomplete.php b/core/modules/user/src/UserAutocomplete.php
index cb75d5b..9b28b42 100644
--- a/core/modules/user/src/UserAutocomplete.php
+++ b/core/modules/user/src/UserAutocomplete.php
@@ -74,7 +74,7 @@ public function getMatches($string, $include_anonymous = FALSE) {
$anonymous_name = $this->configFactory->get('user.settings')->get('anonymous');
// Allow autocompletion for the anonymous user.
if (stripos($anonymous_name, $string) !== FALSE) {
- $matches[] = array('value' => $anonymous_name, 'label' => String::checkPlain($anonymous_name));
+ $matches[] = array('id' => $anonymous_name, 'text' => String::checkPlain($anonymous_name));
}
}
$uids = $this->entityQuery->get('user')
@@ -84,7 +84,7 @@ public function getMatches($string, $include_anonymous = FALSE) {
$controller = $this->entityManager->getStorage('user');
foreach ($controller->loadMultiple($uids) as $account) {
- $matches[] = array('value' => $account->getUsername(), 'label' => String::checkPlain($account->getUsername()));
+ $matches[] = array('id' => $account->getUsername(), 'text' => String::checkPlain($account->getUsername()));
}
}
diff --git a/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php b/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php
index 270da71..b8ac329 100644
--- a/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php
+++ b/core/modules/views/src/Tests/ViewsTaxonomyAutocompleteTest.php
@@ -75,8 +75,8 @@ public function testTaxonomyAutocomplete() {
// Test a with whole name term.
$label = $this->term1->getName();
$expected = array(array(
- 'value' => $label,
- 'label' => String::checkPlain($label),
+ 'id' => $label,
+ 'text' => String::checkPlain($label),
));
$this->assertIdentical($expected, $this->drupalGetJSON($base_autocomplete_path, array('query' => array('q' => $label))));
// Test a term by partial name.
diff --git a/core/themes/seven/css/components/jquery.ui.theme.css b/core/themes/seven/css/components/jquery.ui.theme.css
index b22ca5e..2d95975 100644
--- a/core/themes/seven/css/components/jquery.ui.theme.css
+++ b/core/themes/seven/css/components/jquery.ui.theme.css
@@ -381,10 +381,3 @@
border-color: #D2D2D2;
color: #000;
}
-
-/**
- * Autocomplete
- */
-.ui-autocomplete {
- background: #fff;
-}