grafana/public/app/plugins/datasource/grafana-azure-monitor-datas.../multi-select.directive.ts

170 lines
4.2 KiB
TypeScript

import angular from 'angular';
import _ from 'lodash';
export class MultiSelectDropdownCtrl {
dropdownVisible: boolean;
highlightIndex: number;
linkText: string;
options: Array<{ selected: boolean; text: string; value: string }>;
selectedValues: Array<{ text: string; value: string }>;
initialValues: string[];
onUpdated: any;
show() {
this.highlightIndex = -1;
this.options = this.options;
this.selectedValues = this.options.filter(({ selected }) => selected);
this.dropdownVisible = true;
}
hide() {
this.dropdownVisible = false;
}
updateLinkText() {
this.linkText =
this.selectedValues.length === 1 ? this.selectedValues[0].text : `(${this.selectedValues.length}) selected`;
}
clearSelections() {
this.selectedValues = _.filter(this.options, { selected: true });
if (this.selectedValues.length > 1) {
_.each(this.options, option => {
option.selected = false;
});
} else {
_.each(this.options, option => {
option.selected = true;
});
}
this.selectionsChanged();
}
selectValue(option: any) {
if (!option) {
return;
}
option.selected = !option.selected;
this.selectionsChanged();
}
selectionsChanged() {
this.selectedValues = _.filter(this.options, { selected: true });
if (!this.selectedValues.length && this.options.length) {
this.selectedValues = this.options.slice(0, 1);
}
this.updateLinkText();
this.onUpdated({ values: this.selectedValues.map(({ value }) => value) });
}
onClickOutside() {
this.selectedValues = _.filter(this.options, { selected: true });
if (this.selectedValues.length === 0) {
this.options[0].selected = true;
this.selectionsChanged();
}
this.dropdownVisible = false;
}
init() {
if (!this.options) {
return;
}
this.options = this.options.map(o => ({
...o,
selected: this.initialValues.includes(o.value),
}));
this.selectedValues = _.filter(this.options, { selected: true });
if (!this.selectedValues.length) {
this.options = this.options.map(o => ({
...o,
selected: true,
}));
}
this.updateLinkText();
}
updateSelection() {
this.selectedValues = _.filter(this.options, { selected: true });
if (!this.selectedValues.length && this.options.length) {
this.options = this.options.map(o => ({
...o,
selected: true,
}));
this.selectedValues = _.filter(this.options, { selected: true });
this.selectionsChanged();
}
this.updateLinkText();
}
}
/** @ngInject */
export function multiSelectDropdown($window: any, $timeout: any) {
return {
scope: { onUpdated: '&', options: '=', initialValues: '=' },
templateUrl: 'public/app/plugins/datasource/grafana-azure-monitor-datasource/partials/multi-select.directive.html',
controller: MultiSelectDropdownCtrl,
controllerAs: 'vm',
bindToController: true,
link: (scope: any, elem: any) => {
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(
() => {
bodyEl.on('click', () => {
bodyEl.on('click', bodyOnClick);
});
},
0,
false
);
}
function switchToLink() {
inputEl.hide();
linkEl.show();
bodyEl.off('click', bodyOnClick);
}
function bodyOnClick(e: any) {
if (elem.has(e.target).length === 0) {
scope.$apply(() => {
scope.vm.onClickOutside();
});
}
}
scope.$watch('vm.options', (newValue: any) => {
if (newValue) {
scope.vm.updateSelection(newValue);
}
});
scope.$watch('vm.dropdownVisible', (newValue: any) => {
if (newValue) {
openDropdown();
} else {
switchToLink();
}
});
scope.vm.init();
},
};
}
angular.module('grafana.directives').directive('multiSelect', multiSelectDropdown);