MDL-60773 core: Add pendingJS checks for autocomplete interactions
authorAndrew Nicols <andrew@nicols.co.uk>
Fri, 10 Nov 2017 06:18:51 +0000 (14:18 +0800)
committerJake Dallimore <jake@moodle.com>
Fri, 17 Nov 2017 05:52:04 +0000 (13:52 +0800)
lib/amd/build/form-autocomplete.min.js
lib/amd/src/form-autocomplete.js

index 3b75249..e5c8906 100644 (file)
Binary files a/lib/amd/build/form-autocomplete.min.js and b/lib/amd/build/form-autocomplete.min.js differ
index 76294eb..29ae071 100644 (file)
@@ -448,6 +448,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 $(ele).prop('selected', true);
             }
         });
+
         // Rerender the selection list.
         updateSelectionList(options, state, originalSelect);
         // Notifiy that the selection changed.
@@ -478,6 +479,8 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
      * @param {Object} ajaxHandler This is a module that does the ajax fetch and translates the results.
      */
     var updateAjax = function(e, options, state, originalSelect, ajaxHandler) {
+        var pendingKey = 'form-autocomplete-updateajax';
+        M.util.js_pending(pendingKey);
         // 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).
@@ -514,7 +517,11 @@ 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(options, state, '', originalSelect);
-        }, notification.exception);
+            M.util.js_complete(pendingKey);
+        }, function(error) {
+            M.util.js_complete(pendingKey);
+            notification.exception(error);
+        });
     };
 
     /**
@@ -531,11 +538,15 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
         var inputElement = $(document.getElementById(state.inputId));
         // Add keyboard nav with keydown.
         inputElement.on('keydown', function(e) {
+            var pendingKey = 'form-autocomplete-addnav-' + state.inputId + '-' + e.keyCode;
+            M.util.js_pending(pendingKey);
+
             switch (e.keyCode) {
                 case KEYS.DOWN:
                     // If the suggestion list is open, move to the next item.
                     if (!options.showSuggestions) {
                         // Do not consume this event.
+                        M.util.js_complete(pendingKey);
                         return true;
                     } else if (inputElement.attr('aria-expanded') === "true") {
                         activateNextItem(state);
@@ -552,12 +563,14 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                     }
                     // We handled this event, so prevent it.
                     e.preventDefault();
+                    M.util.js_complete(pendingKey);
                     return false;
                 case KEYS.UP:
                     // Choose the previous active item.
                     activatePreviousItem(state);
                     // We handled this event, so prevent it.
                     e.preventDefault();
+                    M.util.js_complete(pendingKey);
                     return false;
                 case KEYS.ENTER:
                     var suggestionsElement = $(document.getElementById(state.suggestionsId));
@@ -571,6 +584,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                     }
                     // We handled this event, so prevent it.
                     e.preventDefault();
+                    M.util.js_complete(pendingKey);
                     return false;
                 case KEYS.ESCAPE:
                     if (inputElement.attr('aria-expanded') === "true") {
@@ -579,12 +593,16 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                     }
                     // We handled this event, so prevent it.
                     e.preventDefault();
+                    M.util.js_complete(pendingKey);
                     return false;
             }
+            M.util.js_complete(pendingKey);
             return true;
         });
         // Support multi lingual COMMA keycode (44).
         inputElement.on('keypress', function(e) {
+            var pendingKey = 'form-autocomplete-keypress-' + e.keyCode;
+            M.util.js_pending(pendingKey);
             if (e.keyCode === KEYS.COMMA) {
                 if (options.tags) {
                     // If we are allowing tags, comma should create a tag (or enter).
@@ -592,13 +610,17 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 }
                 // We handled this event, so prevent it.
                 e.preventDefault();
+                M.util.js_complete(pendingKey);
                 return false;
             }
+            M.util.js_complete(pendingKey);
             return true;
         });
         // Handler used to force set the value from behat.
         inputElement.on('behat:set-value', function() {
             var suggestionsElement = $(document.getElementById(state.suggestionsId));
+            var pendingKey = 'form-autocomplete-behat';
+            M.util.js_pending(pendingKey);
             if ((inputElement.attr('aria-expanded') === "true") &&
                     (suggestionsElement.children('[aria-selected=true]').length > 0)) {
                 // If the suggestion list has an active item, select it.
@@ -607,8 +629,11 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 // If tags are enabled, create a tag.
                 createItem(options, state, originalSelect);
             }
+            M.util.js_complete(pendingKey);
         });
         inputElement.on('blur', function() {
+            var pendingKey = 'form-autocomplete-blur';
+            M.util.js_pending(pendingKey);
             window.setTimeout(function() {
                 // Get the current element with focus.
                 var focusElement = $(document.activeElement);
@@ -619,11 +644,14 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                     }
                     closeSuggestions(state);
                 }
+                M.util.js_complete(pendingKey);
             }, 500);
         });
         if (options.showSuggestions) {
             var arrowElement = $(document.getElementById(state.downArrowId));
             arrowElement.on('click', function(e) {
+                var pendingKey = 'form-autocomplete-show-suggestions';
+                M.util.js_pending(pendingKey);
                 // Prevent the close timer, or we will open, then close the suggestions.
                 inputElement.focus();
                 // Handle ajax population of suggestions.
@@ -635,11 +663,14 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                     // Else - open the suggestions list.
                     updateSuggestions(options, state, inputElement.val(), originalSelect);
                 }
+                M.util.js_complete(pendingKey);
             });
         }
 
         var suggestionsElement = $(document.getElementById(state.suggestionsId));
         suggestionsElement.parent().on('click', '[role=option]', function(e) {
+            var pendingKey = 'form-autocomplete-parent';
+            M.util.js_pending(pendingKey);
             // Handle clicks on suggestions.
             var element = $(e.currentTarget).closest('[role=option]');
             var suggestionsElement = $(document.getElementById(state.suggestionsId));
@@ -649,29 +680,37 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
             activateItem(current, state);
             // And select it.
             selectCurrentItem(options, state, originalSelect);
+            M.util.js_complete(pendingKey);
         });
         var selectionElement = $(document.getElementById(state.selectionId));
         // Handle clicks on the selected items (will unselect an item).
         selectionElement.on('click', '[role=listitem]', function(e) {
+            var pendingKey = 'form-autocomplete-clicks';
+            M.util.js_pending(pendingKey);
             // Get the item that was clicked.
             var item = $(e.currentTarget);
             // Remove it from the selection.
             deselectItem(options, state, item, originalSelect);
+            M.util.js_complete(pendingKey);
         });
         // Keyboard navigation for the selection list.
         selectionElement.on('keydown', function(e) {
+            var pendingKey = 'form-autocomplete-keydown-' + e.keyCode;
+            M.util.js_pending(pendingKey);
             switch (e.keyCode) {
                 case KEYS.DOWN:
                     // Choose the next selection item.
                     activateNextSelection(state);
                     // We handled this event, so prevent it.
                     e.preventDefault();
+                    M.util.js_complete(pendingKey);
                     return false;
                 case KEYS.UP:
                     // Choose the previous selection item.
                     activatePreviousSelection(state);
                     // We handled this event, so prevent it.
                     e.preventDefault();
+                    M.util.js_complete(pendingKey);
                     return false;
                 case KEYS.SPACE:
                 case KEYS.ENTER:
@@ -683,8 +722,10 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                         // We handled this event, so prevent it.
                         e.preventDefault();
                     }
+                    M.util.js_complete(pendingKey);
                     return false;
             }
+            M.util.js_complete(pendingKey);
             return true;
         });
         // Whenever the input field changes, update the suggestion list.
@@ -693,8 +734,10 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
             if (options.ajax) {
                 require([options.ajax], function(ajaxHandler) {
                     var throttleTimeout = null;
+                    var pendingKey = 'autocomplete-throttledhandler';
                     var handler = function(e) {
                         updateAjax(e, options, state, originalSelect, ajaxHandler);
+                        M.util.js_complete(pendingKey);
                     };
 
                     // For input events, we do not want to trigger many, many updates.
@@ -702,6 +745,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                         if (throttleTimeout !== null) {
                             window.clearTimeout(throttleTimeout);
                             throttleTimeout = null;
+                        } else {
+                            // No existing timeout handler, so this is the start of a throttling check.
+                            M.util.js_pending(pendingKey);
                         }
                         throttleTimeout = window.setTimeout(handler.bind(this, e), 300);
                     };
@@ -756,6 +802,8 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
                 showSuggestions: true,
                 noSelectionString: noSelectionString
             };
+            var pendingKey = 'autocomplete-setup-' + selector;
+            M.util.js_pending(pendingKey);
             if (typeof tags !== "undefined") {
                 options.tags = tags;
             }
@@ -778,6 +826,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
             var originalSelect = $(selector);
             if (!originalSelect) {
                 log.debug('Selector not found: ' + selector);
+                M.util.js_complete(pendingKey);
                 return false;
             }
 
@@ -839,7 +888,11 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
 
                 // Show the current values in the selection list.
                 updateSelectionList(options, state, originalSelect);
+                M.util.js_complete(pendingKey);
                 return true;
+            }).fail(function(error) {
+                M.util.js_complete(pendingKey);
+                notification.exception(error);
             });
         }
     };