add_graphite_func.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. define(['angular', 'lodash', 'jquery', 'rst2html', 'tether-drop'], function(angular, _, $, rst2html, Drop) {
  2. 'use strict';
  3. angular.module('grafana.directives').directive('graphiteAddFunc', function($compile) {
  4. var inputTemplate =
  5. '<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
  6. var buttonTemplate =
  7. '<a class="gf-form-label query-part dropdown-toggle"' +
  8. ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
  9. '<i class="fa fa-plus"></i></a>';
  10. return {
  11. link: function($scope, elem) {
  12. var ctrl = $scope.ctrl;
  13. var $input = $(inputTemplate);
  14. var $button = $(buttonTemplate);
  15. $input.appendTo(elem);
  16. $button.appendTo(elem);
  17. ctrl.datasource.getFuncDefs().then(function(funcDefs) {
  18. var allFunctions = _.map(funcDefs, 'name').sort();
  19. $scope.functionMenu = createFunctionDropDownMenu(funcDefs);
  20. $input.attr('data-provide', 'typeahead');
  21. $input.typeahead({
  22. source: allFunctions,
  23. minLength: 1,
  24. items: 10,
  25. updater: function(value) {
  26. var funcDef = ctrl.datasource.getFuncDef(value);
  27. if (!funcDef) {
  28. // try find close match
  29. value = value.toLowerCase();
  30. funcDef = _.find(allFunctions, function(funcName) {
  31. return funcName.toLowerCase().indexOf(value) === 0;
  32. });
  33. if (!funcDef) {
  34. return;
  35. }
  36. }
  37. $scope.$apply(function() {
  38. ctrl.addFunction(funcDef);
  39. });
  40. $input.trigger('blur');
  41. return '';
  42. },
  43. });
  44. $button.click(function() {
  45. $button.hide();
  46. $input.show();
  47. $input.focus();
  48. });
  49. $input.keyup(function() {
  50. elem.toggleClass('open', $input.val() === '');
  51. });
  52. $input.blur(function() {
  53. // clicking the function dropdown menu wont
  54. // work if you remove class at once
  55. setTimeout(function() {
  56. $input.val('');
  57. $input.hide();
  58. $button.show();
  59. elem.removeClass('open');
  60. }, 200);
  61. });
  62. $compile(elem.contents())($scope);
  63. });
  64. var drop;
  65. var cleanUpDrop = function() {
  66. if (drop) {
  67. drop.destroy();
  68. drop = null;
  69. }
  70. };
  71. $(elem)
  72. .on('mouseenter', 'ul.dropdown-menu li', function() {
  73. cleanUpDrop();
  74. var funcDef;
  75. try {
  76. funcDef = ctrl.datasource.getFuncDef($('a', this).text());
  77. } catch (e) {
  78. // ignore
  79. }
  80. if (funcDef && funcDef.description) {
  81. var shortDesc = funcDef.description;
  82. if (shortDesc.length > 500) {
  83. shortDesc = shortDesc.substring(0, 497) + '...';
  84. }
  85. var contentElement = document.createElement('div');
  86. contentElement.innerHTML = '<h4>' + funcDef.name + '</h4>' + rst2html(shortDesc);
  87. drop = new Drop({
  88. target: this,
  89. content: contentElement,
  90. classes: 'drop-popover',
  91. openOn: 'always',
  92. tetherOptions: {
  93. attachment: 'bottom left',
  94. targetAttachment: 'bottom right',
  95. },
  96. });
  97. }
  98. })
  99. .on('mouseout', 'ul.dropdown-menu li', function() {
  100. cleanUpDrop();
  101. });
  102. $scope.$on('$destroy', cleanUpDrop);
  103. },
  104. };
  105. });
  106. function createFunctionDropDownMenu(funcDefs) {
  107. var categories = {};
  108. _.forEach(funcDefs, function(funcDef) {
  109. if (!funcDef.category) {
  110. return;
  111. }
  112. if (!categories[funcDef.category]) {
  113. categories[funcDef.category] = [];
  114. }
  115. categories[funcDef.category].push({
  116. text: funcDef.name,
  117. click: "ctrl.addFunction('" + funcDef.name + "')",
  118. });
  119. });
  120. return _.sortBy(
  121. _.map(categories, function(submenu, category) {
  122. return {
  123. text: category,
  124. submenu: _.sortBy(submenu, 'text'),
  125. };
  126. }),
  127. 'text'
  128. );
  129. }
  130. });