added func controls

This commit is contained in:
Torkel Ödegaard 2014-03-07 13:14:41 +01:00
parent e3e6f511e7
commit feb20243e5
6 changed files with 291 additions and 188 deletions

View File

@ -10,7 +10,7 @@ function (angular, _, config, gfunc, Parser) {
var module = angular.module('kibana.controllers');
module.controller('GraphiteTargetCtrl', function($scope, $http, filterSrv, $timeout) {
module.controller('GraphiteTargetCtrl', function($scope, $http, filterSrv) {
$scope.init = function() {
parseTarget();

View File

@ -14,120 +14,201 @@ function (angular, _, $) {
var paramTemplate = '<input type="text" style="display:none"' +
' class="input-mini grafana-function-param-input"></input>';
var clickFuncParam = function(func, paramIndex) {
var $link = $(this);
var $input = $link.next();
$input.val(func.params[paramIndex]);
$input.css('width', ($link.width() + 16) + 'px');
$link.hide();
$input.show();
$input.focus();
$input.select();
var typeahead = $input.data('typeahead');
if (typeahead) {
$input.val('');
typeahead.lookup();
}
};
var inputBlur = function(scope, func, paramIndex) {
var $input = $(this);
var $link = $input.prev();
if ($input.val() !== '') {
$link.text($input.val());
if (func.updateParam($input.val(), paramIndex)) {
scope.$apply(function() {
scope.targetChanged();
});
}
}
$input.hide();
$link.show();
};
var inputKeyPress = function(scope, func, paramIndex, e) {
if(e.which === 13) {
inputBlur.call(this, scope, func, paramIndex);
}
};
var inputKeyDown = function() {
this.style.width = (3 + this.value.length) * 8 + 'px';
};
var addTypeahead = function($input, scope, func, paramIndex) {
$input.attr('data-provide', 'typeahead');
var options = func.def.params[paramIndex].options;
if (func.def.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], scope, func, paramIndex);
}, 0);
return value;
}
});
var typeahead = $input.data('typeahead');
typeahead.lookup = function () {
this.query = this.$element.val() || '';
return this.process(this.source);
};
};
var funcControlsTemplate =
'<span class="graphite-func-controls">' +
'<span class="pointer icon-arrow-left"></span>' +
'<span class="pointer icon-info-sign"></span>' +
'<span class="pointer icon-remove" ></span>' +
'<span class="pointer icon-arrow-right"></span>' +
'</span>';
return {
restrict: 'A',
link: function postLink($scope, elem) {
var $funcLink = $(funcSpanTemplate);
var $funcControls = $(funcControlsTemplate);
var func = $scope.func;
var funcDef = func.def;
$funcLink.appendTo(elem);
function clickFuncParam(paramIndex) {
/*jshint validthis:true */
_.each($scope.func.def.params, function(param, index) {
var $paramLink = $('<a ng-click="">' + $scope.func.params[index] + '</a>');
var $input = $(paramTemplate);
var $link = $(this);
var $input = $link.next();
$paramLink.appendTo(elem);
$input.appendTo(elem);
$input.val(func.params[paramIndex]);
$input.css('width', ($link.width() + 16) + 'px');
$input.blur(_.partial(inputBlur, $scope, $scope.func, index));
$input.keyup(inputKeyDown);
$input.keypress(_.partial(inputKeyPress, $scope, $scope.func, index));
$paramLink.click(_.partial(clickFuncParam, $scope.func, index));
$link.hide();
$input.show();
$input.focus();
$input.select();
if (index !== $scope.func.def.params.length - 1) {
$('<span>, </span>').appendTo(elem);
var typeahead = $input.data('typeahead');
if (typeahead) {
$input.val('');
typeahead.lookup();
}
}
function inputBlur(paramIndex) {
/*jshint validthis:true */
var $input = $(this);
var $link = $input.prev();
if ($input.val() !== '') {
$link.text($input.val());
if (func.updateParam($input.val(), paramIndex)) {
$scope.$apply(function() {
$scope.targetChanged();
});
}
}
if ($scope.func.def.params[index].options) {
addTypeahead($input, $scope, $scope.func, index);
$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;
}
});
$('<span>)</span>').appendTo(elem);
var typeahead = $input.data('typeahead');
typeahead.lookup = function () {
this.query = this.$element.val() || '';
return this.process(this.source);
};
}
$compile(elem.contents())($scope);
function getPosition() {
var el = elem[0];
var pos = {};
if (typeof el.getBoundingClientRect === 'function') {
pos = el.getBoundingClientRect();
}
else {
pos = { width: el.offsetWidth, height: el.offsetHeight };
}
return $.extend(pos, elem.offset());
}
function toggleFuncControls() {
var targetDiv = elem.closest('.grafana-target-inner');
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');
if ($scope.func.added) {
$scope.func.added = false;
setTimeout(function() {
elem.find('a').click();
var pos = getPosition();
$funcControls.css('position', 'absolute');
$funcControls.css('top', (pos.top - 78) + 'px');
$funcControls.css('left', pos.left + 'px');
$funcControls.css('width', pos.width + 'px');
console.log(pos);
$funcControls.show();
}, 10);
}
function addElementsAndCompile() {
$funcLink.appendTo(elem);
_.each(funcDef.params, function(param, index) {
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + func.params[index] + '</a>');
var $input = $(paramTemplate);
$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 (index !== funcDef.params.length - 1) {
$('<span>, </span>').appendTo(elem);
}
if (funcDef.params[index].options) {
addTypeahead($input, index);
}
});
$('<span>)</span>').appendTo(elem);
elem.append($funcControls);
$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() {
$funcLink.click(toggleFuncControls);
}
function registerFuncControlsActions() {
$funcControls.click(function(e) {
var $target = $(e.target);
if ($target.hasClass('icon-remove')) {
toggleFuncControls();
$scope.$apply(function() {
$scope.removeFunction($scope.func);
});
}
});
}
addElementsAndCompile();
ifJustAddedFocusFistParam();
registerFuncControlsToggle();
registerFuncControlsActions();
}
};

View File

@ -7,99 +7,97 @@
ng-controller="GraphiteTargetCtrl"
ng-init="init()">
<div class="grafana-target-inner-wrapper">
<div class="grafana-target-inner">
<ul class="grafana-target-controls">
<li ng-show="parserError">
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
<i class="icon-warning-sign"></i>
</a>
</li>
<li>
<a class="pointer" tabindex="1" ng-click="showTextEditor = !showTextEditor">
<i class="icon-pencil"></i>
</a>
</li>
<li class="dropdown">
<a class="pointer dropdown-toggle"
data-toggle="dropdown"
tabindex="1">
<i class="icon-cog"></i>
</a>
<ul class="dropdown-menu pull-right" role="menu">
<li role="menuitem">
<a tabindex="1"
ng-click="duplicate()">
Duplicate
</a>
</li>
</ul>
</li>
<li>
<a class="pointer" tabindex="1" ng-click="removeTarget(target)">
<i class="icon-remove"></i>
</a>
</li>
</ul>
<div class="grafana-target-inner">
<ul class="grafana-target-controls">
<li ng-show="parserError">
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
<i class="icon-warning-sign"></i>
</a>
</li>
<li>
<a class="pointer" tabindex="1" ng-click="showTextEditor = !showTextEditor">
<i class="icon-pencil"></i>
</a>
</li>
<li class="dropdown">
<a class="pointer dropdown-toggle"
data-toggle="dropdown"
tabindex="1">
<i class="icon-cog"></i>
</a>
<ul class="dropdown-menu pull-right" role="menu">
<li role="menuitem">
<a tabindex="1"
ng-click="duplicate()">
Duplicate
</a>
</li>
</ul>
</li>
<li>
<a class="pointer" tabindex="1" ng-click="removeTarget(target)">
<i class="icon-remove"></i>
</a>
</li>
</ul>
<ul class="grafana-target-controls-left">
<li>
<a class="grafana-target-segment"
ng-click="target.hide = !target.hide; get_data();"
role="menuitem">
<i class="icon-eye-open"></i>
</a>
</li>
</ul>
<ul class="grafana-target-controls-left">
<li>
<a class="grafana-target-segment"
ng-click="target.hide = !target.hide; get_data();"
role="menuitem">
<i class="icon-eye-open"></i>
</a>
</li>
</ul>
<input type="text"
class="grafana-target-text-input span10"
ng-model="target.target"
focus-me="showTextEditor"
spellcheck='false'
ng-model-onblur ng-change="targetTextChanged()"
ng-show="showTextEditor" />
<input type="text"
class="grafana-target-text-input span10"
ng-model="target.target"
focus-me="showTextEditor"
spellcheck='false'
ng-model-onblur ng-change="targetTextChanged()"
ng-show="showTextEditor" />
<ul class="grafana-segment-list" role="menu" ng-hide="showTextEditor">
<li class="dropdown" ng-repeat="segment in segments" role="menuitem">
<a tabindex="1"
class="grafana-target-segment dropdown-toggle"
data-toggle="dropdown"
ng-click="getAltSegments($index)"
focus-me="segment.focus"
ng-bind-html-unsafe="segment.html">
</a>
<ul class="dropdown-menu scrollable grafana-segment-dropdown-menu" role="menu">
<li ng-repeat="altSegment in altSegments" role="menuitem">
<a href="javascript:void(0)" tabindex="1" ng-click="setSegment($index, $parent.$index)" ng-bind-html-unsafe="altSegment.html"></a>
</li>
</ul>
</li>
<li ng-repeat="func in functions">
<span graphite-func-editor class="grafana-target-segment grafana-target-function">
</span>
<!-- <a class="grafana-target-segment grafana-target-function dropdown-toggle"
bs-popover="'app/partials/graphite/funcEditor.html'"
data-placement="bottom">
{{func.def.name}}
</a> -->
<!-- <span class="grafana-target-segment grafana-target-function">
<span>{{func.def.name}}(</span><span ng-repeat="param in func.def.params">
<input type="text"
class="input-mini grafana-function-param-input"
dynamic-width
ng-model="func.params[$index]"></input>
</span><span>)</span>
</span> -->
</li>
<li class="dropdown" graphite-add-func>
<ul class="grafana-segment-list" role="menu" ng-hide="showTextEditor">
<li class="dropdown" ng-repeat="segment in segments" role="menuitem">
<a tabindex="1"
class="grafana-target-segment dropdown-toggle"
data-toggle="dropdown"
ng-click="getAltSegments($index)"
focus-me="segment.focus"
ng-bind-html-unsafe="segment.html">
</a>
<ul class="dropdown-menu scrollable grafana-segment-dropdown-menu" role="menu">
<li ng-repeat="altSegment in altSegments" role="menuitem">
<a href="javascript:void(0)" tabindex="1" ng-click="setSegment($index, $parent.$index)" ng-bind-html-unsafe="altSegment.html"></a>
</li>
</ul>
</li>
<li ng-repeat="func in functions">
<span graphite-func-editor class="grafana-target-segment grafana-target-function">
</span>
<!-- <a class="grafana-target-segment grafana-target-function dropdown-toggle"
bs-popover="'app/partials/graphite/funcEditor.html'"
data-placement="bottom">
{{func.def.name}}
</a> -->
<!-- <span class="grafana-target-segment grafana-target-function">
<span>{{func.def.name}}(</span><span ng-repeat="param in func.def.params">
<input type="text"
class="input-mini grafana-function-param-input"
dynamic-width
ng-model="func.params[$index]"></input>
</span><span>)</span>
</span> -->
</li>
<li class="dropdown" graphite-add-func>
</li>
</ul>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="clearfix"></div>
</div>
</div>
</div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -221,16 +221,16 @@
border-bottom: 1px solid @grafanaTargetBorder;
}
.grafana-target-inner-wrapper {
width: 100%;
}
.grafana-target-inner {
border-top: 1px solid @grafanaTargetBorder;
border-left: 1px solid @grafanaTargetBorder;
border-right: 1px solid @grafanaTargetBorder;
background: @grafanaTargetBackground;
width: 100%;
&.has-open-function {
margin-top: 35px;
}
}
.grafana-target-onoff {
@ -282,6 +282,11 @@
> a:hover {
color: @linkColor;
}
&.show-function-controls {
min-width: 100px;
text-align: center;
}
}
input[type=text].grafana-function-param-input {
@ -358,6 +363,25 @@ select.grafana-target-segment-input {
padding: 0; margin: 0;
}
.graphite-func-controls {
display: none;
text-align: center;
.icon-arrow-left {
float: left;
position: relative;
top: 2px;
}
.icon-arrow-right {
float: right;
position: relative;
top: 2px;
}
.icon-remove {
margin-left: 10px;
}
}
input[type=text].func-param {
border: none;
background: inherit;