query_part_editor.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. define([
  2. 'angular',
  3. 'lodash',
  4. 'jquery',
  5. ],
  6. function (angular, _, $) {
  7. 'use strict';
  8. angular
  9. .module('grafana.directives')
  10. .directive('influxQueryPartEditor', function($compile, templateSrv) {
  11. var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
  12. var paramTemplate = '<input type="text" style="display:none"' +
  13. ' class="input-mini tight-form-func-param"></input>';
  14. var funcControlsTemplate =
  15. '<div class="tight-form-func-controls">' +
  16. '<span class="pointer fa fa-question-circle"></span>' +
  17. '<span class="pointer fa fa-remove" ></span>' +
  18. '</div>';
  19. return {
  20. restrict: 'A',
  21. link: function postLink($scope, elem) {
  22. var $funcLink = $(funcSpanTemplate);
  23. var $funcControls = $(funcControlsTemplate);
  24. var func = $scope.func;
  25. var funcDef = func.def;
  26. var scheduledRelink = false;
  27. var paramCountAtLink = 0;
  28. function clickFuncParam(paramIndex) {
  29. /*jshint validthis:true */
  30. var $link = $(this);
  31. var $input = $link.next();
  32. $input.val(func.params[paramIndex]);
  33. $input.css('width', ($link.width() + 16) + 'px');
  34. $link.hide();
  35. $input.show();
  36. $input.focus();
  37. $input.select();
  38. var typeahead = $input.data('typeahead');
  39. if (typeahead) {
  40. $input.val('');
  41. typeahead.lookup();
  42. }
  43. }
  44. function scheduledRelinkIfNeeded() {
  45. if (paramCountAtLink === func.params.length) {
  46. return;
  47. }
  48. if (!scheduledRelink) {
  49. scheduledRelink = true;
  50. setTimeout(function() {
  51. relink();
  52. scheduledRelink = false;
  53. }, 200);
  54. }
  55. }
  56. function inputBlur(paramIndex) {
  57. /*jshint validthis:true */
  58. var $input = $(this);
  59. var $link = $input.prev();
  60. var newValue = $input.val();
  61. if (newValue !== '' || func.def.params[paramIndex].optional) {
  62. $link.html(templateSrv.highlightVariablesAsHtml(newValue));
  63. func.updateParam($input.val(), paramIndex);
  64. scheduledRelinkIfNeeded();
  65. $scope.$apply($scope.targetChanged);
  66. }
  67. $input.hide();
  68. $link.show();
  69. }
  70. function inputKeyPress(paramIndex, e) {
  71. /*jshint validthis:true */
  72. if(e.which === 13) {
  73. inputBlur.call(this, paramIndex);
  74. }
  75. }
  76. function inputKeyDown() {
  77. /*jshint validthis:true */
  78. this.style.width = (3 + this.value.length) * 8 + 'px';
  79. }
  80. function addTypeahead($input, paramIndex) {
  81. $input.attr('data-provide', 'typeahead');
  82. var options = funcDef.params[paramIndex].options;
  83. if (funcDef.params[paramIndex].type === 'int') {
  84. options = _.map(options, function(val) { return val.toString(); });
  85. }
  86. $input.typeahead({
  87. source: options,
  88. minLength: 0,
  89. items: 20,
  90. updater: function (value) {
  91. setTimeout(function() {
  92. inputBlur.call($input[0], paramIndex);
  93. }, 0);
  94. return value;
  95. }
  96. });
  97. var typeahead = $input.data('typeahead');
  98. typeahead.lookup = function () {
  99. this.query = this.$element.val() || '';
  100. return this.process(this.source);
  101. };
  102. }
  103. function toggleFuncControls() {
  104. var targetDiv = elem.closest('.tight-form');
  105. if (elem.hasClass('show-function-controls')) {
  106. elem.removeClass('show-function-controls');
  107. targetDiv.removeClass('has-open-function');
  108. $funcControls.hide();
  109. return;
  110. }
  111. elem.addClass('show-function-controls');
  112. targetDiv.addClass('has-open-function');
  113. $funcControls.show();
  114. }
  115. function addElementsAndCompile() {
  116. $funcControls.appendTo(elem);
  117. $funcLink.appendTo(elem);
  118. _.each(funcDef.params, function(param, index) {
  119. if (param.optional && func.params.length <= index) {
  120. return;
  121. }
  122. if (index > 0) {
  123. $('<span>, </span>').appendTo(elem);
  124. }
  125. var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
  126. var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + paramValue + '</a>');
  127. var $input = $(paramTemplate);
  128. paramCountAtLink++;
  129. $paramLink.appendTo(elem);
  130. $input.appendTo(elem);
  131. $input.blur(_.partial(inputBlur, index));
  132. $input.keyup(inputKeyDown);
  133. $input.keypress(_.partial(inputKeyPress, index));
  134. $paramLink.click(_.partial(clickFuncParam, index));
  135. if (funcDef.params[index].options) {
  136. addTypeahead($input, index);
  137. }
  138. });
  139. $('<span>)</span>').appendTo(elem);
  140. $compile(elem.contents())($scope);
  141. }
  142. function ifJustAddedFocusFistParam() {
  143. if ($scope.func.added) {
  144. $scope.func.added = false;
  145. setTimeout(function() {
  146. elem.find('.graphite-func-param-link').first().click();
  147. }, 10);
  148. }
  149. }
  150. function registerFuncControlsToggle() {
  151. $funcLink.click(toggleFuncControls);
  152. }
  153. function registerFuncControlsActions() {
  154. $funcControls.click(function(e) {
  155. var $target = $(e.target);
  156. if ($target.hasClass('fa-remove')) {
  157. toggleFuncControls();
  158. $scope.$apply(function() {
  159. $scope.removeFunction($scope.func);
  160. });
  161. return;
  162. }
  163. if ($target.hasClass('fa-arrow-left')) {
  164. $scope.$apply(function() {
  165. _.move($scope.functions, $scope.$index, $scope.$index - 1);
  166. $scope.targetChanged();
  167. });
  168. return;
  169. }
  170. if ($target.hasClass('fa-arrow-right')) {
  171. $scope.$apply(function() {
  172. _.move($scope.functions, $scope.$index, $scope.$index + 1);
  173. $scope.targetChanged();
  174. });
  175. return;
  176. }
  177. if ($target.hasClass('fa-question-circle')) {
  178. window.open("http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions." + funcDef.name,'_blank');
  179. return;
  180. }
  181. });
  182. }
  183. function relink() {
  184. elem.children().remove();
  185. addElementsAndCompile();
  186. ifJustAddedFocusFistParam();
  187. registerFuncControlsToggle();
  188. registerFuncControlsActions();
  189. }
  190. relink();
  191. }
  192. };
  193. });
  194. });