MDL-51966 forms: case-insensitive search in autocomplete
authorMarina Glancy <marina@moodle.com>
Thu, 29 Oct 2015 05:49:56 +0000 (13:49 +0800)
committerMarina Glancy <marina@moodle.com>
Thu, 29 Oct 2015 07:10:20 +0000 (15:10 +0800)
lib/amd/build/form-autocomplete.min.js
lib/amd/src/form-autocomplete.js
lib/form/autocomplete.php

index bced484..4fbc871 100644 (file)
Binary files a/lib/amd/build/form-autocomplete.min.js and b/lib/amd/build/form-autocomplete.min.js differ
index 70eb9de..660a280 100644 (file)
@@ -250,8 +250,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
      * @param {JQuery} originalSelect The JQuery object matching the hidden select list.
      * @param {Boolean} multiple Are multiple items allowed to be selected?
      * @param {Boolean} tags Are we allowed to create new items on the fly?
+     * @param {Boolean} caseSensitive - If search has to be made case sensitive.
      */
-    var updateSuggestions = function(query, inputId, suggestionsId, originalSelect, multiple, tags) {
+    var updateSuggestions = function(query, inputId, suggestionsId, originalSelect, multiple, tags, caseSensitive) {
         // Find the elements in the DOM.
         var inputElement = $(document.getElementById(inputId));
         var suggestionsElement = $(document.getElementById(suggestionsId));
@@ -267,6 +268,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
         });
 
         // Re-render the list of suggestions.
+        var searchquery = caseSensitive ? query : query.toLocaleLowerCase();
         templates.render(
             'core/form_autocomplete_suggestions',
             { inputId: inputId, suggestionsId: suggestionsId, options: options, multiple: multiple}
@@ -280,7 +282,8 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
             // For each option in the list, hide it if it doesn't match the query.
             suggestionsElement.children().each(function(index, node) {
                 node = $(node);
-                if (node.text().indexOf(query) > -1) {
+                if ((caseSensitive && node.text().indexOf(searchquery) > -1) ||
+                        (!caseSensitive && node.text().toLocaleLowerCase().indexOf(searchquery) > -1)) {
                     node.show().attr('aria-hidden', false);
                     matchingElements = true;
                 } else {
@@ -460,8 +463,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
      * @param {Boolean} multiple Are multiple items allowed to be selected?
      * @param {Boolean} tags Are we allowed to create new items on the fly?
      * @param {Object} ajaxHandler This is a module that does the ajax fetch and translates the results.
+     * @param {Boolean} caseSensitive - If search has to be made case sensitive.
      */
-    var updateAjax = function(e, selector, inputId, suggestionsId, originalSelect, multiple, tags, ajaxHandler) {
+    var updateAjax = function(e, selector, inputId, suggestionsId, originalSelect, multiple, tags, ajaxHandler, caseSensitive) {
         // Get the query to pass to the ajax function.
         var query = $(e.currentTarget).val();
         // Call the transport function to do the ajax (name taken from Select2).
@@ -489,7 +493,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 }
             });
             // Update the list of suggestions now from the new values in the select list.
-            updateSuggestions('', inputId, suggestionsId, originalSelect, multiple, tags);
+            updateSuggestions('', inputId, suggestionsId, originalSelect, multiple, tags, caseSensitive);
         }, notification.exception);
     };
 
@@ -508,8 +512,18 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
      * @param {String} selector The selector for this select list.
      * @param {String} ajax Name of an AMD module to handle ajax requests. If specified, the AMD
      *                      module must expose 2 functions "transport" and "processResults".
+     * @param {Boolean} caseSensitive - If search has to be made case sensitive.
      */
-    var addNavigation = function(inputId, suggestionsId, downArrowId, selectionId, originalSelect, multiple, tags, selector, ajax) {
+    var addNavigation = function(inputId,
+                                 suggestionsId,
+                                 downArrowId,
+                                 selectionId,
+                                 originalSelect,
+                                 multiple,
+                                 tags,
+                                 selector,
+                                 ajax,
+                                 caseSensitive) {
         // Start with the input element.
         var inputElement = $(document.getElementById(inputId));
         // Add keyboard nav with keydown.
@@ -523,11 +537,25 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                         // Handle ajax population of suggestions.
                         if (!inputElement.val() && ajax) {
                             require([ajax], function(ajaxHandler) {
-                                updateAjax(e, selector, inputId, suggestionsId, originalSelect, multiple, tags, ajaxHandler);
+                                updateAjax(e,
+                                    selector,
+                                    inputId,
+                                    suggestionsId,
+                                    originalSelect,
+                                    multiple,
+                                    tags,
+                                    ajaxHandler,
+                                    caseSensitive);
                             });
                         } else {
                             // Else - open the suggestions list.
-                            updateSuggestions(inputElement.val(), inputId, suggestionsId, originalSelect, multiple, tags);
+                            updateSuggestions(inputElement.val(),
+                                inputId,
+                                suggestionsId,
+                                originalSelect,
+                                multiple,
+                                tags,
+                                caseSensitive);
                         }
                     }
                     // We handled this event, so prevent it.
@@ -599,7 +627,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 window.clearTimeout(closeSuggestionsTimer);
             }
             // Show the suggestions list.
-            updateSuggestions(inputElement.val(), inputId, suggestionsId, originalSelect, multiple, tags);
+            updateSuggestions(inputElement.val(), inputId, suggestionsId, originalSelect, multiple, tags, caseSensitive);
         });
 
         var suggestionsElement = $(document.getElementById(suggestionsId));
@@ -654,7 +682,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
         // Whenever the input field changes, update the suggestion list.
         inputElement.on('input', function(e) {
             var query = $(e.currentTarget).val();
-            updateSuggestions(query, inputId, suggestionsId, originalSelect, multiple, tags);
+            updateSuggestions(query, inputId, suggestionsId, originalSelect, multiple, tags, caseSensitive);
         });
     };
 
@@ -670,8 +698,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
          *                      module must expose 2 functions "transport" and "processResults".
          *                      These are modeled on Select2 see: https://select2.github.io/options.html#ajax
          * @param {String} placeholder - The text to display before a selection is made.
+         * @param {Boolean} caseSensitive - If search has to be made case sensitive.
          */
-        enhance: function(selector, tags, ajax, placeholder) {
+        enhance: function(selector, tags, ajax, placeholder, caseSensitive) {
             // Set some default values.
             if (typeof tags === "undefined") {
                 tags = false;
@@ -679,6 +708,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
             if (typeof ajax === "undefined") {
                 ajax = false;
             }
+            if (typeof caseSensitive === "undefined") {
+                caseSensitive = false;
+            }
 
             // Look for the select element.
             var originalSelect = $(selector);
@@ -732,7 +764,16 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 // Update the form label to point to the text input.
                 originalLabel.attr('for', inputId);
                 // Add the event handlers.
-                addNavigation(inputId, suggestionsId, downArrowId, selectionId, originalSelect, multiple, tags, selector, ajax);
+                addNavigation(inputId,
+                    suggestionsId,
+                    downArrowId,
+                    selectionId,
+                    originalSelect,
+                    multiple,
+                    tags,
+                    selector,
+                    ajax,
+                    caseSensitive);
 
                 var inputElement = $(document.getElementById(inputId));
                 var suggestionsElement = $(document.getElementById(suggestionsId));
@@ -743,7 +784,15 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 if (ajax) {
                     require([ajax], function(ajaxHandler) {
                         var handler = function(e) {
-                            updateAjax(e, selector, inputId, suggestionsId, originalSelect, multiple, tags, ajaxHandler);
+                            updateAjax(e,
+                                selector,
+                                inputId,
+                                suggestionsId,
+                                originalSelect,
+                                multiple,
+                                tags,
+                                ajaxHandler,
+                                caseSensitive);
                         };
                         // Trigger an ajax update after the text field value changes.
                         inputElement.on("input keypress", handler);
index 4207373..c63cd29 100644 (file)
@@ -46,6 +46,8 @@ class MoodleQuickForm_autocomplete extends MoodleQuickForm_select {
     protected $ajax = '';
     /** @var string $placeholder Placeholder text for an empty list. */
     protected $placeholder = '';
+    /** @var bool $casesensitive Wether the search has to be case-sensitive. */
+    protected $casesensitive = false;
 
     /**
      * constructor
@@ -54,7 +56,7 @@ class MoodleQuickForm_autocomplete extends MoodleQuickForm_select {
      * @param mixed $elementLabel Label(s) for the select
      * @param mixed $options Data to be used to populate options
      * @param mixed $attributes Either a typical HTML attribute string or an associative array. Special options
-     *                          "tags", "placeholder", "ajax", "multiple" are supported.
+     *                          "tags", "placeholder", "ajax", "multiple", "casesensitive" are supported.
      */
     function MoodleQuickForm_autocomplete($elementName=null, $elementLabel=null, $options=null, $attributes=null) {
         // Even if the constructor gets called twice we do not really want 2x options (crazy forms!).
@@ -75,6 +77,10 @@ class MoodleQuickForm_autocomplete extends MoodleQuickForm_select {
             $this->ajax = $attributes['ajax'];
             unset($attributes['ajax']);
         }
+        if (isset($attributes['casesensitive'])) {
+            $this->casesensitive = $attributes['casesensitive'] ? true : false;
+            unset($attributes['casesensitive']);
+        }
         parent::HTML_QuickForm_select($elementName, $elementLabel, $options, $attributes);
 
         $this->_type = 'autocomplete';
@@ -91,7 +97,8 @@ class MoodleQuickForm_autocomplete extends MoodleQuickForm_select {
         // Enhance the select with javascript.
         $this->_generateId();
         $id = $this->getAttribute('id');
-        $PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array('#' . $id, $this->tags, $this->ajax, $this->placeholder));
+        $PAGE->requires->js_call_amd('core/form-autocomplete', 'enhance', $params = array('#' . $id, $this->tags, $this->ajax,
+            $this->placeholder, $this->casesensitive));
 
         return parent::toHTML();
     }