mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-05 02:16:39 +00:00
264 lines
7.6 KiB
Vue
264 lines
7.6 KiB
Vue
<template>
|
|
<select class="select2 form-select" ref="select2" required name="filter_type" :multiple="multiple" :disabled="disabled">
|
|
<option class="no-wrap p-0" v-for="(item, i) in options_2" :selected="is_selected(item)" :value="item.value" :disabled="item.disabled">
|
|
{{item.label}}
|
|
</option>
|
|
<optgroup v-for="(item, i) in groups_options_2" :label="item.group">
|
|
<option v-for="(opt, j) in item.options" :selected="is_selected(opt)" :value="opt.value" :disabled="opt.disabled">
|
|
{{opt.label}}
|
|
</option>
|
|
</optgroup>
|
|
</select>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, computed, watch, onBeforeUnmount } from "vue";
|
|
|
|
const select2 = ref(null);
|
|
|
|
// const selected2_option = ref({});
|
|
|
|
const emit = defineEmits(['update:selected_option', 'update:selected_options', 'select_option', 'unselect_option', 'change_selected_options']);
|
|
|
|
const options_2 = ref([]);
|
|
const groups_options_2 = ref([]);
|
|
const selected_option_2 = ref({});
|
|
const selected_values = ref([]); // used only if multiple == true
|
|
const refresh_options = ref(0);
|
|
|
|
const props = defineProps({
|
|
id: String,
|
|
options: Array,
|
|
selected_option: Object,
|
|
selected_options: Array,
|
|
multiple: Boolean,
|
|
add_tag: Boolean,
|
|
disable_change: Boolean,
|
|
theme: String,
|
|
dropdown_size: String,
|
|
disabled: Boolean
|
|
});
|
|
|
|
let first_time_render = true;
|
|
|
|
onMounted(() => {
|
|
if (!props.options) { return; }
|
|
if (!props.disable_change || !first_time_render) {
|
|
set_input();
|
|
}
|
|
});
|
|
|
|
watch(() => props.selected_option, (cur_value, old_value) => {
|
|
set_selected_option(cur_value);
|
|
change_select_2_selected_value();
|
|
}, { flush: 'pre'});
|
|
|
|
watch(() => props.selected_options, (cur_value, old_value) => {
|
|
set_selected_values(cur_value);
|
|
change_select_2_selected_value();
|
|
}, { flush: 'pre'});
|
|
|
|
|
|
watch([refresh_options], (cur_value, old_value) => {
|
|
render();
|
|
}, { flush: 'post'});
|
|
|
|
|
|
watch(() => props.options, (current_value, old_value) => {
|
|
if (props.disable_change == true || current_value == null) { return; }
|
|
set_input();
|
|
}, { flush: 'pre'});
|
|
|
|
|
|
function set_input() {
|
|
set_options();
|
|
set_selected_option();
|
|
set_selected_values();
|
|
}
|
|
|
|
function set_options() {
|
|
options_2.value = [];
|
|
groups_options_2.value = [];
|
|
|
|
if (props.options == null) { return; }
|
|
let groups_dict = {};
|
|
props.options.forEach((option) => {
|
|
let opt_2 = { ...option };
|
|
if (opt_2.value == null) {
|
|
opt_2.value = opt_2.label;
|
|
}
|
|
if (option.group == null) {
|
|
options_2.value.push(opt_2);
|
|
} else {
|
|
if (groups_dict[option.group] == null) {
|
|
groups_dict[option.group] = { group: opt_2.group, options: [] };
|
|
}
|
|
groups_dict[option.group].options.push(opt_2);
|
|
}
|
|
});
|
|
groups_options_2.value = ntopng_utility.object_to_array(groups_dict);
|
|
refresh_options.value += 1;
|
|
}
|
|
|
|
|
|
const render = () => {
|
|
let select2Div = select2.value;
|
|
if (first_time_render == false) {
|
|
destroy();
|
|
}
|
|
if (!$(select2Div).hasClass("select2-hidden-accessible")) {
|
|
$(select2Div).select2({
|
|
width: '100%',
|
|
theme: props.theme ? props.theme : 'bootstrap-5',
|
|
dropdownParent: $(select2Div).parent(),
|
|
dropdownAutoWidth : true,
|
|
tags: props.add_tag && !props.multiple,
|
|
selectionCssClass: props.dropdown_size == "small" ? 'select2--small' : '',
|
|
dropdownCssClass: props.dropdown_size == "small" ? 'select2--small' : ''
|
|
});
|
|
$(select2Div).on('select2:select', function (e) {
|
|
let data = e.params.data;
|
|
if (data.element === null) {
|
|
//TODO: implement for multiselect
|
|
let option = { label: data.text, value: data.id };
|
|
emit('update:selected_option', option);
|
|
emit('select_option', option);
|
|
return;
|
|
}
|
|
let value = data.element._value;
|
|
let option = find_option_from_value_or_label(value);
|
|
if (value !== props.selected_option) {
|
|
emit('update:selected_option', option);
|
|
emit('select_option', option);
|
|
}
|
|
if (!props.multiple) {
|
|
return;
|
|
}
|
|
selected_values.value = selected_values.value.filter((v) => v != value);
|
|
selected_values.value.push(value);
|
|
let options = find_options_from_values(selected_values.value);
|
|
emit('update:selected_options', options);
|
|
emit('change_selected_options', options);
|
|
});
|
|
$(select2Div).on('select2:unselect', function (e) {
|
|
let data = e.params.data;
|
|
let value = data.element._value;
|
|
if (!props.multiple) {
|
|
return;
|
|
}
|
|
selected_values.value = selected_values.value.filter((v) => v != value);
|
|
let option = find_option_from_value_or_label(value);
|
|
let options = find_options_from_values(selected_values.value);
|
|
emit('unselect_option', option);
|
|
emit('update:selected_options', options);
|
|
emit('change_selected_options', options);
|
|
});
|
|
}
|
|
first_time_render = false;
|
|
// this.$forceUpdate();
|
|
change_select_2_selected_value();
|
|
};
|
|
|
|
function change_select_2_selected_value() {
|
|
let select2Div = select2.value;
|
|
if (!props.multiple) {
|
|
let value = get_value_from_selected_option(props.selected_option);
|
|
$(select2Div).val(value);
|
|
$(select2Div).trigger("change");
|
|
} else {
|
|
$(select2Div).val(selected_values.value);
|
|
$(select2Div).trigger("change");
|
|
}
|
|
}
|
|
|
|
function is_selected(item) {
|
|
if (!props.multiple) {
|
|
const is_zero_value = selected_option_2.value.value == 0 ||selected_option_2.value.value == "0";
|
|
return item.value == selected_option_2.value.value || (is_zero_value && item.label == selected_option_2.value.label);
|
|
}
|
|
return selected_values.value.find((v) => v == item.value) != null || item.selected;
|
|
}
|
|
|
|
function set_selected_values() {
|
|
if (props.selected_options == null || !props.multiple) {
|
|
return;
|
|
}
|
|
selected_values.value = [];
|
|
props.selected_options.forEach((opt) => {
|
|
let value = opt.value || opt.label;
|
|
selected_values.value.push(value);
|
|
});
|
|
}
|
|
|
|
function set_selected_option(selected_option) {
|
|
if (selected_option == null && !props.multiple) {
|
|
selected_option = get_props_selected_option();
|
|
}
|
|
selected_option_2.value = selected_option;
|
|
}
|
|
|
|
function get_props_selected_option() {
|
|
if (props.selected_option == null) {
|
|
return props.options[0];
|
|
}
|
|
return props.selected_option;
|
|
}
|
|
|
|
function get_value_from_selected_option(selected_option) {
|
|
if (selected_option == null) {
|
|
selected_option = get_props_selected_option();
|
|
}
|
|
let value;
|
|
if (selected_option.value != null) {
|
|
value = selected_option.value;
|
|
} else {
|
|
value = selected_option.label;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function find_options_from_values(values) {
|
|
let options = values.map((v) => find_option_from_value_or_label(v));
|
|
return options;
|
|
}
|
|
|
|
function find_option_from_value_or_label(value) {
|
|
let option_2 = find_option_2_from_value(value);
|
|
let option = props.options.find((o) => (o.value === option_2.value) || (o.label == option_2.label));
|
|
return option;
|
|
}
|
|
|
|
function find_option_2_from_value(value) {
|
|
if (value == null) {
|
|
value = get_value_from_selected_option();
|
|
}
|
|
// let option = options_2.value.find((o) => o.value == value);
|
|
let option = options_2.value.find((o) => o.value === value);
|
|
if (option != null) { return option; }
|
|
for (let i = 0; i < groups_options_2.value.length; i += 1) {
|
|
let g = groups_options_2.value[i];
|
|
option = g.options.find((o) => o.value === value);
|
|
if (option != null) {
|
|
return option;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
defineExpose({ render });
|
|
|
|
function destroy() {
|
|
try {
|
|
$(select2.value).select2('destroy');
|
|
$(select2.value).off('select2:select');
|
|
} catch(err) {
|
|
console.error("Destroy select-search catch error:");
|
|
console.error(err);
|
|
}
|
|
}
|
|
|
|
onBeforeUnmount(() => {
|
|
destroy();
|
|
});
|
|
|
|
</script>
|