Browse Source

HUE-6815 [frontend] Enable inline autocomplete in the global search input

Johan Ahlen 8 years ago
parent
commit
7054ca7

+ 1 - 0
desktop/core/src/desktop/templates/hue.mako

@@ -470,6 +470,7 @@ ${ hueIcons.symbols() }
 
 <script src="${ static('desktop/js/autocomplete/sqlParseSupport.js') }"></script>
 <script src="${ static('desktop/js/autocomplete/sqlAutocompleteParser.js') }"></script>
+<script src="${ static('desktop/js/autocomplete/globalSearchParser.js') }"></script>
 <script src="${ static('desktop/js/sqlAutocompleter.js') }"></script>
 <script src="${ static('desktop/js/sqlAutocompleter2.js') }"></script>
 <script src="${ static('desktop/js/hdfsAutocompleter.js') }"></script>

+ 92 - 21
desktop/core/src/desktop/templates/ko_components.mako

@@ -552,8 +552,8 @@ from desktop.views import _ko
   <script type="text/html" id="hue-global-search-template">
     <div class="global-search-input-container">
       <div>
-        <input class="global-search-input" placeholder="${ _('Search data and saved documents...') }" type="text" data-bind="textInput: searchInput, hasFocus: searchHasFocus">
-        <input class="global-search-autocomplete" disabled type="text" data-bind="value: searchAutocomplete">
+        <input class="global-search-input" type="text" data-bind="attr: { 'placeHolder' : searchHasFocus() ? '' : '${ _ko('Search data and saved documents...') }' }, textInput: searchInput, hasFocus: searchHasFocus">
+        <input class="global-search-autocomplete" disabled type="text" data-bind="value: inlineAutocomplete">
       </div>
     </div>
     <!-- ko if: searchResultVisible-->
@@ -601,10 +601,15 @@ from desktop.views import _ko
         'HUE': 'fa-file-o'
       };
 
+      var FACETS = [
+        'tags', 'type'
+      ];
+
       var GlobalSearch = function (params) {
         var self = this;
         self.searchHasFocus = ko.observable(false);
         self.searchInput = ko.observable('');
+        self.inlineAutocomplete = ko.observable('');
         self.searchActive = ko.observable(false);
 
         self.searchResultCategories = ko.observableArray([]);
@@ -616,6 +621,73 @@ from desktop.views import _ko
           }
         });
 
+        var lastNonPartial = null;
+        var lastResult = {};
+
+        var updateInlineAutocomplete = function (partial) {
+          self.inlineAutocomplete('');
+          if (lastResult.suggestFacets) {
+            if (partial === '') {
+              self.inlineAutocomplete(lastNonPartial + FACETS[0] + ':');
+            } else {
+              var lowerCase = partial.length !== '' && partial[partial.length - 1].toLowerCase() === partial[partial.length - 1];
+              var suggestion = lastNonPartial + partial;
+              FACETS.every(function (facet) {
+                if (facet.indexOf(partial.toLowerCase()) === 0) {
+                  var remainder = facet.substring(partial.length);
+                  suggestion += lowerCase ? remainder : remainder.toUpperCase();
+                  suggestion += ':';
+                  self.inlineAutocomplete(suggestion);
+                  return false;
+                }
+                return true;
+              });
+            }
+          }
+        };
+
+        var triggerAutocomplete = function (newValue, direct) {
+          self.inlineAutocomplete(newValue);
+          var partial, nonPartial;
+          var partialMatch = newValue.match(/([a-z]+)$/i);
+          if (partialMatch) {
+            partial = partialMatch[0];
+            nonPartial = newValue.substring(0, newValue.length - partial.length);
+          } else {
+            partial = '';
+            nonPartial = newValue;
+          }
+
+          if (lastNonPartial && lastNonPartial === nonPartial) {
+            updateInlineAutocomplete(partial);
+            return;
+          }
+
+          window.clearTimeout(autocompleteThrottle);
+          autocompleteThrottle = window.setTimeout(function () {
+            lastNonPartial = nonPartial;
+
+            // TODO: Get cursor position and split to before and after
+            lastResult = globalSearchParser.parseGlobalSearch(newValue, '');
+            if (hueDebug && hueDebug.showGlobalSearchParseResults) {
+              console.log(lastResult);
+            }
+            if (lastResult) {
+              updateInlineAutocomplete(partial);
+            } else {
+              lastNonPartial = null;
+            }
+          }, direct ? 0 : 200);
+        };
+
+        var autocompleteThrottle = -1;
+        self.searchInput.subscribe(function (newValue) {
+          self.inlineAutocomplete(newValue);
+          if (newValue !== '') {
+            triggerAutocomplete(newValue);
+          }
+        });
+
         self.searchResultCategories([
           {
             label: 'Top Hits',
@@ -651,6 +723,19 @@ from desktop.views import _ko
         ]);
 
         $(document).keydown(function (event) {
+          if (event.keyCode === 32 && event.ctrlKey) {
+            triggerAutocomplete(self.searchInput(), true);
+            return;
+          } else if (event.keyCode === 39 && self.inlineAutocomplete() !== self.searchInput()) {
+            // TODO: Check that cursor is last
+            self.searchInput(self.inlineAutocomplete());
+            return;
+          } else if (event.keyCode === 9 && self.inlineAutocomplete() !== self.searchInput()) { // Tab
+            self.searchInput(self.inlineAutocomplete());
+            event.preventDefault();
+            return;
+          }
+
           if (self.searchResultVisible() && self.searchResultCategories().length > 0) {
             var currentIndex = self.selectedIndex();
             if (event.keyCode === 40) { // Down
@@ -675,29 +760,15 @@ from desktop.views import _ko
                 self.selectedIndex({ categoryIndex: self.searchResultCategories().length - 1, resultIndex: self.searchResultCategories()[self.searchResultCategories().length - 1].result.length - 1 });
               }
               event.preventDefault();
-            } else if (event.keyCode === 13) { // Enter
-              if (self.selectedIndex()) {
-                self.openResult();
-              }
-            } else if (event.keyCode === 9) { // Tab
-              if (self.searchAutocomplete() !== self.searchInput()) {
-                self.searchInput(self.searchAutocomplete());
-                event.preventDefault();
-              } else {
-                if (!self.selectedIndex()) {
-                  self.selectedIndex({categoryIndex: 0, resultIndex: 0});
-                  event.preventDefault();
-                }
-              }
+            } else if (event.keyCode === 13 && self.selectedIndex()) { // Enter
+              self.openResult();
+            } else if (event.keyCode === 9 && !self.selectedIndex()) { // Tab
+              self.selectedIndex({categoryIndex: 0, resultIndex: 0});
+              event.preventDefault();
             }
           }
         });
 
-        self.searchAutocomplete = ko.pureComputed(function () {
-          // TODO: Add autocomplete suggestions here
-          return self.searchInput() + '';
-        });
-
         self.searchResultVisible = ko.observable(false);
 
         self.searchResultVisible.subscribe(function (newVal) {