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

242 lines (197 loc) 6.86 kB
define(function (require) { var _ = require('lodash'); var typeahead = require('ui/modules').get('kibana/typeahead'); require('ui/typeahead/typeahead.less'); require('ui/typeahead/_input'); require('ui/typeahead/_items'); typeahead.directive('kbnTypeahead', function () { var keyMap = { ESC: 27, UP: 38, DOWN: 40, TAB: 9, ENTER: 13 }; return { restrict: 'A', scope: { historyKey: '@kbnTypeahead' }, controllerAs: 'typeahead', controller: function ($scope, $element, $timeout, PersistedLog, config) { var self = this; self.form = $element.closest('form'); self.query = ''; self.hidden = true; self.focused = false; self.mousedOver = false; // instantiate history and add items to the scope self.history = new PersistedLog('typeahead:' + $scope.historyKey, { maxLength: config.get('history:limit'), filterDuplicates: true }); $scope.items = self.history.get(); $scope.filteredItems = []; self.setInputModel = function (model) { $scope.inputModel = model; // watch for changes to the query parameter, delegate to typeaheadCtrl $scope.$watch('inputModel.$viewValue', self.filterItemsByQuery); }; self.setHidden = function (hidden) { self.hidden = !!(hidden); }; self.setFocused = function (focused) { self.focused = !!(focused); }; self.setMouseover = function (mousedOver) { self.mousedOver = !!(mousedOver); }; // activation methods self.activateItem = function (item) { self.active = item; }; self.getActiveIndex = function () { if (!self.active) { return; } return $scope.filteredItems.indexOf(self.active); }; self.getItems = function () { return $scope.filteredItems; }; self.activateNext = function () { var index = self.getActiveIndex(); if (index == null) { index = 0; } else if (index < $scope.filteredItems.length - 1) { ++index; } self.activateItem($scope.filteredItems[index]); }; self.activatePrev = function () { var index = self.getActiveIndex(); if (index > 0 && index != null) { --index; } else if (index === 0) { self.active = false; return; } self.activateItem($scope.filteredItems[index]); }; self.isActive = function (item) { return item === self.active; }; // selection methods self.selectItem = function (item, ev) { self.hidden = true; self.active = false; $scope.inputModel.$setViewValue(item); $scope.inputModel.$render(); self.persistEntry(); if (ev && ev.type === 'click') { $timeout(function () { self.submitForm(); }); } }; self.submitForm = function () { if (self.form.length) { self.form.submit(); } }; self.persistEntry = function () { if ($scope.inputModel.$viewValue.length) { // push selection into the history $scope.items = self.history.add($scope.inputModel.$viewValue); } }; self.selectActive = function () { if (self.active) { self.selectItem(self.active); } }; self.keypressHandler = function (ev) { var keyCode = ev.which || ev.keyCode; if (self.focused) { self.hidden = false; } // hide on escape if (_.contains([keyMap.ESC], keyCode)) { self.hidden = true; self.active = false; } // change selection with arrow up/down // on down key, attempt to load all items if none are loaded if (_.contains([keyMap.DOWN], keyCode) && $scope.filteredItems.length === 0) { $scope.filteredItems = $scope.items; $scope.$digest(); } else if (_.contains([keyMap.UP, keyMap.DOWN], keyCode)) { if (self.isVisible() && $scope.filteredItems.length) { ev.preventDefault(); if (keyCode === keyMap.DOWN) { self.activateNext(); } else { self.activatePrev(); } } } // persist selection on enter, when not selecting from the list if (_.contains([keyMap.ENTER], keyCode)) { if (!self.active) { self.persistEntry(); } } // select on enter or tab if (_.contains([keyMap.ENTER, keyMap.TAB], keyCode)) { self.selectActive(); self.hidden = true; } }; self.filterItemsByQuery = function (query) { // cache query so we can call it again if needed if (query) { self.query = query; } // if the query is empty, clear the list items if (!self.query.length) { $scope.filteredItems = []; return; } // update the filteredItems using the query var beginningMatches = $scope.items.filter(function (item) { return item.indexOf(query) === 0; }); var otherMatches = $scope.items.filter(function (item) { return item.indexOf(query) > 0; }); $scope.filteredItems = beginningMatches.concat(otherMatches); }; self.isVisible = function () { return !self.hidden && ($scope.filteredItems.length > 0) && (self.focused || self.mousedOver); }; // handle updates to parent scope history $scope.$watch('items', function (items) { if (self.query) { self.filterItemsByQuery(self.query); } }); // watch for changes to the filtered item list $scope.$watch('filteredItems', function (filteredItems) { // if list is empty, or active item is missing, unset active item if (!filteredItems.length || !_.contains(filteredItems, self.active)) { self.active = false; } }); }, link: function ($scope, $el, attr) { // should be defined via setInput() method if (!$scope.inputModel) { throw new Error('kbn-typeahead-input must be defined'); } $scope.$watch('typeahead.isVisible()', function (vis) { $el.toggleClass('visible', vis); }); } }; }); });