Преглед изворни кода

fix: graphite func editor fixes, this component is messy and ugly as hell

Torkel Ödegaard пре 8 година
родитељ
комит
e9d33750cb

+ 122 - 126
public/app/plugins/datasource/graphite/add_graphite_func.js

@@ -1,137 +1,130 @@
-define([
-  'angular',
-  'lodash',
-  'jquery',
-  'rst2html',
-  'tether-drop',
-],
-function (angular, _, $, rst2html, Drop) {
+define(['angular', 'lodash', 'jquery', 'rst2html', 'tether-drop'], function(angular, _, $, rst2html, Drop) {
   'use strict';
   'use strict';
 
 
-  angular
-    .module('grafana.directives')
-  .directive('graphiteAddFunc', function($compile) {
-      var inputTemplate = '<input type="text"'+
-                            ' class="gf-form-input"' +
-                            ' spellcheck="false" style="display:none"></input>';
-
-      var buttonTemplate = '<a class="gf-form-label query-part dropdown-toggle"' +
-                              ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
-                              '<i class="fa fa-plus"></i></a>';
-
-      return {
-        link: function($scope, elem) {
-          var ctrl = $scope.ctrl;
-
-          var $input = $(inputTemplate);
-          var $button = $(buttonTemplate);
-
-          $input.appendTo(elem);
-          $button.appendTo(elem);
-
-          ctrl.datasource.getFuncDefs().then(function(funcDefs) {
-            var allFunctions = _.map(funcDefs, 'name').sort();
-
-            $scope.functionMenu = createFunctionDropDownMenu(funcDefs);
+  angular.module('grafana.directives').directive('graphiteAddFunc', function($compile) {
+    var inputTemplate =
+      '<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
+
+    var buttonTemplate =
+      '<a class="gf-form-label query-part dropdown-toggle"' +
+      ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
+      '<i class="fa fa-plus"></i></a>';
+
+    return {
+      link: function($scope, elem) {
+        var ctrl = $scope.ctrl;
+
+        var $input = $(inputTemplate);
+        var $button = $(buttonTemplate);
+
+        $input.appendTo(elem);
+        $button.appendTo(elem);
+
+        ctrl.datasource.getFuncDefs().then(function(funcDefs) {
+          var allFunctions = _.map(funcDefs, 'name').sort();
+
+          $scope.functionMenu = createFunctionDropDownMenu(funcDefs);
+
+          $input.attr('data-provide', 'typeahead');
+          $input.typeahead({
+            source: allFunctions,
+            minLength: 1,
+            items: 10,
+            updater: function(value) {
+              var funcDef = ctrl.datasource.getFuncDef(value);
+              if (!funcDef) {
+                // try find close match
+                value = value.toLowerCase();
+                funcDef = _.find(allFunctions, function(funcName) {
+                  return funcName.toLowerCase().indexOf(value) === 0;
+                });
 
 
-            $input.attr('data-provide', 'typeahead');
-            $input.typeahead({
-              source: allFunctions,
-              minLength: 1,
-              items: 10,
-              updater: function (value) {
-                var funcDef = ctrl.datasource.getFuncDef(value);
                 if (!funcDef) {
                 if (!funcDef) {
-                  // try find close match
-                  value = value.toLowerCase();
-                  funcDef = _.find(allFunctions, function(funcName) {
-                    return funcName.toLowerCase().indexOf(value) === 0;
-                  });
-
-                  if (!funcDef) { return; }
+                  return;
                 }
                 }
+              }
 
 
-                $scope.$apply(function() {
-                  ctrl.addFunction(funcDef);
-                });
+              $scope.$apply(function() {
+                ctrl.addFunction(funcDef);
+              });
 
 
-                $input.trigger('blur');
-                return '';
-              }
-            });
-
-            $button.click(function() {
-              $button.hide();
-              $input.show();
-              $input.focus();
-            });
-
-            $input.keyup(function() {
-              elem.toggleClass('open', $input.val() === '');
-            });
-
-            $input.blur(function() {
-              // clicking the function dropdown menu wont
-              // work if you remove class at once
-              setTimeout(function() {
-                $input.val('');
-                $input.hide();
-                $button.show();
-                elem.removeClass('open');
-              }, 200);
-            });
-
-            $compile(elem.contents())($scope);
+              $input.trigger('blur');
+              return '';
+            },
           });
           });
 
 
-          var drops = [];
-
-          $(elem)
-            .on('mouseenter', 'ul.dropdown-menu li', function () {
-              while (drops.length > 0) {
-                drops.pop().remove();
-              }
+          $button.click(function() {
+            $button.hide();
+            $input.show();
+            $input.focus();
+          });
 
 
-              var funcDef;
-              try {
-                funcDef = ctrl.datasource.getFuncDef($('a', this).text());
-              } catch (e) {
-                // ignore
-              }
+          $input.keyup(function() {
+            elem.toggleClass('open', $input.val() === '');
+          });
 
 
-              if (funcDef && funcDef.description) {
-                var shortDesc = funcDef.description;
-                if (shortDesc.length > 500) {
-                  shortDesc = shortDesc.substring(0, 497) + '...';
-                }
+          $input.blur(function() {
+            // clicking the function dropdown menu wont
+            // work if you remove class at once
+            setTimeout(function() {
+              $input.val('');
+              $input.hide();
+              $button.show();
+              elem.removeClass('open');
+            }, 200);
+          });
 
 
-                var contentElement = document.createElement('div');
-                contentElement.innerHTML = '<h4>' + funcDef.name + '</h4>' + rst2html(shortDesc);
-
-                var drop = new Drop({
-                  target: this,
-                  content: contentElement,
-                  classes: 'drop-popover',
-                  openOn: 'always',
-                  tetherOptions: {
-                    attachment: 'bottom left',
-                    targetAttachment: 'bottom right',
-                  },
-                });
+          $compile(elem.contents())($scope);
+        });
+
+        var drop;
+        var cleanUpDrop = function() {
+          if (drop) {
+            drop.destroy();
+            drop = null;
+          }
+        };
+
+        $(elem)
+          .on('mouseenter', 'ul.dropdown-menu li', function() {
+            cleanUpDrop();
+
+            var funcDef;
+            try {
+              funcDef = ctrl.datasource.getFuncDef($('a', this).text());
+            } catch (e) {
+              // ignore
+            }
+
+            if (funcDef && funcDef.description) {
+              var shortDesc = funcDef.description;
+              if (shortDesc.length > 500) {
+                shortDesc = shortDesc.substring(0, 497) + '...';
+              }
 
 
-                drops.push(drop);
+              var contentElement = document.createElement('div');
+              contentElement.innerHTML = '<h4>' + funcDef.name + '</h4>' + rst2html(shortDesc);
+
+              drop = new Drop({
+                target: this,
+                content: contentElement,
+                classes: 'drop-popover',
+                openOn: 'always',
+                tetherOptions: {
+                  attachment: 'bottom left',
+                  targetAttachment: 'bottom right',
+                },
+              });
+            }
+          })
+          .on('mouseout', 'ul.dropdown-menu li', function() {
+            cleanUpDrop();
+          });
 
 
-                drop.open();
-              }
-            })
-            .on('mouseout', 'ul.dropdown-menu li', function() {
-              while (drops.length > 0) {
-                drops.pop().remove();
-              }
-            });
-        }
-      };
-    });
+        $scope.$on('$destroy', cleanUpDrop);
+      },
+    };
+  });
 
 
   function createFunctionDropDownMenu(funcDefs) {
   function createFunctionDropDownMenu(funcDefs) {
     var categories = {};
     var categories = {};
@@ -149,11 +142,14 @@ function (angular, _, $, rst2html, Drop) {
       });
       });
     });
     });
 
 
-    return _.sortBy(_.map(categories, function(submenu, category) {
-      return {
-        text: category,
-        submenu: _.sortBy(submenu, 'text')
-      };
-    }), 'text');
+    return _.sortBy(
+      _.map(categories, function(submenu, category) {
+        return {
+          text: category,
+          submenu: _.sortBy(submenu, 'text'),
+        };
+      }),
+      'text'
+    );
   }
   }
 });
 });

+ 35 - 22
public/app/plugins/datasource/graphite/func_editor.js

@@ -32,6 +32,7 @@ function (angular, _, $, rst2html) {
           var func = $scope.func;
           var func = $scope.func;
           var scheduledRelink = false;
           var scheduledRelink = false;
           var paramCountAtLink = 0;
           var paramCountAtLink = 0;
+          var cancelBlur = null;
 
 
           function clickFuncParam(paramIndex) {
           function clickFuncParam(paramIndex) {
             /*jshint validthis:true */
             /*jshint validthis:true */
@@ -79,41 +80,54 @@ function (angular, _, $, rst2html) {
             return {};
             return {};
           }
           }
 
 
-          function inputBlur(paramIndex) {
+          function switchToLink(inputElem, paramIndex) {
             /*jshint validthis:true */
             /*jshint validthis:true */
-            var $input = $(this);
-            if ($input.data('typeahead') && $input.data('typeahead').shown) {
-              return;
-            }
+            var $input = $(inputElem);
+
+            clearTimeout(cancelBlur);
+            cancelBlur = null;
 
 
             var $link = $input.prev();
             var $link = $input.prev();
             var $comma = $link.prev('.comma');
             var $comma = $link.prev('.comma');
             var newValue = $input.val();
             var newValue = $input.val();
 
 
+            // remove optional empty params
             if (newValue !== '' || paramDef(paramIndex).optional) {
             if (newValue !== '' || paramDef(paramIndex).optional) {
-              $link.html(templateSrv.highlightVariablesAsHtml(newValue));
-
               func.updateParam(newValue, paramIndex);
               func.updateParam(newValue, paramIndex);
-              scheduledRelinkIfNeeded();
+            }
 
 
-              $scope.$apply(function() {
-                ctrl.targetChanged();
-              });
+            $link.html(templateSrv.highlightVariablesAsHtml(newValue));
+            scheduledRelinkIfNeeded();
 
 
-              if ($link.hasClass('last') && newValue === '') {
-                $comma.addClass('last');
-              } else {
-                $link.removeClass('last');
-              }
-              $input.hide();
-              $link.show();
+            $scope.$apply(function() {
+              ctrl.targetChanged();
+            });
+
+            if ($link.hasClass('last') && newValue === '') {
+              $comma.addClass('last');
+            } else {
+              $link.removeClass('last');
             }
             }
+
+            $input.hide();
+            $link.show();
+          }
+
+          // this = input element
+          function inputBlur(paramIndex) {
+            /*jshint validthis:true */
+            var inputElem = this;
+            // happens long before the click event on the typeahead options
+            // need to have long delay because the blur
+            cancelBlur = setTimeout(function() {
+              switchToLink(inputElem, paramIndex);
+            }, 200);
           }
           }
 
 
           function inputKeyPress(paramIndex, e) {
           function inputKeyPress(paramIndex, e) {
             /*jshint validthis:true */
             /*jshint validthis:true */
             if(e.which === 13) {
             if(e.which === 13) {
-              inputBlur.call(this, paramIndex);
+              $(this).blur();
             }
             }
           }
           }
 
 
@@ -135,9 +149,8 @@ function (angular, _, $, rst2html) {
               minLength: 0,
               minLength: 0,
               items: 20,
               items: 20,
               updater: function (value) {
               updater: function (value) {
-                setTimeout(function() {
-                  inputBlur.call($input[0], paramIndex);
-                }, 0);
+                $input.val(value);
+                switchToLink($input[0], paramIndex);
                 return value;
                 return value;
               }
               }
             });
             });