From 71cb5448caf5bad591c0ab1f18e44a71388f982d Mon Sep 17 00:00:00 2001 From: Brian Canini <canini.16@osu.edu> Date: Wed, 4 Mar 2020 10:42:59 -0500 Subject: [PATCH] Updating drupal/views_autocomplete_filters (1.1.0 => 1.2.0) --- composer.json | 4 +- composer.lock | 16 +- vendor/composer/installed.json | 16 +- ...iews_autocomplete_filters.views.schema.yml | 113 ++++++ .../views-autocomplete-filters-dependent.js | 351 ++++++++++++++---- .../js/views-autocomplete-filters.js | 21 ++ .../ViewsAutocompleteFiltersController.php | 70 ++-- .../ViewsAutocompleteFiltersCombine.php | 125 +------ .../ViewsAutocompleteFiltersInterface.php | 17 + ...wsAutocompleteFiltersSearchApiFulltext.php | 29 ++ .../ViewsAutocompleteFiltersSearchApiText.php | 21 ++ .../filter/ViewsAutocompleteFiltersString.php | 138 +------ .../filter/ViewsAutocompleteFiltersTrait.php | 162 ++++++++ .../views_autocomplete_filters.info.yml | 6 +- .../views_autocomplete_filters.libraries.yml | 8 + .../views_autocomplete_filters.views.inc | 12 +- 16 files changed, 740 insertions(+), 369 deletions(-) create mode 100644 web/modules/views_autocomplete_filters/config/schema/views_autocomplete_filters.views.schema.yml create mode 100644 web/modules/views_autocomplete_filters/js/views-autocomplete-filters.js create mode 100644 web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersInterface.php create mode 100644 web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiFulltext.php create mode 100644 web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiText.php create mode 100644 web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersTrait.php diff --git a/composer.json b/composer.json index 8de26d8ad5..b25e8cfdc7 100644 --- a/composer.json +++ b/composer.json @@ -177,7 +177,7 @@ "drupal/view_unpublished": "^1.0@alpha", "drupal/views_accordion": "1.1", "drupal/views_ajax_history": "^1.1", - "drupal/views_autocomplete_filters": "1.1", + "drupal/views_autocomplete_filters": "1.2", "drupal/views_bootstrap": "3.1", "drupal/views_bulk_operations": "^3.0", "drupal/views_fieldsets": "3.3", @@ -316,4 +316,4 @@ "php": "7.0.8" } } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index e304ef53bb..7b0303c87c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9cebdfa2dca9a89bb18005ed1f9db499", + "content-hash": "1ef3b6e293db50b4ebd66d3e2d88a077", "packages": [ { "name": "alchemy/zippy", @@ -7915,17 +7915,17 @@ }, { "name": "drupal/views_autocomplete_filters", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/views_autocomplete_filters.git", - "reference": "8.x-1.1" + "reference": "8.x-1.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.1.zip", - "reference": "8.x-1.1", - "shasum": "08dda1e5bdc3e25e7946fc64642cf245c4f429cf" + "url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.2.zip", + "reference": "8.x-1.2", + "shasum": "bab27febe29aa69eff5c6b3ce3125e49685a6346" }, "require": { "drupal/core": "*" @@ -7936,7 +7936,7 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.1", + "version": "8.x-1.2", "datestamp": "1500109743", "security-coverage": { "status": "covered", @@ -7961,7 +7961,7 @@ "description": "Use Autocomplete for string field filters.", "homepage": "https://www.drupal.org/project/views_autocomplete_filters", "support": { - "source": "http://cgit.drupalcode.org/views_autocomplete_filters" + "source": "https://git.drupalcode.org/project/views_autocomplete_filters" } }, { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 899a4506a1..a27afb929d 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -8166,18 +8166,18 @@ }, { "name": "drupal/views_autocomplete_filters", - "version": "1.1.0", - "version_normalized": "1.1.0.0", + "version": "1.2.0", + "version_normalized": "1.2.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/views_autocomplete_filters.git", - "reference": "8.x-1.1" + "reference": "8.x-1.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.1.zip", - "reference": "8.x-1.1", - "shasum": "08dda1e5bdc3e25e7946fc64642cf245c4f429cf" + "url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.2.zip", + "reference": "8.x-1.2", + "shasum": "bab27febe29aa69eff5c6b3ce3125e49685a6346" }, "require": { "drupal/core": "*" @@ -8188,7 +8188,7 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.1", + "version": "8.x-1.2", "datestamp": "1500109743", "security-coverage": { "status": "covered", @@ -8214,7 +8214,7 @@ "description": "Use Autocomplete for string field filters.", "homepage": "https://www.drupal.org/project/views_autocomplete_filters", "support": { - "source": "http://cgit.drupalcode.org/views_autocomplete_filters" + "source": "https://git.drupalcode.org/project/views_autocomplete_filters" } }, { diff --git a/web/modules/views_autocomplete_filters/config/schema/views_autocomplete_filters.views.schema.yml b/web/modules/views_autocomplete_filters/config/schema/views_autocomplete_filters.views.schema.yml new file mode 100644 index 0000000000..2e5bb17d9a --- /dev/null +++ b/web/modules/views_autocomplete_filters/config/schema/views_autocomplete_filters.views.schema.yml @@ -0,0 +1,113 @@ +views.filter.views_autocomplete_filters_combine: + type: views.filter.combine + label: 'Autocomplete for Combine fields filter' + mapping: + expose: + type: mapping + label: 'Exposed' + mapping: + autocomplete_filter: + type: integer + label: 'Use Autocomplete' + autocomplete_min_chars: + type: string + label: 'Minimum number of characters to start filter' + autocomplete_items: + type: string + label: 'Maximum number of items in Autocomplete' + autocomplete_raw_suggestion: + type: integer + label: 'Unformatted suggestion' + autocomplete_raw_dropdown: + type: integer + label: 'Unformatted dropdown' + autocomplete_dependent: + type: integer + label: 'Suggestions depend on other filter fields' + +views.filter.views_autocomplete_filters_search_api_fulltext: + type: views.filter.search_api_fulltext + label: 'Autocomplete for Search API fulltext search filter' + mapping: + expose: + type: mapping + label: 'Exposed' + mapping: + autocomplete_filter: + type: integer + label: 'Use Autocomplete' + autocomplete_min_chars: + type: string + label: 'Minimum number of characters to start filter' + autocomplete_items: + type: string + label: 'Maximum number of items in Autocomplete' + autocomplete_raw_suggestion: + type: integer + label: 'Unformatted suggestion' + autocomplete_raw_dropdown: + type: integer + label: 'Unformatted dropdown' + autocomplete_dependent: + type: integer + label: 'Suggestions depend on other filter fields' + +views.filter.views_autocomplete_filters_search_api_text: + type: views.filter.search_api_text + label: 'Autocomplete for Search API text field filter' + mapping: + expose: + type: mapping + label: 'Exposed' + mapping: + autocomplete_filter: + type: integer + label: 'Use Autocomplete' + autocomplete_min_chars: + type: string + label: 'Minimum number of characters to start filter' + autocomplete_items: + type: string + label: 'Maximum number of items in Autocomplete' + autocomplete_field: + type: string + label: 'Field with autocomplete results' + autocomplete_raw_suggestion: + type: integer + label: 'Unformatted suggestion' + autocomplete_raw_dropdown: + type: integer + label: 'Unformatted dropdown' + autocomplete_dependent: + type: integer + label: 'Suggestions depend on other filter fields' + +views.filter.views_autocomplete_filters_string: + type: views.filter.string + label: 'Autocomplete for basic textfield filter' + mapping: + expose: + type: mapping + label: 'Exposed' + mapping: + autocomplete_filter: + type: integer + label: 'Use Autocomplete' + autocomplete_min_chars: + type: string + label: 'Minimum number of characters to start filter' + autocomplete_items: + type: string + label: 'Maximum number of items in Autocomplete' + autocomplete_field: + type: string + label: 'Field with autocomplete results' + autocomplete_raw_suggestion: + type: integer + label: 'Unformatted suggestion' + autocomplete_raw_dropdown: + type: integer + label: 'Unformatted dropdown' + autocomplete_dependent: + type: integer + label: 'Suggestions depend on other filter fields' diff --git a/web/modules/views_autocomplete_filters/js/views-autocomplete-filters-dependent.js b/web/modules/views_autocomplete_filters/js/views-autocomplete-filters-dependent.js index c2a194bc55..9e81b71b4c 100644 --- a/web/modules/views_autocomplete_filters/js/views-autocomplete-filters-dependent.js +++ b/web/modules/views_autocomplete_filters/js/views-autocomplete-filters-dependent.js @@ -1,78 +1,297 @@ -(function ($) { - /** - * Overrides function from misc/autocomplete.js to send full form values instead - * of just autocomplete value. + * @file + * Autocomplete based on jQuery UI. */ -Drupal.ACDB.prototype.search = function (searchString) { - var db = this; - this.searchString = searchString; - - // See if this string needs to be searched for anyway. - searchString = searchString.replace(/^\s+|\s+$/, ''); - if (searchString.length <= 0 || - searchString.charAt(searchString.length - 1) == ',') { - return; - } - // See if this key has been searched for before. - if (this.cache[searchString]) { - return this.owner.found(this.cache[searchString]); +(function ($, Drupal) { + + 'use strict'; + + var autocomplete; + + /** + * Helper splitting terms from the autocomplete value. + * + * @function Drupal.autocomplete.splitValues + * + * @param {string} value + * The value being entered by the user. + * + * @return {Array} + * Array of values, split by comma. + */ + function autocompleteSplitValues(value) { + // We will match the value against comma-separated terms. + var result = []; + var quote = false; + var current = ''; + var valueLength = value.length; + var character; + + for (var i = 0; i < valueLength; i++) { + character = value.charAt(i); + if (character === '"') { + current += character; + quote = !quote; + } + else if (character === ',' && !quote) { + result.push(current.trim()); + current = ''; + } + else { + current += character; + } + } + if (value.length > 0) { + result.push($.trim(current)); + } + + return result; } - // Fill data with form values if we're working with dependent autocomplete - var data = ''; - if (this.owner.isDependent()) { - data = this.owner.serializeOuterForm(); + /** + * Returns the last value of an multi-value textfield. + * + * @function Drupal.autocomplete.extractLastTerm + * + * @param {string} terms + * The value of the field. + * + * @return {string} + * The last value of the input field. + */ + function extractLastTerm(terms) { + return autocomplete.splitValues(terms).pop(); } - // Initiate delayed search. - if (this.timer) { - clearTimeout(this.timer); + /** + * The search handler is called before a search is performed. + * + * @function Drupal.autocomplete.options.search + * + * @param {object} event + * The event triggered. + * + * @return {bool} + * Whether to perform a search or not. + */ + function searchHandler(event) { + var options = autocomplete.options; + var term = autocomplete.extractLastTerm(event.target.value); + // Abort search if the first character is in firstCharacterBlacklist. + if (term.length > 0 && options.firstCharacterBlacklist.indexOf(term[0]) !== -1) { + return false; + } + // Only search when the term is at least the minimum length. + return term.length >= options.minLength; } - this.timer = setTimeout(function () { - db.owner.setStatus('begin'); - - // Ajax GET request for autocompletion. We use Drupal.encodePath instead of - // encodeURIComponent to allow autocomplete search terms to contain slashes. - $.ajax({ - type: 'GET', - url: db.uri + '/' + Drupal.encodePath(searchString), - data: data, - dataType: 'json', - success: function (matches) { - if (typeof matches.status == 'undefined' || matches.status != 0) { - db.cache[searchString] = matches; - // Verify if these are still the matches the user wants to see. - if (db.searchString == searchString) { - db.owner.found(matches); - } - db.owner.setStatus('found'); + + /** + * JQuery UI autocomplete source callback. + * + * @param {object} request + * The request object. + * @param {function} response + * The function to call with the response. + */ + function sourceData(request, response) { + 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 + * Suggestions returned by the server. + */ + function showSuggestions(suggestions) { + var tagged = autocomplete.splitValues(request.term); + var il = tagged.length; + for (var i = 0; i < il; i++) { + var index = suggestions.toString().indexOf(tagged[i]); + if (index >= 0) { + suggestions.splice(index, 1); } - }, - error: function (xmlhttp) { - alert(Drupal.ajaxError(xmlhttp, db.uri)); } - }); - }, this.delay); -}; + response(suggestions); + } -/** - * Function which checks if autocomplete depends on other filter fields. - */ -Drupal.jsAC.prototype.isDependent = function() { - return $(this.input).hasClass('views-ac-dependent-filter'); -}; + /** + * Transforms the data object into an array and update autocomplete results. + * + * @param {object} data + * The data sent back from the server. + */ + function sourceCallbackHandler(data) { + autocomplete.cache[elementId][term] = data; -/** - * Returns serialized input values from form except autocomplete input. - */ -Drupal.jsAC.prototype.serializeOuterForm = function() { - return $(this.input) - .parents('form:first') - .find('select[name], textarea[name], input[name][type!=submit]') - .not(this.input) - .serialize(); -}; - -})(jQuery); \ No newline at end of file + // 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 data_string = []; + data_string.success = sourceCallbackHandler; + data_string.data = {}; + data_string.data['q'] = term; + + if (Drupal.isDependent(this.element)) { + var a = Drupal.serializeOuterForm(this.element); + $.each(a, function (key, value) { + data_string.data[value['name']] = value['value']; + }); + } + var options = $.extend(data_string, autocomplete.ajax); + $.ajax(this.element.attr('data-autocomplete-path'), options); + } + } + + /** + * Handles an autocompletefocus event. + * + * @return {bool} + * Always returns false. + */ + function focusHandler() { + return false; + } + + /** + * Handles an autocompleteselect event. + * + * @param {jQuery.Event} event + * The event triggered. + * @param {object} ui + * The jQuery UI settings object. + * + * @return {bool} + * Returns false to indicate the event status. + */ + function selectHandler(event, ui) { + var terms = autocomplete.splitValues(event.target.value); + // Remove the current input. + terms.pop(); + // Add the selected item. + 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 {jQuery} ul + * jQuery collection of the ul element. + * @param {object} item + * The list item to append. + * + * @return {jQuery} + * jQuery collection of the ul element. + */ + function renderItem(ul, item) { + return $('<li>') + .append($('<a>').html(item.label)) + .appendTo(ul); + } + + /** + * Attaches the autocomplete behavior to all required fields. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the autocomplete behaviors. + * @prop {Drupal~behaviorDetach} detach + * Detaches the autocomplete behaviors. + */ + 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) { + // Allow options to be overriden per instance. + var blacklist = $autocomplete.attr('data-autocomplete-first-character-blacklist'); + $.extend(autocomplete.options, { + firstCharacterBlacklist: (blacklist) ? blacklist : '' + }); + // Use jQuery UI Autocomplete on the textfield. + $autocomplete.autocomplete(autocomplete.options) + .each(function () { + $(this).data('ui-autocomplete')._renderItem = autocomplete.options.renderItem; + }); + } + }, + detach: function (context, settings, trigger) { + if (trigger === 'unload') { + $(context).find('input.form-autocomplete') + .removeOnce('autocomplete') + .autocomplete('destroy'); + } + } + }; + + /** + * Autocomplete object implementation. + * + * @namespace Drupal.autocomplete + */ + autocomplete = { + cache: {}, + // Exposes options to allow overriding by contrib. + splitValues: autocompleteSplitValues, + extractLastTerm: extractLastTerm, + // jQuery UI autocomplete options. + + /** + * JQuery UI option object. + * + * @name Drupal.autocomplete.options + */ + options: { + source: sourceData, + focus: focusHandler, + search: searchHandler, + select: selectHandler, + renderItem: renderItem, + minLength: 1, + // Custom options, used by Drupal.autocomplete. + firstCharacterBlacklist: '' + }, + ajax: { + dataType: 'json' + } + }; + + Drupal.autocomplete = autocomplete; + + /** + * Function which checks if autocomplete depends on other filter fields. + */ + Drupal.isDependent = function (element) { + return $(element).hasClass('views-ac-dependent-filter'); + }; + + /** + * Returns serialized input values from form except autocomplete input. + */ + Drupal.serializeOuterForm = function (element) { + return $(element) + .parents('form:first') + .find('select[name], textarea[name], input[name][type!=submit]') + .not(this.input) + .serializeArray(); + }; + +})(jQuery, Drupal); diff --git a/web/modules/views_autocomplete_filters/js/views-autocomplete-filters.js b/web/modules/views_autocomplete_filters/js/views-autocomplete-filters.js new file mode 100644 index 0000000000..a1394fbdbe --- /dev/null +++ b/web/modules/views_autocomplete_filters/js/views-autocomplete-filters.js @@ -0,0 +1,21 @@ +/** + * @file + * Expands the behaviour of the default autocompletion. + */ + +(function ($, Drupal) { + + // Override the "select" option of the jQueryUI autocomplete + // to make sure we do not use quotes for inputs with comma. + Drupal.autocomplete.options.select = function (event, ui) { + var terms = Drupal.autocomplete.splitValues(event.target.value); + // Remove the current input. + terms.pop(); + // Add the selected item. + 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; + }; + +})(jQuery, Drupal); diff --git a/web/modules/views_autocomplete_filters/src/Controller/ViewsAutocompleteFiltersController.php b/web/modules/views_autocomplete_filters/src/Controller/ViewsAutocompleteFiltersController.php index 9b0d2b74e6..5d7fc54da2 100644 --- a/web/modules/views_autocomplete_filters/src/Controller/ViewsAutocompleteFiltersController.php +++ b/web/modules/views_autocomplete_filters/src/Controller/ViewsAutocompleteFiltersController.php @@ -1,10 +1,5 @@ <?php -/** - * @file - * Contains \Drupal\views_autocomplete_filters\Controller\ViewsAutocompleteFiltersController. - */ - namespace Drupal\views_autocomplete_filters\Controller; use Drupal\Component\Utility\Html; @@ -12,6 +7,7 @@ use Drupal\Core\Access\AccessResult; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\views\Views; +use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\JsonResponse; @@ -22,11 +18,29 @@ */ class ViewsAutocompleteFiltersController implements ContainerInjectionInterface { + /** + * @var \Psr\Log\LoggerInterface + */ + protected $logger; + + + /** + * ViewsAutocompleteFiltersController constructor. + * + * @param \Psr\Log\LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) { + $this->logger = $logger; + } + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static(); + return new static( + $container->get('logger.factory')->get('views_autocomplete_filters') + ); } /** @@ -75,7 +89,7 @@ public function access($view_name, $view_display) { * containing a failure message. */ public function autocomplete(Request $request, $view_name, $view_display, $filter_name, $view_args) { - $matches = []; + $matches = $field_names = []; $string = $request->query->get('q'); // Get view and execute. $view = Views::getView($view_name); @@ -103,8 +117,8 @@ public function autocomplete(Request $request, $view_name, $view_display, $filte if (empty($filters[$filter_name]['exposed']) || empty($filters[$filter_name]['expose']['autocomplete_filter'])) { throw new NotFoundHttpException(); } - $filter = $filters[$filter_name]; - $expose_options = $filter['expose']; + $current_filter = $filters[$filter_name]; + $expose_options = $current_filter['expose']; // Do not filter if the string length is less that minimum characters setting. if (strlen(trim($string)) < $expose_options['autocomplete_min_chars']) { @@ -112,20 +126,20 @@ public function autocomplete(Request $request, $view_name, $view_display, $filte } // Determine fields which will be used for output. - if (empty($expose_options['autocomplete_field']) && !empty($filter['name']) ) { - if ($view->getHandler($display_name, 'field', $filters[$filter_name]['id'])) { + if (empty($expose_options['autocomplete_field']) && !empty($current_filter['name']) ) { + if ($view->getHandler($view->current_display, 'field', $filters[$filter_name]['id'])) { $field_names = [[$filter_name]['id']]; - // force raw data for no autocomplete field defined. + // Force raw data for no autocomplete field defined. $expose_options['autocomplete_raw_suggestion'] = 1; $expose_options['autocomplete_raw_dropdown'] = 1; } else { // Field is not set, report about it to watchdog and return empty array. - watchdog('views_autocomplete_filters', 'Field for autocomplete filter %label is not set in view %view, display %display', [ + $this->logger->error('Field for autocomplete filter %label is not set in view %view, display %display', [ '%label' => $expose_options['label'], - '%view' => $view->name, - '%display' => $display->id, - ], WATCHDOG_ERROR); + '%view' => $view->id(), + '%display' => $view->current_display, + ]); return new JsonResponse($matches); } } @@ -134,20 +148,20 @@ public function autocomplete(Request $request, $view_name, $view_display, $filte $field_names =[$expose_options['autocomplete_field']]; } // For combine fields autocomplete filter. - elseif (!empty($filter['fields'])) { - $field_names = array_keys($filter['fields']); + elseif (!empty($current_filter['fields'])) { + $field_names = array_keys($current_filter['fields']); } // Get fields options and check field exists in this display. foreach ($field_names as $field_name) { - $field_options = $view->getHandler($view_display, 'field', $field_name); + $field_options = $view->getHandler($view->current_display, 'field', $field_name); if (empty($field_options)) { // Field not exists, report about it to watchdog and return empty array. - watchdog('views_autocomplete_filters', 'Field for autocomplete filter %label not exists in view %view, display %display', [ + $this->logger->error('Field for autocomplete filter %label not exists in view %view, display %display', [ '%label' => $expose_options['label'], - '%view' => $view->name, - '%display' => $display->id, - ], WATCHDOG_ERROR); + '%view' => $view->id(), + '%display' => $view->current_display, + ]); return new JsonResponse($matches); } } @@ -194,6 +208,7 @@ public function autocomplete(Request $request, $view_name, $view_display, $filte foreach ($view->result as $index => $row) { $view->row_index = $index; $rendered_field = $raw_field = ''; + /** @var \Drupal\views\Plugin\views\style\StylePluginBase $style_plugin */ $style_plugin = $display_handler->getPlugin('style'); foreach ($field_names as $field_name) { @@ -207,6 +222,13 @@ public function autocomplete(Request $request, $view_name, $view_display, $filte if (!is_array($raw_field)) { $raw_field = [['value' => $raw_field]]; } + else { + $raw_field_items = $raw_field; + $raw_field = []; + foreach ($raw_field_items as $raw_field_item) { + $raw_field[] = ['value' => $raw_field_item]; + } + } } if (empty($raw_field)) { @@ -236,7 +258,7 @@ public function autocomplete(Request $request, $view_name, $view_display, $filte // provide a solution for such messages. if (!empty($matches)) { - $matches = array_unique($matches, SORT_REGULAR); + $matches = array_values(array_unique($matches, SORT_REGULAR)); } return new JsonResponse($matches); diff --git a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersCombine.php b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersCombine.php index acca936002..2858405b56 100644 --- a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersCombine.php +++ b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersCombine.php @@ -1,13 +1,7 @@ <?php -/** - * @file - * Definition of Drupal\views_autocomplete_filters\Plugin\views\filter\ViewsAutocompleteFiltersCombine. - */ - namespace Drupal\views_autocomplete_filters\Plugin\views\filter; -use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\filter\Combine; /** @@ -18,127 +12,18 @@ * * @ViewsFilter("views_autocomplete_filters_combine") */ -class ViewsAutocompleteFiltersCombine extends Combine { +class ViewsAutocompleteFiltersCombine extends Combine implements ViewsAutocompleteFiltersInterface { // Exposed filter options. var $alwaysMultiple = TRUE; - protected function defineOptions() { - $options = parent::defineOptions(); - - $options['expose']['contains']['required'] = ['default' => FALSE, 'bool' => TRUE]; - $options['expose']['contains'] += [ - 'autocomplete_filter' => ['default' => 0], - 'autocomplete_min_chars' => ['default' => 0], - 'autocomplete_items' => ['default' => 10], - 'autocomplete_raw_suggestion' => ['default' => TRUE], - 'autocomplete_raw_dropdown' => ['default' => TRUE], - 'autocomplete_dependent' => ['default' => FALSE], - ]; - - return $options; - } + use ViewsAutocompleteFiltersTrait; /** - * Build the options form. + * {@inheritdoc} */ - public function buildOptionsForm(&$form, FormStateInterface $form_state) { - parent::buildOptionsForm($form, $form_state); - - if ($this->canExpose() && !empty($form['expose'])) { - $field_options_all = $this->view->display_handler->getFieldLabels(); - // Limit options to fields with the same name. - foreach ($this->view->display_handler->getHandlers('field') as $id => $handler) { - if ($handler->realField == $this->realField) { - $field_options[$id] = $field_options_all[$id]; - } - } - if (empty($field_options)) { - $field_options[''] = $this->t('Add some fields to view'); - } - - // Build form elements for the right side of the exposed filter form - $states = [ - 'visible' => [' - :input[name="options[expose][autocomplete_filter]"]' => ['checked' => TRUE], - ], - ]; - $form['expose'] += [ - 'autocomplete_filter' => [ - '#type' => 'checkbox', - '#title' => $this->t('Use Autocomplete'), - '#default_value' => $this->options['expose']['autocomplete_filter'], - '#description' => $this->t('Use Autocomplete for this filter.'), - ], - 'autocomplete_items' => [ - '#type' => 'textfield', - '#title' => $this->t('Maximum number of items in Autocomplete'), - '#default_value' => $this->options['expose']['autocomplete_items'], - '#description' => $this->t('Enter 0 for no limit.'), - '#states' => $states, - ], - 'autocomplete_min_chars' => [ - '#type' => 'textfield', - '#title' => t('Minimum number of characters to start filter'), - '#default_value' => $this->options['expose']['autocomplete_min_chars'], - '#element_validate' => ['element_validate_integer'], - '#states' => $states, - ], - 'autocomplete_dependent' => [ - '#type' => 'checkbox', - '#title' => $this->t('Suggestions depend on other filter fields'), - '#default_value' => $this->options['expose']['autocomplete_dependent'], - '#description' => $this->t('Autocomplete suggestions will be filtered by other filter fields'), - '#states' => $states, - ], - 'autocomplete_raw_dropdown' => [ - '#type' => 'checkbox', - '#title' => $this->t('Unformatted dropdown'), - '#default_value' => $this->options['expose']['autocomplete_raw_dropdown'], - '#description' => $this->t('Use unformatted data from database for dropdown list instead of field formatter result. Value will be printed as plain text.'), - '#states' => $states, - ], - 'autocomplete_raw_suggestion' => [ - '#type' => 'checkbox', - '#title' => $this->t('Unformatted suggestion'), - '#default_value' => $this->options['expose']['autocomplete_raw_suggestion'], - '#description' => $this->t('The same as above, but for suggestion (text appearing inside textfield when item is selected).'), - '#states' => $states, - ], - ]; - } - } - - public function valueForm(&$form, FormStateInterface $form_state) { - parent::valueForm($form, $form_state); - $exposed = $form_state->get('exposed'); - if (!$exposed || empty($this->options['expose']['autocomplete_filter'])) { - // It is not an exposed form or autocomplete is not enabled. - return; - } - - if (empty($form['value']['#type']) || $form['value']['#type'] !== 'textfield') { - // Not a textfield. - return; - } - - // Add autocomplete path to the exposed textfield. - $view_args = !empty($this->view->args) ? implode('||', $this->view->args) : 0; - $form['value']['#autocomplete_route_name'] = 'viewsfilters.autocomplete'; - $form['value']['#autocomplete_route_parameters'] = [ - 'view_name' => $this->view->storage->get('id'), - 'view_display' => $this->view->current_display, - 'filter_name' => $this->options['id'], - 'view_args' => $view_args, - ]; - - // Add JS script with core autocomplete overrides to the end of JS files - // list to be sure it is added after the "misc/autocomplete.js" file. Also - // mark the field with special class. - if (!empty($this->options['expose']['autocomplete_dependent'])) { - $form['#attached']['library'][] = 'views_autocomplete_filters/drupal.views-autocomplete-filters-dependent'; - $form['value']['#attributes']['class'][] = 'views-ac-dependent-filter'; - } + public function hasAutocompleteFieldSelector() { + return FALSE; } } diff --git a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersInterface.php b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersInterface.php new file mode 100644 index 0000000000..34b3f4d7b4 --- /dev/null +++ b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersInterface.php @@ -0,0 +1,17 @@ +<?php + +namespace Drupal\views_autocomplete_filters\Plugin\views\filter; + +/** + * Define extra methods for Autocomplete filters. + */ +interface ViewsAutocompleteFiltersInterface { + + /** + * Returns of the handler has 'autocomplete_field' selector. + * + * @return boolean + */ + public function hasAutocompleteFieldSelector(); + +} diff --git a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiFulltext.php b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiFulltext.php new file mode 100644 index 0000000000..c9dfd86fd1 --- /dev/null +++ b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiFulltext.php @@ -0,0 +1,29 @@ +<?php + +namespace Drupal\views_autocomplete_filters\Plugin\views\filter; + +use Drupal\search_api\Plugin\views\filter\SearchApiFulltext; + +/** + * Autocomplete for Search API fulltext search for the view to handle fulltext + * search filtering. + * + * @ingroup views_filter_handlers + * + * @ViewsFilter("views_autocomplete_filters_search_api_fulltext") + */ +class ViewsAutocompleteFiltersSearchApiFulltext extends SearchApiFulltext implements ViewsAutocompleteFiltersInterface { + + // Exposed filter options. + var $alwaysMultiple = TRUE; + + use ViewsAutocompleteFiltersTrait; + + /** + * {@inheritdoc} + */ + public function hasAutocompleteFieldSelector() { + return FALSE; + } + +} diff --git a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiText.php b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiText.php new file mode 100644 index 0000000000..ac9484ecdc --- /dev/null +++ b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersSearchApiText.php @@ -0,0 +1,21 @@ +<?php + +namespace Drupal\views_autocomplete_filters\Plugin\views\filter; + +use Drupal\search_api\Plugin\views\filter\SearchApiText; + +/** + * Autocomplete for Search API fulltext fields to handle fulltext filtering. + * + * @ingroup views_filter_handlers + * + * @ViewsFilter("views_autocomplete_filters_search_api_text") + */ +class ViewsAutocompleteFiltersSearchApiText extends SearchApiText implements ViewsAutocompleteFiltersInterface { + + // Exposed filter options. + var $alwaysMultiple = TRUE; + + use ViewsAutocompleteFiltersTrait; + +} diff --git a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersString.php b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersString.php index 23181ea16b..96e3ba290f 100644 --- a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersString.php +++ b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersString.php @@ -1,13 +1,7 @@ <?php -/** - * @file - * Definition of Drupal\views_autocomplete_filters\Plugin\views\filter\ViewsAutocompleteFiltersString. - */ - namespace Drupal\views_autocomplete_filters\Plugin\views\filter; -use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\filter\StringFilter; /** @@ -18,139 +12,11 @@ * * @ViewsFilter("views_autocomplete_filters_string") */ -class ViewsAutocompleteFiltersString extends StringFilter { +class ViewsAutocompleteFiltersString extends StringFilter implements ViewsAutocompleteFiltersInterface { // Exposed filter options. var $alwaysMultiple = TRUE; - protected function defineOptions() { - $options = parent::defineOptions(); - - $options['expose']['contains']['required'] = ['default' => FALSE, 'bool' => TRUE]; - $options['expose']['contains'] += [ - 'autocomplete_filter' => ['default' => 0], - 'autocomplete_min_chars' => ['default' => 0], - 'autocomplete_items' => ['default' => 10], - 'autocomplete_field' => ['default' => ''], - 'autocomplete_raw_suggestion' => ['default' => TRUE], - 'autocomplete_raw_dropdown' => ['default' => TRUE], - 'autocomplete_dependent' => ['default' => FALSE], - ]; - - return $options; - } - - /** - * Build the options form. - */ - public function buildOptionsForm(&$form, FormStateInterface $form_state) { - parent::buildOptionsForm($form, $form_state); - - if ($this->canExpose() && !empty($form['expose'])) { - $field_options_all = $this->view->display_handler->getFieldLabels(); - // Limit options to fields with the same name. - foreach ($this->view->display_handler->getHandlers('field') as $id => $handler) { - if ($handler->realField == $this->realField) { - $field_options[$id] = $field_options_all[$id]; - } - } - if (empty($field_options)) { - $field_options[''] = $this->t('Add some fields to view'); - } - elseif (empty($this->options['expose']['autocomplete_field']) && !empty($field_options[$this->options['id']])) { - $this->options['expose']['autocomplete_field'] = $this->options['id']; - } - - // Build form elements for the right side of the exposed filter form. - $states = [ - 'visible' => [' - :input[name="options[expose][autocomplete_filter]"]' => ['checked' => TRUE], - ], - ]; - $form['expose'] += [ - 'autocomplete_filter' => [ - '#type' => 'checkbox', - '#title' => $this->t('Use Autocomplete'), - '#default_value' => $this->options['expose']['autocomplete_filter'], - '#description' => $this->t('Use Autocomplete for this filter.'), - ], - 'autocomplete_items' => [ - '#type' => 'textfield', - '#title' => $this->t('Maximum number of items in Autocomplete'), - '#default_value' => $this->options['expose']['autocomplete_items'], - '#description' => $this->t('Enter 0 for no limit.'), - '#states' => $states, - ], - 'autocomplete_min_chars' => [ - '#type' => 'textfield', - '#title' => t('Minimum number of characters to start filter'), - '#default_value' => $this->options['expose']['autocomplete_min_chars'], - '#element_validate' => ['element_validate_integer'], - '#states' => $states, - ], - 'autocomplete_dependent' => [ - '#type' => 'checkbox', - '#title' => $this->t('Suggestions depend on other filter fields'), - '#default_value' => $this->options['expose']['autocomplete_dependent'], - '#description' => $this->t('Autocomplete suggestions will be filtered by other filter fields'), - '#states' => $states, - ], - 'autocomplete_field' => [ - '#type' => 'select', - '#title' => $this->t('Field with autocomplete results'), - '#default_value' => $this->options['expose']['autocomplete_field'], - '#options' => $field_options, - '#description' => $this->t('Selected field will be used for dropdown results of autocomplete. In most cases it should be the same field you use for filter.'), - '#states' => $states, - ], - 'autocomplete_raw_dropdown' => [ - '#type' => 'checkbox', - '#title' => $this->t('Unformatted dropdown'), - '#default_value' => $this->options['expose']['autocomplete_raw_dropdown'], - '#description' => $this->t('Use unformatted data from database for dropdown list instead of field formatter result. Value will be printed as plain text.'), - '#states' => $states, - ], - 'autocomplete_raw_suggestion' => [ - '#type' => 'checkbox', - '#title' => $this->t('Unformatted suggestion'), - '#default_value' => $this->options['expose']['autocomplete_raw_suggestion'], - '#description' => $this->t('The same as above, but for suggestion (text appearing inside textfield when item is selected).'), - '#states' => $states, - ], - ]; - } - } - - public function valueForm(&$form, FormStateInterface $form_state) { - parent::valueForm($form, $form_state); - $exposed = $form_state->get('exposed'); - if (!$exposed || empty($this->options['expose']['autocomplete_filter'])) { - // It is not an exposed form or autocomplete is not enabled. - return; - } - - if (empty($form['value']['#type']) || $form['value']['#type'] !== 'textfield') { - // Not a textfield. - return; - } - - // Add autocomplete path to the exposed textfield. - $view_args = !empty($this->view->args) ? implode('||', $this->view->args) : 0; - $form['value']['#autocomplete_route_name'] = 'viewsfilters.autocomplete'; - $form['value']['#autocomplete_route_parameters'] = [ - 'view_name' => $this->view->storage->get('id'), - 'view_display' => $this->view->current_display, - 'filter_name' => $this->options['id'], - 'view_args' => $view_args, - ]; - - // Add JS script with core autocomplete overrides to the end of JS files - // list to be sure it is added after the "misc/autocomplete.js" file. Also - // mark the field with special class. - if (!empty($this->options['expose']['autocomplete_dependent'])) { - $form['#attached']['library'][] = 'views_autocomplete_filters/drupal.views-autocomplete-filters-dependent'; - $form['value']['#attributes']['class'][] = 'views-ac-dependent-filter'; - } - } + use ViewsAutocompleteFiltersTrait; } diff --git a/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersTrait.php b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersTrait.php new file mode 100644 index 0000000000..f737d3e3e7 --- /dev/null +++ b/web/modules/views_autocomplete_filters/src/Plugin/views/filter/ViewsAutocompleteFiltersTrait.php @@ -0,0 +1,162 @@ +<?php + +namespace Drupal\views_autocomplete_filters\Plugin\views\filter; + +use Drupal\Core\Form\FormStateInterface; + +/** + * Provides common methods for all Views Autocomplete Filters. + */ +trait ViewsAutocompleteFiltersTrait { + + public function defineOptions() { + $options = parent::defineOptions(); + + $options['expose']['contains']['required'] = ['default' => FALSE, 'bool' => TRUE]; + $options['expose']['contains'] += [ + 'autocomplete_filter' => ['default' => 0], + 'autocomplete_min_chars' => ['default' => 0], + 'autocomplete_items' => ['default' => 10], + 'autocomplete_field' => ['default' => ''], + 'autocomplete_raw_suggestion' => ['default' => TRUE], + 'autocomplete_raw_dropdown' => ['default' => TRUE], + 'autocomplete_dependent' => ['default' => FALSE], + ]; + + if (!$this->hasAutocompleteFieldSelector()) { + unset($options['expose']['contains']['autocomplete_field']); + } + + return $options; + } + + /** + * Build the options form. + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + parent::buildOptionsForm($form, $form_state); + + if ($this->canExpose() && !empty($form['expose'])) { + $field_options_all = $this->view->display_handler->getFieldLabels(); + // Limit options to fields with the same name. + /** @var \Drupal\views\Plugin\views\field\FieldHandlerInterface $handler */ + foreach ($this->view->display_handler->getHandlers('field') as $id => $handler) { + if ($handler->field == $this->realField) { + $field_options[$id] = $field_options_all[$id]; + } + } + if (empty($field_options)) { + $field_options[''] = $this->t('Add some fields to view'); + } + elseif (empty($this->options['expose']['autocomplete_field']) && !empty($field_options[$this->options['id']])) { + $this->options['expose']['autocomplete_field'] = $this->options['id']; + } + + // Build form elements for the right side of the exposed filter form. + $states = [ + 'visible' => [' + :input[name="options[expose][autocomplete_filter]"]' => ['checked' => TRUE], + ], + ]; + $form['expose'] += [ + 'autocomplete_filter' => [ + '#type' => 'checkbox', + '#title' => $this->t('Use Autocomplete'), + '#default_value' => $this->options['expose']['autocomplete_filter'], + '#description' => $this->t('Use Autocomplete for this filter.'), + ], + 'autocomplete_items' => [ + '#type' => 'textfield', + '#title' => $this->t('Maximum number of items in Autocomplete'), + '#default_value' => $this->options['expose']['autocomplete_items'], + '#description' => $this->t('Enter 0 for no limit.'), + '#states' => $states, + ], + 'autocomplete_min_chars' => [ + '#type' => 'textfield', + '#title' => t('Minimum number of characters to start filter'), + '#default_value' => $this->options['expose']['autocomplete_min_chars'], + '#element_validate' => ['element_validate_integer'], + '#states' => $states, + ], + 'autocomplete_dependent' => [ + '#type' => 'checkbox', + '#title' => $this->t('Suggestions depend on other filter fields'), + '#default_value' => $this->options['expose']['autocomplete_dependent'], + '#description' => $this->t('Autocomplete suggestions will be filtered by other filter fields'), + '#states' => $states, + ], + 'autocomplete_field' => [ + '#type' => 'select', + '#title' => $this->t('Field with autocomplete results'), + '#default_value' => $this->options['expose']['autocomplete_field'], + '#options' => $field_options, + '#description' => $this->t('Selected field will be used for dropdown results of autocomplete. In most cases it should be the same field you use for filter.'), + '#states' => $states, + ], + 'autocomplete_raw_dropdown' => [ + '#type' => 'checkbox', + '#title' => $this->t('Unformatted dropdown'), + '#default_value' => $this->options['expose']['autocomplete_raw_dropdown'], + '#description' => $this->t('Use unformatted data from database for dropdown list instead of field formatter result. Value will be printed as plain text.'), + '#states' => $states, + ], + 'autocomplete_raw_suggestion' => [ + '#type' => 'checkbox', + '#title' => $this->t('Unformatted suggestion'), + '#default_value' => $this->options['expose']['autocomplete_raw_suggestion'], + '#description' => $this->t('The same as above, but for suggestion (text appearing inside textfield when item is selected).'), + '#states' => $states, + ], + ]; + if (!$this->hasAutocompleteFieldSelector()) { + unset($form['expose']['autocomplete_field']); + } + } + } + + public function valueForm(&$form, FormStateInterface $form_state) { + parent::valueForm($form, $form_state); + $exposed = $form_state->get('exposed'); + if (!$exposed || empty($this->options['expose']['autocomplete_filter'])) { + // It is not an exposed form or autocomplete is not enabled. + return; + } + + if (empty($form['value']['#type']) || $form['value']['#type'] !== 'textfield') { + // Not a textfield. + return; + } + + // Add autocomplete path to the exposed textfield. + $view_args = !empty($this->view->args) ? implode('||', $this->view->args) : 0; + $form['value']['#autocomplete_route_name'] = 'viewsfilters.autocomplete'; + $form['value']['#autocomplete_route_parameters'] = [ + 'view_name' => $this->view->storage->get('id'), + 'view_display' => $this->view->current_display, + 'filter_name' => $this->options['id'], + 'view_args' => $view_args, + ]; + + // Add JS script to expands the behaviour of the default autocompletion. + // Override the "select" option of the jQueryUI auto-complete for + // to make sure we do not use quotes for inputs with comma. + $form['#attached']['library'][] = 'views_autocomplete_filters/drupal.views-autocomplete-filters'; + + // Add JS script with core autocomplete overrides to the end of JS files + // list to be sure it is added after the "misc/autocomplete.js" file. Also + // mark the field with special class. + if (!empty($this->options['expose']['autocomplete_dependent'])) { + $form['#attached']['library'][] = 'views_autocomplete_filters/drupal.views-autocomplete-filters-dependent'; + $form['value']['#attributes']['class'][] = 'views-ac-dependent-filter'; + } + } + + /** + * Autocomplete filters should have 'autocomplete_field' selector by default. + */ + public function hasAutocompleteFieldSelector() { + return TRUE; + } + +} diff --git a/web/modules/views_autocomplete_filters/views_autocomplete_filters.info.yml b/web/modules/views_autocomplete_filters/views_autocomplete_filters.info.yml index be1baad746..0b096a291a 100644 --- a/web/modules/views_autocomplete_filters/views_autocomplete_filters.info.yml +++ b/web/modules/views_autocomplete_filters/views_autocomplete_filters.info.yml @@ -9,8 +9,8 @@ tags: - views - utility -# Information added by Drupal.org packaging script on 2016-02-20 -version: '8.x-1.1' +# Information added by Drupal.org packaging script on 2017-07-15 +version: '8.x-1.2' core: '8.x' project: 'views_autocomplete_filters' -datestamp: 1455957542 +datestamp: 1500109745 diff --git a/web/modules/views_autocomplete_filters/views_autocomplete_filters.libraries.yml b/web/modules/views_autocomplete_filters/views_autocomplete_filters.libraries.yml index f1297d26be..61a3d73d5d 100644 --- a/web/modules/views_autocomplete_filters/views_autocomplete_filters.libraries.yml +++ b/web/modules/views_autocomplete_filters/views_autocomplete_filters.libraries.yml @@ -1,4 +1,12 @@ drupal.views-autocomplete-filters: + version: VERSION + js: + js/views-autocomplete-filters.js: {} + dependencies: + - core/jquery + - core/drupal + - core/drupal.form +drupal.views-autocomplete-filters-dependent: version: VERSION js: js/views-autocomplete-filters-dependent.js: {} diff --git a/web/modules/views_autocomplete_filters/views_autocomplete_filters.views.inc b/web/modules/views_autocomplete_filters/views_autocomplete_filters.views.inc index d2fd1420ea..90534e4bc4 100644 --- a/web/modules/views_autocomplete_filters/views_autocomplete_filters.views.inc +++ b/web/modules/views_autocomplete_filters/views_autocomplete_filters.views.inc @@ -10,14 +10,22 @@ function views_autocomplete_filters_views_data_alter(array &$data) { foreach ($data as $table_name => $table_data) { foreach ($table_data as $field_name => $field_data) { - // Extend String filter handler with autocomplete capabilities. + // Extend String handler with autocomplete capabilities. if (isset($field_data['filter']['id']) && $field_data['filter']['id'] == 'string') { $data[$table_name][$field_name]['filter']['id'] = 'views_autocomplete_filters_string'; } - // Extend Combine fields filter handler with autocomplete capabilities. + // Extend Combine filter handler with autocomplete capabilities. if (isset($field_data['filter']['id']) && $field_data['filter']['id'] == 'combine') { $data[$table_name][$field_name]['filter']['id'] = 'views_autocomplete_filters_combine'; } + // Extend SearchApiText filter handler with autocomplete capabilities. + if (isset($field_data['filter']['id']) && $field_data['filter']['id'] == 'search_api_text') { + $data[$table_name][$field_name]['filter']['id'] = 'views_autocomplete_filters_search_api_text'; + } + // Extend SearchApiFulltext filter handler with autocomplete capabilities. + if (isset($field_data['filter']['id']) && $field_data['filter']['id'] == 'search_api_fulltext') { + $data[$table_name][$field_name]['filter']['id'] = 'views_autocomplete_filters_search_api_fulltext'; + } } } } -- GitLab