UNPKG

@spalger/kibana

Version:

Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elastic

186 lines (149 loc) 5 kB
define(function (require) { var $ = require('jquery'); var _ = require('lodash'); var keyMap = require('ui/utils/key_map'); var INVALID = {}; // invalid flag var FLOATABLE = /^[\d\.e\-\+]+$/i; var VALIDATION_ERROR = 'numberListRangeAndOrder'; var DIRECTIVE_ATTR = 'kbn-number-list-input'; require('ui/modules') .get('kibana') .directive('kbnNumberListInput', function ($parse) { return { restrict: 'A', require: ['ngModel', '^kbnNumberList'], link: function ($scope, $el, attrs, controllers) { var ngModelCntr = controllers[0]; var numberListCntr = controllers[1]; var $setModel = $parse(attrs.ngModel).assign; var $repeater = $el.closest('[ng-repeat]'); var handlers = { up: change(add, 1), 'shift-up': change(addTenth, 1), down: change(add, -1), 'shift-down': change(addTenth, -1), tab: go('next'), 'shift-tab': go('prev'), 'shift-enter': numberListCntr.add, backspace: removeIfEmpty, delete: removeIfEmpty }; function removeIfEmpty(event) { if (!ngModelCntr.$viewValue) { $get('prev').focus(); numberListCntr.remove($scope.$index); event.preventDefault(); } return false; } function $get(dir) { return $repeater[dir]().find('[' + DIRECTIVE_ATTR + ']'); } function go(dir) { return function () { var $to = $get(dir); if ($to.size()) $to.focus(); else return false; }; } function idKey(event) { var id = []; if (event.ctrlKey) id.push('ctrl'); if (event.shiftKey) id.push('shift'); if (event.metaKey) id.push('meta'); if (event.altKey) id.push('alt'); id.push(keyMap[event.keyCode] || event.keyCode); return id.join('-'); } function add(n, val) { return parse(val + n); } function addTenth(n, val, str) { var int = Math.floor(val); var dec = parseInt(str.split('.')[1] || 0, 10); dec = dec + parseInt(n, 10); if (dec < 0 || dec > 9) { int += Math.floor(dec / 10); if (dec < 0) { dec = 10 + (dec % 10); } else { dec = dec % 10; } } return parse(int + '.' + dec); } function change(using, mod) { return function () { var str = String(ngModelCntr.$viewValue); var val = parse(str); if (val === INVALID) return; var next = using(mod, val, str); if (next === INVALID) return; $el.val(next); ngModelCntr.$setViewValue(next); }; } function onKeydown(event) { var handler = handlers[idKey(event)]; if (!handler) return; if (handler(event) !== false) { event.preventDefault(); } $scope.$apply(); } $el.on('keydown', onKeydown); $scope.$on('$destroy', function () { $el.off('keydown', onKeydown); }); function parse(viewValue) { var num = viewValue; if (typeof num !== 'number' || isNaN(num)) { // parse non-numbers num = String(viewValue || 0).trim(); if (!FLOATABLE.test(num)) return INVALID; num = parseFloat(num); if (isNaN(num)) return INVALID; } var range = numberListCntr.range; if (!range.within(num)) return INVALID; if ($scope.$index > 0) { var i = $scope.$index - 1; var list = numberListCntr.getList(); var prev = list[i]; if (num <= prev) return INVALID; } return num; } $scope.$watchMulti([ '$index', { fn: $scope.$watchCollection, get: function () { return numberListCntr.getList(); } } ], function () { var valid = parse(ngModelCntr.$viewValue) !== INVALID; ngModelCntr.$setValidity(VALIDATION_ERROR, valid); }); function validate(then) { return function (input) { var value = parse(input); var valid = value !== INVALID; value = valid ? value : input; ngModelCntr.$setValidity(VALIDATION_ERROR, valid); then && then(input, value); return value; }; } ngModelCntr.$parsers.push(validate()); ngModelCntr.$formatters.push(validate(function (input, value) { if (input !== value) $setModel($scope, value); })); if (parse(ngModelCntr.$viewValue) === INVALID) { ngModelCntr.$setTouched(); } } }; }); });