| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- import angular from 'angular';
- import _ from 'lodash';
- import coreModule from '../core_module';
- export class ValueSelectDropdownCtrl {
- dropdownVisible: any;
- highlightIndex: any;
- linkText: any;
- oldVariableText: any;
- options: any;
- search: any;
- selectedTags: any;
- selectedValues: any;
- tags: any;
- variable: any;
- hide: any;
- onUpdated: any;
- /** @ngInject */
- constructor(private $q) {}
- show() {
- this.oldVariableText = this.variable.current.text;
- this.highlightIndex = -1;
- this.options = this.variable.options;
- this.selectedValues = _.filter(this.options, { selected: true });
- this.tags = _.map(this.variable.tags, value => {
- let tag = { text: value, selected: false };
- _.each(this.variable.current.tags, tagObj => {
- if (tagObj.text === value) {
- tag = tagObj;
- }
- });
- return tag;
- });
- this.search = {
- query: '',
- options: this.options.slice(0, Math.min(this.options.length, 1000)),
- };
- this.dropdownVisible = true;
- }
- updateLinkText() {
- const current = this.variable.current;
- if (current.tags && current.tags.length) {
- // filer out values that are in selected tags
- const selectedAndNotInTag = _.filter(this.variable.options, option => {
- if (!option.selected) {
- return false;
- }
- for (let i = 0; i < current.tags.length; i++) {
- const tag = current.tags[i];
- if (_.indexOf(tag.values, option.value) !== -1) {
- return false;
- }
- }
- return true;
- });
- // convert values to text
- const currentTexts = _.map(selectedAndNotInTag, 'text');
- // join texts
- this.linkText = currentTexts.join(' + ');
- if (this.linkText.length > 0) {
- this.linkText += ' + ';
- }
- } else {
- this.linkText = this.variable.current.text;
- }
- }
- clearSelections() {
- _.each(this.options, option => {
- option.selected = false;
- });
- this.selectionsChanged(false);
- }
- selectTag(tag) {
- tag.selected = !tag.selected;
- let tagValuesPromise;
- if (!tag.values) {
- tagValuesPromise = this.variable.getValuesForTag(tag.text);
- } else {
- tagValuesPromise = this.$q.when(tag.values);
- }
- return tagValuesPromise.then(values => {
- tag.values = values;
- tag.valuesText = values.join(' + ');
- _.each(this.options, option => {
- if (_.indexOf(tag.values, option.value) !== -1) {
- option.selected = tag.selected;
- }
- });
- this.selectionsChanged(false);
- });
- }
- keyDown(evt) {
- if (evt.keyCode === 27) {
- this.hide();
- }
- if (evt.keyCode === 40) {
- this.moveHighlight(1);
- }
- if (evt.keyCode === 38) {
- this.moveHighlight(-1);
- }
- if (evt.keyCode === 13) {
- if (this.search.options.length === 0) {
- this.commitChanges();
- } else {
- this.selectValue(this.search.options[this.highlightIndex], {}, true, false);
- }
- }
- if (evt.keyCode === 32) {
- this.selectValue(this.search.options[this.highlightIndex], {}, false, false);
- }
- }
- moveHighlight(direction) {
- this.highlightIndex = (this.highlightIndex + direction) % this.search.options.length;
- }
- selectValue(option, event, commitChange?, excludeOthers?) {
- if (!option) {
- return;
- }
- option.selected = this.variable.multi ? !option.selected : true;
- commitChange = commitChange || false;
- excludeOthers = excludeOthers || false;
- const setAllExceptCurrentTo = newValue => {
- _.each(this.options, other => {
- if (option !== other) {
- other.selected = newValue;
- }
- });
- };
- // commit action (enter key), should not deselect it
- if (commitChange) {
- option.selected = true;
- }
- if (option.text === 'All' || excludeOthers) {
- setAllExceptCurrentTo(false);
- commitChange = true;
- } else if (!this.variable.multi) {
- setAllExceptCurrentTo(false);
- commitChange = true;
- } else if (event.ctrlKey || event.metaKey || event.shiftKey) {
- commitChange = true;
- setAllExceptCurrentTo(false);
- }
- this.selectionsChanged(commitChange);
- }
- selectionsChanged(commitChange) {
- this.selectedValues = _.filter(this.options, { selected: true });
- if (this.selectedValues.length > 1) {
- if (this.selectedValues[0].text === 'All') {
- this.selectedValues[0].selected = false;
- this.selectedValues = this.selectedValues.slice(1, this.selectedValues.length);
- }
- }
- // validate selected tags
- _.each(this.tags, tag => {
- if (tag.selected) {
- _.each(tag.values, value => {
- if (!_.find(this.selectedValues, { value: value })) {
- tag.selected = false;
- }
- });
- }
- });
- this.selectedTags = _.filter(this.tags, { selected: true });
- this.variable.current.value = _.map(this.selectedValues, 'value');
- this.variable.current.text = _.map(this.selectedValues, 'text').join(' + ');
- this.variable.current.tags = this.selectedTags;
- if (!this.variable.multi) {
- this.variable.current.value = this.selectedValues[0].value;
- }
- if (commitChange) {
- this.commitChanges();
- }
- }
- commitChanges() {
- // if we have a search query and no options use that
- if (this.search.options.length === 0 && this.search.query.length > 0) {
- this.variable.current = { text: this.search.query, value: this.search.query };
- } else if (this.selectedValues.length === 0) {
- // make sure one option is selected
- this.options[0].selected = true;
- this.selectionsChanged(false);
- }
- this.dropdownVisible = false;
- this.updateLinkText();
- if (this.variable.current.text !== this.oldVariableText) {
- this.onUpdated();
- }
- }
- queryChanged() {
- this.highlightIndex = -1;
- this.search.options = _.filter(this.options, option => {
- return option.text.toLowerCase().indexOf(this.search.query.toLowerCase()) !== -1;
- });
- this.search.options = this.search.options.slice(0, Math.min(this.search.options.length, 1000));
- }
- init() {
- this.selectedTags = this.variable.current.tags || [];
- this.updateLinkText();
- }
- }
- /** @ngInject */
- export function valueSelectDropdown($compile, $window, $timeout, $rootScope) {
- return {
- scope: { variable: '=', onUpdated: '&' },
- templateUrl: 'public/app/partials/valueSelectDropdown.html',
- controller: 'ValueSelectDropdownCtrl',
- controllerAs: 'vm',
- bindToController: true,
- link: function(scope, elem) {
- const bodyEl = angular.element($window.document.body);
- const linkEl = elem.find('.variable-value-link');
- const inputEl = elem.find('input');
- function openDropdown() {
- inputEl.css('width', Math.max(linkEl.width(), 80) + 'px');
- inputEl.show();
- linkEl.hide();
- inputEl.focus();
- $timeout(
- function() {
- bodyEl.on('click', bodyOnClick);
- },
- 0,
- false
- );
- }
- function switchToLink() {
- inputEl.hide();
- linkEl.show();
- bodyEl.off('click', bodyOnClick);
- }
- function bodyOnClick(e) {
- if (elem.has(e.target).length === 0) {
- scope.$apply(function() {
- scope.vm.commitChanges();
- });
- }
- }
- scope.$watch('vm.dropdownVisible', newValue => {
- if (newValue) {
- openDropdown();
- } else {
- switchToLink();
- }
- });
- const cleanUp = $rootScope.$on('template-variable-value-updated', () => {
- scope.vm.updateLinkText();
- });
- scope.$on('$destroy', () => {
- cleanUp();
- });
- scope.vm.init();
- },
- };
- }
- coreModule.controller('ValueSelectDropdownCtrl', ValueSelectDropdownCtrl);
- coreModule.directive('valueSelectDropdown', valueSelectDropdown);
|