Directives refactor.

This commit is contained in:
Alexander Zobnin
2016-03-19 14:20:55 +03:00
parent e8b4a4319c
commit e74824f840
3 changed files with 303 additions and 329 deletions

View File

@@ -15,16 +15,7 @@ module.exports = function(grunt) {
expand: true, expand: true,
src: [ src: [
'**/*', '**/*',
'!**/datasource.js', '!**/*.js',
'!**/module.js',
'!**/query.controller.js',
'!**/utils.js',
'!**/DataProcessor.js',
'!**/zabbixAPICore.service.js',
'!**/zabbixAPI.service.js',
'!**/queryProcessor.service.js',
'!**/zabbixCache.service.js',
'!**/metricFunctions.js',
'!**/*.scss' '!**/*.scss'
], ],
dest: 'dist/' dest: 'dist/'
@@ -55,16 +46,7 @@ module.exports = function(grunt) {
cwd: 'src', cwd: 'src',
expand: true, expand: true,
src: [ src: [
'**/**/module.js', '**/**/*.js'
'**/**/datasource.js',
'**/**/query.controller.js',
'**/**/utils.js',
'**/**/DataProcessor.js',
'**/**/zabbixAPICore.service.js',
'**/**/zabbixAPI.service.js',
'**/**/queryProcessor.service.js',
'**/**/zabbixCache.service.js',
'**/**/metricFunctions.js'
], ],
dest: 'dist/' dest: 'dist/'
}] }]

View File

@@ -1,107 +1,104 @@
define([ import angular from 'angular';
'angular', import _ from 'lodash';
'lodash', import $ from 'jquery';
'jquery', import * as metricFunctions from './metricFunctions';
'./metricFunctions'
],
function (angular, _, $, metricFunctions) {
'use strict';
angular /** @ngInject */
.module('grafana.directives') angular
.directive('addMetricFunction', function($compile) { .module('grafana.directives')
var inputTemplate = '<input type="text"'+ .directive('addMetricFunction', function($compile) {
' class="tight-form-input input-medium tight-form-input"' + var inputTemplate = '<input type="text"'+
' spellcheck="false" style="display:none"></input>'; ' class="tight-form-input input-medium tight-form-input"' +
' spellcheck="false" style="display:none"></input>';
var buttonTemplate = '<a class="tight-form-item tight-form-func dropdown-toggle"' + var buttonTemplate = '<a class="tight-form-item tight-form-func dropdown-toggle"' +
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' + ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
'<i class="fa fa-plus"></i></a>'; '<i class="fa fa-plus"></i></a>';
return { return {
link: function($scope, elem) { link: function($scope, elem) {
var categories = metricFunctions.getCategories(); var categories = metricFunctions.getCategories();
var allFunctions = getAllFunctionNames(categories); var allFunctions = getAllFunctionNames(categories);
$scope.functionMenu = createFunctionDropDownMenu(categories); $scope.functionMenu = createFunctionDropDownMenu(categories);
var $input = $(inputTemplate); var $input = $(inputTemplate);
var $button = $(buttonTemplate); var $button = $(buttonTemplate);
$input.appendTo(elem); $input.appendTo(elem);
$button.appendTo(elem); $button.appendTo(elem);
$input.attr('data-provide', 'typeahead'); $input.attr('data-provide', 'typeahead');
$input.typeahead({ $input.typeahead({
source: allFunctions, source: allFunctions,
minLength: 1, minLength: 1,
items: 10, items: 10,
updater: function (value) { updater: function (value) {
var funcDef = metricFunctions.getFuncDef(value); var funcDef = metricFunctions.getFuncDef(value);
if (!funcDef) { if (!funcDef) {
// try find close match // try find close match
value = value.toLowerCase(); value = value.toLowerCase();
funcDef = _.find(allFunctions, function(funcName) { funcDef = _.find(allFunctions, function(funcName) {
return funcName.toLowerCase().indexOf(value) === 0; return funcName.toLowerCase().indexOf(value) === 0;
});
if (!funcDef) { return; }
}
$scope.$apply(function() {
$scope.addFunction(funcDef);
}); });
$input.trigger('blur'); if (!funcDef) { return; }
return '';
} }
});
$button.click(function() { $scope.$apply(function() {
$button.hide(); $scope.addFunction(funcDef);
$input.show(); });
$input.focus();
});
$input.keyup(function() { $input.trigger('blur');
elem.toggleClass('open', $input.val() === ''); return '';
}); }
});
$input.blur(function() { $button.click(function() {
// clicking the function dropdown menu wont $button.hide();
// work if you remove class at once $input.show();
setTimeout(function() { $input.focus();
$input.val(''); });
$input.hide();
$button.show();
elem.removeClass('open');
}, 200);
});
$compile(elem.contents())($scope); $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);
}
};
});
function getAllFunctionNames(categories) {
return _.reduce(categories, function(list, category) {
_.each(category, function(func) {
list.push(func.name);
}); });
return list;
}, []);
}
function getAllFunctionNames(categories) { function createFunctionDropDownMenu(categories) {
return _.reduce(categories, function(list, category) { return _.map(categories, function(list, category) {
_.each(category, function(func) { return {
list.push(func.name); text: category,
}); submenu: _.map(list, function(value) {
return list; return {
}, []); text: value.name,
} click: "ctrl.addFunction('" + value.name + "')",
};
})
};
});
}
function createFunctionDropDownMenu(categories) {
return _.map(categories, function(list, category) {
return {
text: category,
submenu: _.map(list, function(value) {
return {
text: value.name,
click: "ctrl.addFunction('" + value.name + "')",
};
})
};
});
}
});

View File

@@ -1,247 +1,242 @@
define([ import angular from 'angular';
'angular', import _ from 'lodash';
'lodash', import $ from 'jquery';
'jquery',
],
function (angular, _, $) {
'use strict';
angular /** @ngInject */
.module('grafana.directives') angular
.directive('metricFunctionEditor', function($compile, templateSrv) { .module('grafana.directives')
.directive('metricFunctionEditor', function($compile, templateSrv) {
var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>'; var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
var paramTemplate = '<input type="text" style="display:none"' + var paramTemplate = '<input type="text" style="display:none"' +
' class="input-mini tight-form-func-param"></input>'; ' class="input-mini tight-form-func-param"></input>';
var funcControlsTemplate = var funcControlsTemplate =
'<div class="tight-form-func-controls">' + '<div class="tight-form-func-controls">' +
'<span class="pointer fa fa-arrow-left"></span>' + '<span class="pointer fa fa-arrow-left"></span>' +
'<span class="pointer fa fa-question-circle"></span>' + '<span class="pointer fa fa-question-circle"></span>' +
'<span class="pointer fa fa-remove" ></span>' + '<span class="pointer fa fa-remove" ></span>' +
'<span class="pointer fa fa-arrow-right"></span>' + '<span class="pointer fa fa-arrow-right"></span>' +
'</div>'; '</div>';
return { return {
restrict: 'A', restrict: 'A',
link: function postLink($scope, elem) { link: function postLink($scope, elem) {
var $funcLink = $(funcSpanTemplate); var $funcLink = $(funcSpanTemplate);
var $funcControls = $(funcControlsTemplate); var $funcControls = $(funcControlsTemplate);
var ctrl = $scope.ctrl; var ctrl = $scope.ctrl;
var func = $scope.func; var func = $scope.func;
var funcDef = func.def; var funcDef = func.def;
var scheduledRelink = false; var scheduledRelink = false;
var paramCountAtLink = 0; var paramCountAtLink = 0;
function clickFuncParam(paramIndex) { function clickFuncParam(paramIndex) {
/*jshint validthis:true */ /*jshint validthis:true */
var $link = $(this); var $link = $(this);
var $input = $link.next(); var $input = $link.next();
$input.val(func.params[paramIndex]); $input.val(func.params[paramIndex]);
$input.css('width', ($link.width() + 16) + 'px'); $input.css('width', ($link.width() + 16) + 'px');
$link.hide(); $link.hide();
$input.show(); $input.show();
$input.focus(); $input.focus();
$input.select(); $input.select();
var typeahead = $input.data('typeahead'); var typeahead = $input.data('typeahead');
if (typeahead) { if (typeahead) {
$input.val(''); $input.val('');
typeahead.lookup(); typeahead.lookup();
} }
}
function scheduledRelinkIfNeeded() {
if (paramCountAtLink === func.params.length) {
return;
} }
function scheduledRelinkIfNeeded() { if (!scheduledRelink) {
if (paramCountAtLink === func.params.length) { scheduledRelink = true;
setTimeout(function() {
relink();
scheduledRelink = false;
}, 200);
}
}
function inputBlur(paramIndex) {
/*jshint validthis:true */
var $input = $(this);
var $link = $input.prev();
var newValue = $input.val();
if (newValue !== '' || func.def.params[paramIndex].optional) {
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
func.updateParam($input.val(), paramIndex);
scheduledRelinkIfNeeded();
$scope.$apply(function() {
ctrl.targetChanged();
});
$input.hide();
$link.show();
}
}
function inputKeyPress(paramIndex, e) {
/*jshint validthis:true */
if(e.which === 13) {
inputBlur.call(this, paramIndex);
}
}
function inputKeyDown() {
/*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px';
}
function addTypeahead($input, paramIndex) {
$input.attr('data-provide', 'typeahead');
var options = funcDef.params[paramIndex].options;
if (funcDef.params[paramIndex].type === 'int') {
options = _.map(options, function(val) { return val.toString(); });
}
$input.typeahead({
source: options,
minLength: 0,
items: 20,
updater: function (value) {
setTimeout(function() {
inputBlur.call($input[0], paramIndex);
}, 0);
return value;
}
});
var typeahead = $input.data('typeahead');
typeahead.lookup = function () {
this.query = this.$element.val() || '';
return this.process(this.source);
};
}
function toggleFuncControls() {
var targetDiv = elem.closest('.tight-form');
if (elem.hasClass('show-function-controls')) {
elem.removeClass('show-function-controls');
targetDiv.removeClass('has-open-function');
$funcControls.hide();
return;
}
elem.addClass('show-function-controls');
targetDiv.addClass('has-open-function');
$funcControls.show();
}
function addElementsAndCompile() {
$funcControls.appendTo(elem);
$funcLink.appendTo(elem);
_.each(funcDef.params, function(param, index) {
if (param.optional && func.params.length <= index) {
return; return;
} }
if (!scheduledRelink) { if (index > 0) {
scheduledRelink = true; $('<span>, </span>').appendTo(elem);
setTimeout(function() {
relink();
scheduledRelink = false;
}, 200);
} }
var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + paramValue + '</a>');
var $input = $(paramTemplate);
paramCountAtLink++;
$paramLink.appendTo(elem);
$input.appendTo(elem);
$input.blur(_.partial(inputBlur, index));
$input.keyup(inputKeyDown);
$input.keypress(_.partial(inputKeyPress, index));
$paramLink.click(_.partial(clickFuncParam, index));
if (funcDef.params[index].options) {
addTypeahead($input, index);
}
});
$('<span>)</span>').appendTo(elem);
$compile(elem.contents())($scope);
}
function ifJustAddedFocusFistParam() {
if ($scope.func.added) {
$scope.func.added = false;
setTimeout(function() {
elem.find('.graphite-func-param-link').first().click();
}, 10);
} }
}
function inputBlur(paramIndex) { function registerFuncControlsToggle() {
/*jshint validthis:true */ $funcLink.click(toggleFuncControls);
var $input = $(this); }
var $link = $input.prev();
var newValue = $input.val();
if (newValue !== '' || func.def.params[paramIndex].optional) {
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
func.updateParam($input.val(), paramIndex);
scheduledRelinkIfNeeded();
function registerFuncControlsActions() {
$funcControls.click(function(e) {
var $target = $(e.target);
if ($target.hasClass('fa-remove')) {
toggleFuncControls();
$scope.$apply(function() { $scope.$apply(function() {
ctrl.removeFunction($scope.func);
});
return;
}
if ($target.hasClass('fa-arrow-left')) {
$scope.$apply(function() {
_.move($scope.target.functions, $scope.$index, $scope.$index - 1);
ctrl.targetChanged(); ctrl.targetChanged();
}); });
$input.hide();
$link.show();
}
}
function inputKeyPress(paramIndex, e) {
/*jshint validthis:true */
if(e.which === 13) {
inputBlur.call(this, paramIndex);
}
}
function inputKeyDown() {
/*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px';
}
function addTypeahead($input, paramIndex) {
$input.attr('data-provide', 'typeahead');
var options = funcDef.params[paramIndex].options;
if (funcDef.params[paramIndex].type === 'int') {
options = _.map(options, function(val) { return val.toString(); });
}
$input.typeahead({
source: options,
minLength: 0,
items: 20,
updater: function (value) {
setTimeout(function() {
inputBlur.call($input[0], paramIndex);
}, 0);
return value;
}
});
var typeahead = $input.data('typeahead');
typeahead.lookup = function () {
this.query = this.$element.val() || '';
return this.process(this.source);
};
}
function toggleFuncControls() {
var targetDiv = elem.closest('.tight-form');
if (elem.hasClass('show-function-controls')) {
elem.removeClass('show-function-controls');
targetDiv.removeClass('has-open-function');
$funcControls.hide();
return; return;
} }
elem.addClass('show-function-controls'); if ($target.hasClass('fa-arrow-right')) {
targetDiv.addClass('has-open-function'); $scope.$apply(function() {
_.move($scope.target.functions, $scope.$index, $scope.$index + 1);
$funcControls.show(); ctrl.targetChanged();
} });
return;
function addElementsAndCompile() {
$funcControls.appendTo(elem);
$funcLink.appendTo(elem);
_.each(funcDef.params, function(param, index) {
if (param.optional && func.params.length <= index) {
return;
}
if (index > 0) {
$('<span>, </span>').appendTo(elem);
}
var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + paramValue + '</a>');
var $input = $(paramTemplate);
paramCountAtLink++;
$paramLink.appendTo(elem);
$input.appendTo(elem);
$input.blur(_.partial(inputBlur, index));
$input.keyup(inputKeyDown);
$input.keypress(_.partial(inputKeyPress, index));
$paramLink.click(_.partial(clickFuncParam, index));
if (funcDef.params[index].options) {
addTypeahead($input, index);
}
});
$('<span>)</span>').appendTo(elem);
$compile(elem.contents())($scope);
}
function ifJustAddedFocusFistParam() {
if ($scope.func.added) {
$scope.func.added = false;
setTimeout(function() {
elem.find('.graphite-func-param-link').first().click();
}, 10);
} }
}
function registerFuncControlsToggle() { if ($target.hasClass('fa-question-circle')) {
$funcLink.click(toggleFuncControls); window.open("http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions." + funcDef.name,'_blank');
} return;
}
function registerFuncControlsActions() { });
$funcControls.click(function(e) {
var $target = $(e.target);
if ($target.hasClass('fa-remove')) {
toggleFuncControls();
$scope.$apply(function() {
ctrl.removeFunction($scope.func);
});
return;
}
if ($target.hasClass('fa-arrow-left')) {
$scope.$apply(function() {
_.move($scope.target.functions, $scope.$index, $scope.$index - 1);
ctrl.targetChanged();
});
return;
}
if ($target.hasClass('fa-arrow-right')) {
$scope.$apply(function() {
_.move($scope.target.functions, $scope.$index, $scope.$index + 1);
ctrl.targetChanged();
});
return;
}
if ($target.hasClass('fa-question-circle')) {
window.open("http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions." + funcDef.name,'_blank');
return;
}
});
}
function relink() {
elem.children().remove();
addElementsAndCompile();
ifJustAddedFocusFistParam();
registerFuncControlsToggle();
registerFuncControlsActions();
}
relink();
} }
};
}); function relink() {
elem.children().remove();
}); addElementsAndCompile();
ifJustAddedFocusFistParam();
registerFuncControlsToggle();
registerFuncControlsActions();
}
relink();
}
};
});