diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TermAutocompleteController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TermAutocompleteController.php index a4f7019..844ccb0 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TermAutocompleteController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Controller/TermAutocompleteController.php @@ -14,6 +14,7 @@ use Drupal\Core\Entity\Query\QueryInterface; use Drupal\field\FieldInfo; use Drupal\taxonomy\TermStorageControllerInterface; +use Drupal\taxonomy\VocabularyInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -129,34 +130,81 @@ public function autocomplete(Request $request, $entity_type, $field_name) { $vids[] = $tree['vocabulary']; } - $this->termEntityQuery->addTag('term_access'); + $matches = $this->getMatchingTerms($tags_typed, $vids, $tag_last); + } - // Do not select already entered terms. - if (!empty($tags_typed)) { - $this->termEntityQuery->condition('name', $tags_typed, 'NOT IN'); - } - // Select rows that match by term name. - $tids = $this->termEntityQuery - ->condition('vid', $vids, 'IN') - ->condition('name', $tag_last, 'CONTAINS') - ->range(0, 10) - ->execute(); - - $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : ''; - if (!empty($tids)) { - $terms = $this->termStorage->loadMultiple(array_keys($tids)); - foreach ($terms as $term) { - $name = $term->label(); - // Term names containing commas or quotes must be wrapped in quotes. - if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) { - $name = '"' . str_replace('"', '""', $name) . '"'; - } - $matches[$prefix . $name] = String::checkPlain($term->label()); + return new JsonResponse($matches); + } + + /** + * Retrieves suggestions for taxonomy term autocompletion by vocabulary ID. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. + * @param \Drupal\taxonomy\VocabularyInterface $taxonomy_vocabulary + * The vocabulary to filter by. + * + * @return \Symfony\Component\HttpFoundation\JsonResponse + * A JSON response containing the autocomplete suggestions for taxonomy + * terms. + */ + public function autocompletePerVid(Request $request, VocabularyInterface $taxonomy_vocabulary) { + // A comma-separated list of term names entered in the autocomplete form + // element. Only the last term is used for autocompletion. + $tags_typed = $request->query->get('q'); + $tags_typed = Tags::explode($tags_typed); + $tag_last = Unicode::strtolower(array_pop($tags_typed)); + + $matches = array(); + if ($tag_last != '') { + $vids = array($taxonomy_vocabulary->id()); + $matches = $this->getMatchingTerms($tags_typed, $vids, $tag_last); + } + return new JsonResponse($matches); + } + + /** + * Gets terms which matches some typed terms. + * + * @param string $tags_typed + * The full typed tags string. + * @param array $vids + * An array of vocabulary IDs which + * @param $tag_last + * The lasted typed tag. + * + * @return array + * Returns an array of matching terms. + */ + protected function getMatchingTerms($tags_typed, array $vids, $tag_last) { + $matches = array(); + $this->termEntityQuery->addTag('term_access'); + + // Do not select already entered terms. + if (!empty($tags_typed)) { + $this->termEntityQuery->condition('name', $tags_typed, 'NOT IN'); + } + // Select rows that match by term name. + $tids = $this->termEntityQuery + ->condition('vid', $vids, 'IN') + ->condition('name', $tag_last, 'CONTAINS') + ->range(0, 10) + ->execute(); + + $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : ''; + if (!empty($tids)) { + $terms = $this->termStorage->loadMultiple(array_keys($tids)); + foreach ($terms as $term) { + $name = $term->label(); + // Term names containing commas or quotes must be wrapped in quotes. + if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) { + $name = '"' . str_replace('"', '""', $name) . '"'; } + $matches[$prefix . $name] = String::checkPlain($term->label()); } + return $matches; } - - return new JsonResponse($matches); + return $matches; } } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/filter/TaxonomyIndexTid.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/filter/TaxonomyIndexTid.php index 9ef575f..72a66c7 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/filter/TaxonomyIndexTid.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Plugin/views/filter/TaxonomyIndexTid.php @@ -127,7 +127,8 @@ protected function valueForm(&$form, &$form_state) { ); if ($this->options['limit']) { - $form['value']['#autocomplete_path'] = 'admin/views/ajax/autocomplete/taxonomy/' . $vocabulary->id(); + $form['value']['#autocomplete_route_name'] = 'taxonomy_autocomplete_vid'; + $form['value']['#autocomplete_route_parameters'] = array('taxonomy_vocabulary' => $vocabulary->id()); } } else { diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyIndexTidUiTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyIndexTidUiTest.php index 1075d7b..17c8829 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyIndexTidUiTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyIndexTidUiTest.php @@ -93,6 +93,16 @@ public function testFilterUI() { $this->assertEqual($terms[$i][$j]->id(), $tid); } } + + // Ensure the autocomplete input element appears when using the 'textfield' + // type. + $view = entity_load('view', 'test_filter_taxonomy_index_tid'); + $display =& $view->getDisplay('default'); + $display['display_options']['filters']['tid']['type'] = 'textfield'; + $view->save(); + $this->drupalGet('admin/structure/views/nojs/config-item/test_filter_taxonomy_index_tid/default/filter/tid'); + $result = $this->xpath('//input[@id = "edit-options-value-autocomplete"]'); + $this->assertEqual((string) $result[0]['value'], url('taxonomy/autocomplete_vid/tags')); } } diff --git a/core/modules/taxonomy/taxonomy.routing.yml b/core/modules/taxonomy/taxonomy.routing.yml index 817c6f6..cb8f46f 100644 --- a/core/modules/taxonomy/taxonomy.routing.yml +++ b/core/modules/taxonomy/taxonomy.routing.yml @@ -61,6 +61,13 @@ taxonomy_autocomplete: requirements: _permission: 'access content' +taxonomy_autocomplete_vid: + pattern: '/taxonomy/autocomplete_vid/{taxonomy_vocabulary}' + defaults: + _controller: '\Drupal\taxonomy\Controller\TermAutocompleteController::autocompletePerVid' + requirements: + _permission: 'access content' + taxonomy_overview_terms: pattern: 'admin/structure/taxonomy/manage/{taxonomy_vocabulary}' defaults: diff --git a/core/modules/views/includes/ajax.inc b/core/modules/views/includes/ajax.inc index a662cc8..788d1c1 100644 --- a/core/modules/views/includes/ajax.inc +++ b/core/modules/views/includes/ajax.inc @@ -5,16 +5,9 @@ * Handles the server side AJAX interactions of Views. */ -use Symfony\Component\HttpFoundation\JsonResponse; use Drupal\views\Ajax\HighlightCommand; use Drupal\views\Ajax\SetFormCommand; -use Drupal\Core\Ajax\ReplaceCommand; -use Drupal\views\Ajax\ScrollTopCommand; -use Drupal\views\Ajax\ViewAjaxResponse; use Drupal\Core\Ajax\AjaxResponse; -use Drupal\Component\Utility\Tags; -use Drupal\Component\Utility\Unicode; -use Drupal\Component\Utility\String; /** * @defgroup views_ajax Views AJAX library @@ -80,53 +73,5 @@ function views_ajax_form_wrapper($form_id, &$form_state) { } /** - * Page callback for views taxonomy autocomplete. - * - * @param $vid - * The vocabulary id of the tags which should be returned. - * - * @see taxonomy_autocomplete() - */ -function views_ajax_autocomplete_taxonomy($vid) { - // The user enters a comma-separated list of tags. We only autocomplete the - // last tag. - $tags_typed = Tags::explode(Drupal::request()->query->get('q')); - $tag_last = Unicode::strtolower(array_pop($tags_typed)); - $term_matches = array(); - - if ($tag_last != '') { - $query = db_select('taxonomy_term_data', 't'); - $query->addTag('term_access'); - - // Do not select already entered terms. - if (!empty($tags_typed)) { - $query->condition('t.name', $tags_typed, 'NOT IN'); - } - // Select rows that match by term name. - $tags_return = $query - ->fields('t', array('tid', 'name')) - ->condition('t.vid', $vid) - ->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE') - ->range(0, 10) - ->execute() - ->fetchAllKeyed(); - - $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : ''; - - foreach ($tags_return as $tid => $name) { - $n = $name; - // Term names containing commas or quotes must be wrapped in quotes. - if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) { - $n = '"' . str_replace('"', '""', $name) . '"'; - } - // Add term name to list of matches. - $term_matches[$prefix . $n] = String::checkPlain($name); - } - } - - return new JsonResponse($term_matches); -} - -/** * @} */ diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php index 6dec14c..ef5f98d 100644 --- a/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php +++ b/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php @@ -74,7 +74,7 @@ public function setUp() { public function testTaxonomyAutocomplete() { $this->user = $this->drupalCreateUser(array('access content')); $this->drupalLogin($this->user); - $base_autocomplete_path = 'admin/views/ajax/autocomplete/taxonomy/' . $this->vocabulary->vid; + $base_autocomplete_path = 'taxonomy/autocomplete_vid/' . $this->vocabulary->vid; // Test that no terms returns an empty array. $this->assertIdentical(array(), $this->drupalGetJSON($base_autocomplete_path)); diff --git a/core/modules/views/views.module b/core/modules/views/views.module index dadfb78..5bc91b2 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -322,17 +322,6 @@ function views_menu() { 'route_name' => 'views_ajax', 'type' => MENU_CALLBACK, ); - // Define another taxonomy autocomplete because the default one of drupal - // does not support a vid a argument anymore - $items['admin/views/ajax/autocomplete/taxonomy/%'] = array( - 'page callback' => 'views_ajax_autocomplete_taxonomy', - 'page arguments' => array(5), - 'theme callback' => 'ajax_base_page_theme', - 'access callback' => 'user_access', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - 'file' => 'includes/ajax.inc', - ); return $items; }