Browse Source

HUE-5526 [editor] Handle mouse events in the new autocomplete dropdown

Johan Ahlen 9 years ago
parent
commit
60505c2

+ 75 - 54
desktop/libs/notebook/src/notebook/templates/hue_ace_autocompleter.mako

@@ -52,6 +52,11 @@ from desktop.views import _ko
       clear: both;
       clear: both;
       background-color: #FFF;
       background-color: #FFF;
       padding:3px;
       padding:3px;
+      cursor: pointer;
+    }
+
+    .autocompleter-list > div:hover {
+      background-color: #DBE8F1;
     }
     }
 
 
     .autocompleter-list > div.selected {
     .autocompleter-list > div.selected {
@@ -62,7 +67,7 @@ from desktop.views import _ko
   <script type="text/html" id="hue-ace-autocompleter">
   <script type="text/html" id="hue-ace-autocompleter">
     <div class="autocompleter-header"><div class="pull-right">header</div></div>
     <div class="autocompleter-header"><div class="pull-right">header</div></div>
     <div class="autocompleter-list" data-bind="foreach: filteredSuggestions">
     <div class="autocompleter-list" data-bind="foreach: filteredSuggestions">
-      <div data-bind="css: { 'selected': $index() === $parent.selectedIndex() }"><div class="pull-left" data-bind="matchedText: { suggestion: $data, filter: $parent.prefixFilter }"></div><div class="pull-right" data-bind="text: meta"></div></div>
+      <div data-bind="click: function () { $parent.selectedIndex($index()); $parent.insertSuggestion(); }, css: { 'selected': $index() === $parent.selectedIndex() }"><div class="pull-left" data-bind="matchedText: { suggestion: $data, filter: $parent.prefixFilter }"></div><div class="pull-right" data-bind="text: meta"></div></div>
     </div>
     </div>
     <!-- /ko -->
     <!-- /ko -->
   </script>
   </script>
@@ -76,7 +81,7 @@ from desktop.views import _ko
         update: function (element, valueAccessor) {
         update: function (element, valueAccessor) {
           var options = valueAccessor();
           var options = valueAccessor();
           var $element = $(element);
           var $element = $(element);
-          $element.empty()
+          $element.empty();
           var suggestion = options.suggestion;
           var suggestion = options.suggestion;
           if (options.filter() && suggestion.matchIndex > -1) {
           if (options.filter() && suggestion.matchIndex > -1) {
             var before = suggestion.value.substring(0, suggestion.matchIndex);
             var before = suggestion.value.substring(0, suggestion.matchIndex);
@@ -94,13 +99,13 @@ from desktop.views import _ko
       function HueAceAutocompleter (params, element) {
       function HueAceAutocompleter (params, element) {
         var self = this;
         var self = this;
         var snippet = params.snippet;
         var snippet = params.snippet;
-        var editor = params.editor;
+        self.editor = params.editor;
 
 
         var autocompleter = new SqlAutocompleter3({ snippet: snippet, timeout: AUTOCOMPLETE_TIMEOUT });
         var autocompleter = new SqlAutocompleter3({ snippet: snippet, timeout: AUTOCOMPLETE_TIMEOUT });
-        self.suggestions = autocompleter.autocomplete(editor.getTextBeforeCursor(), editor.getTextAfterCursor());
+        self.suggestions = autocompleter.autocomplete(self.editor.getTextBeforeCursor(), self.editor.getTextAfterCursor());
 
 
-        var session = editor.getSession();
-        var pos = editor.getCursorPosition();
+        var session = self.editor.getSession();
+        var pos = self.editor.getCursorPosition();
 
 
         var line = session.getLine(pos.row);
         var line = session.getLine(pos.row);
         var prefix = aceUtil.retrievePrecedingIdentifier(line, pos.column);
         var prefix = aceUtil.retrievePrecedingIdentifier(line, pos.column);
@@ -151,8 +156,9 @@ from desktop.views import _ko
               }
               }
               return a.value.localeCompare(b.value);
               return a.value.localeCompare(b.value);
             });
             });
+
             if (self.selectedIndex() > result.length - 1) {
             if (self.selectedIndex() > result.length - 1) {
-              self.selectedIndex(result.length === 0 ? 0 : result.length - 1);
+              self.selectedIndex(result.length - 1);
             }
             }
 
 
             return result;
             return result;
@@ -160,21 +166,24 @@ from desktop.views import _ko
           return self.activeSuggestions();
           return self.activeSuggestions();
         });
         });
 
 
-        self.selectedIndex = ko.observable(0);
+        self.selectedIndex = ko.observable(-1);
 
 
         self.keyboardHandler = new HashHandler();
         self.keyboardHandler = new HashHandler();
         self.keyboardHandler.bindKeys({
         self.keyboardHandler.bindKeys({
           "Up": function() {
           "Up": function() {
-            if (self.selectedIndex() !== 0) {
+            if (self.selectedIndex() > 0) {
               self.selectedIndex(self.selectedIndex() - 1);
               self.selectedIndex(self.selectedIndex() - 1);
+              self.scrollSelectionIntoView();
+            } else if (self.selectedIndex() === -1) {
+              self.selectedIndex(0);
+              self.scrollSelectionIntoView();
             }
             }
-            self.scrollSelectionIntoView();
           },
           },
           "Down": function() {
           "Down": function() {
-            if (self.selectedIndex() !== self.filteredSuggestions().length - 1) {
+            if (self.selectedIndex() < self.filteredSuggestions().length - 1) {
               self.selectedIndex(self.selectedIndex() + 1);
               self.selectedIndex(self.selectedIndex() + 1);
+              self.scrollSelectionIntoView();
             }
             }
-            self.scrollSelectionIntoView();
           },
           },
           "Ctrl-Up|Ctrl-Home": function() {
           "Ctrl-Up|Ctrl-Home": function() {
             self.selectedIndex(0);
             self.selectedIndex(0);
@@ -184,32 +193,22 @@ from desktop.views import _ko
             self.selectedIndex(self.filteredSuggestions().length - 1);
             self.selectedIndex(self.filteredSuggestions().length - 1);
             self.scrollSelectionIntoView();
             self.scrollSelectionIntoView();
           },
           },
-          "Esc": function(editor) {
-            self.destroy();
-          },
-          "Return": function(editor) {
-            if (self.prefixFilter()) {
-              var ranges = editor.selection.getAllRanges();
-              for (var i = 0, range; range = ranges[i]; i++) {
-                range.start.column -= self.prefixFilter().length;
-                editor.session.remove(range);
-              }
-            }
-            editor.execCommand("insertstring", self.filteredSuggestions()[self.selectedIndex()].value);
-            editor.renderer.scrollCursorIntoView();
+          "Esc": function() {
             self.destroy();
             self.destroy();
           },
           },
-          "Shift-Return": function(editor) {
-            console.log('insert deleteSuffix');
-          },
-          "Tab": function(editor) {
-            console.log('insert or down if nothing selected');
+          "Return": function() {
+            self.insertSuggestion();
           },
           },
-          "PageUp": function(editor) {
-            console.log('page up');
+          "Shift-Return": function() {
+            // TODO: Delete suffix
+            self.insertSuggestion();
           },
           },
-          "PageDown": function(editor) {
-            console.log('page down');
+          "Tab": function() {
+            if (self.selectedIndex() === -1) {
+              self.selectedIndex(0);
+            } else {
+              self.insertSuggestion();
+            }
           }
           }
         });
         });
 
 
@@ -217,49 +216,71 @@ from desktop.views import _ko
 
 
         self.changeListener = function () {
         self.changeListener = function () {
           window.clearTimeout(changeTimeout);
           window.clearTimeout(changeTimeout);
-          var cursor = editor.selection.lead;
+          var cursor = self.editor.selection.lead;
           if (cursor.row != self.base.row || cursor.column < self.base.column) {
           if (cursor.row != self.base.row || cursor.column < self.base.column) {
             self.destroy();
             self.destroy();
           } else {
           } else {
             changeTimeout = window.setTimeout(function () {
             changeTimeout = window.setTimeout(function () {
-              self.prefixFilter(editor.session.getTextRange({ start: self.base, end: editor.getCursorPosition() }).toLowerCase())
+              self.prefixFilter(self.editor.session.getTextRange({ start: self.base, end: self.editor.getCursorPosition() }).toLowerCase())
             }, 200);
             }, 200);
           }
           }
         };
         };
 
 
-        self.blurListener = function () {
-          console.log('blur');
-          //self.destroy();
-        };
-
         self.mousedownListener = function () {
         self.mousedownListener = function () {
-          console.log('mousedown');
+          self.destroy();
         };
         };
 
 
         self.mousewheelListener = function () {
         self.mousewheelListener = function () {
-          console.log('mousewheel');
+          self.destroy();
         };
         };
 
 
-        this.destroy = function () {
+        var closeOnClickOutside = function (event) {
+          if ($.contains(document, event.target) && !$.contains(element, event.target)) {
+            self.destroy();
+          }
+        };
+
+        self.destroy = function () {
           self.base.detach();
           self.base.detach();
           window.clearTimeout(changeTimeout);
           window.clearTimeout(changeTimeout);
-          editor.keyBinding.removeKeyboardHandler(self.keyboardHandler);
-          editor.off("changeSelection", self.changeListener);
-          editor.off("blur", self.blurListener);
-          editor.off("mousedown", self.mousedownListener);
-          editor.off("mousewheel", self.mousewheelListener);
+          $(document).off('click', closeOnClickOutside);
+          self.editor.keyBinding.removeKeyboardHandler(self.keyboardHandler);
+          self.editor.off("changeSelection", self.changeListener);
+          self.editor.off("mousedown", self.mousedownListener);
+          self.editor.off("mousewheel", self.mousewheelListener);
           $(element).remove();
           $(element).remove();
         };
         };
 
 
-        editor.keyBinding.addKeyboardHandler(self.keyboardHandler);
-        editor.on("changeSelection", self.changeListener);
-        editor.on("blur", self.blurListener);
-        editor.on("mousedown", self.mousedownListener);
-        editor.on("mousewheel", self.mousewheelListener);
+        $(document).on('click', closeOnClickOutside);
+        self.editor.keyBinding.addKeyboardHandler(self.keyboardHandler);
+        self.editor.on("changeSelection", self.changeListener);
+        self.editor.on("mousedown", self.mousedownListener);
+        self.editor.on("mousewheel", self.mousewheelListener);
       }
       }
 
 
+      HueAceAutocompleter.prototype.insertSuggestion = function () {
+        var self = this;
+        if (self.selectedIndex() === -1 || self.filteredSuggestions().length === 0) {
+          self.destroy();
+          return;
+        }
+        if (self.prefixFilter()) {
+          var ranges = self.editor.selection.getAllRanges();
+          for (var i = 0, range; range = ranges[i]; i++) {
+            range.start.column -= self.prefixFilter().length;
+            self.editor.session.remove(range);
+          }
+        }
+        self.editor.execCommand("insertstring", self.filteredSuggestions()[self.selectedIndex()].value);
+        self.editor.renderer.scrollCursorIntoView();
+        self.destroy();
+      };
+
       HueAceAutocompleter.prototype.scrollSelectionIntoView = function () {
       HueAceAutocompleter.prototype.scrollSelectionIntoView = function () {
         var self = this;
         var self = this;
+        if (self.selectedIndex() === -1) {
+          return;
+        }
         var $autocompleterList = $('.autocompleter-list');
         var $autocompleterList = $('.autocompleter-list');
         var selected = $autocompleterList.children().eq(self.selectedIndex());
         var selected = $autocompleterList.children().eq(self.selectedIndex());
         var selectedTop = selected.position().top;
         var selectedTop = selected.position().top;