/* ** Zabbix ** Copyright (C) 2001-2023 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ (function($) { var ZBX_STYLE_CLASS = 'multiselect-control'; const MS_ACTION_POPUP = 0; const MS_ACTION_AUTOSUGGEST = 1; /** * Multi select helper. * * @param string options['object_name'] backend data source * @param object options['objectOptions'] parameters to be added the request URL (optional) * * @see jQuery.multiSelect() */ $.fn.multiSelectHelper = function(options) { options = $.extend({objectOptions: {}}, options); var curl = new Curl('jsrpc.php'); curl.setArgument('type', 11); // PAGE_TYPE_TEXT_RETURN_JSON curl.setArgument('method', 'multiselect.get'); curl.setArgument('object_name', options.object_name); for (var key in options.objectOptions) { curl.setArgument(key, options.objectOptions[key]); } options.url = curl.getUrl(); return this.each(function() { $(this).empty().multiSelect(options); }); }; /* * Multiselect methods */ var methods = { /** * Get multi select selected data. * * @return array array of multiselect value objects */ getData: function() { var $obj = $(this).first(), ms = $obj.data('multiSelect'); var data = []; for (var id in ms.values.selected) { var item = ms.values.selected[id]; data.push({ id: id, name: item.name, prefix: (typeof item.prefix === 'undefined') ? '' : item.prefix }); } // Sort entries by name field. data.sort(function(a, b) { if (a.name === b.name) { return 0; } else { return (a.name < b.name) ? -1 : 1; } }); return data; }, /** * Insert outside data * * @param {array} items Multiselect value object. * @param {bool} trigger_change (optional) Either to trigger element on-change event once data added. True by default. * * @return jQuery */ addData: function(items, trigger_change) { return this.each(function() { var $obj = $(this), ms = $obj.data('multiSelect'); if (typeof trigger_change !== 'boolean') { trigger_change = true; } if (ms.options.selectedLimit == 1) { for (var id in ms.values.selected) { removeSelected($obj, id); } } for (var i = 0, l = items.length; i < l; i++) { addSelected($obj, items[i]); } trigger_change && $obj.trigger('change', ms); }); }, /** * Enable multi select UI control. * * @return jQuery */ enable: function() { return this.each(function() { var $obj = $(this), ms = $obj.data('multiSelect'); if (ms.options.disabled === true) { $obj.removeAttr('aria-disabled'); $('.multiselect-list', $obj).removeClass('disabled'); $('.multiselect-button > button', $obj.parent()).prop('disabled', false); $obj.append(makeMultiSelectInput($obj)); ms.options.disabled = false; cleanSearch($obj); } }); }, /** * Disable multi select UI control. * * @return jQuery */ disable: function() { return this.each(function() { var $obj = $(this), ms = $obj.data('multiSelect'); if (ms.options.disabled === false) { $obj.attr('aria-disabled', true); $('.multiselect-list', $obj).addClass('disabled'); $('.multiselect-button > button', $obj.parent()).prop('disabled', true); $('input[type="text"]', $obj).remove(); ms.options.disabled = true; cleanSearch($obj); } }); }, /** * Clean multi select object values. * * @return jQuery */ clean: function() { return this.each(function() { var $obj = $(this), ms = $obj.data('multiSelect'); for (var id in ms.values.selected) { removeSelected($obj, id); } cleanSearch($obj); $obj.trigger('change', ms); }); }, /** * Modify one or more multiselect options after multiselect object has been created. * * @return jQuery */ modify: function(options) { return this.each(function() { var $obj = $(this), ms = $obj.data('multiSelect'); var addNew_modified = ('addNew' in options) && options['addNew'] != ms.options['addNew']; for (var key in ms.options) { if (key in options) { ms.options[key] = options[key]; } } if (addNew_modified) { /* * When modifying the "addNew" option, few things must be done: * 1. Search input must be reset. * 2. The already selected "(new)" items must be either hidden and disabled or shown and enabled. * Note: hidden and disabled items will not submit to the server. * 3. The "change" trigger must fire. */ cleanSearch($obj); $('input[name*="[new]"]', $obj) .prop('disabled', !ms.options['addNew']) .each(function() { var id = $(this).val(); $('.selected li[data-id]', $obj).each(function() { if ($(this).data('id') == id) { $(this).toggle(ms.options['addNew']); } }); }); $obj.trigger('change', ms); } }); }, /** * Return option value. * * @return string */ getOption: function(key) { var ret = null; this.each(function() { var $obj = $(this); if ($obj.data('multiSelect') !== undefined) { ret = $obj.data('multiSelect').options[key]; } }); return ret; }, /** * @return HTMLElement */ getSelectButton: function() { var ret = null; this.each(function() { var $obj = $(this); if ($obj.data('multiSelect') !== undefined) { ret = $obj.data('multiSelect').select_button[0]; return false; } }); return ret; }, /** * @param array entries IDs to mark disabled. */ setDisabledEntries: function (entries) { this.each(function() { const $obj = $(this); const ms_parameters = $obj.data('multiSelect'); if (typeof ms_parameters === 'undefined') { return; } const link = new Curl(ms_parameters.options.url); link.setArgument('disabledids', entries); ms_parameters.options.url = link.getUrl(); ms_parameters.options.popup.parameters.disableids = entries; $obj.data('multiSelect', ms_parameters); }); } }; /** * Create multi select input element. * * @param string options['url'] backend url * @param string options['name'] input element name * @param object options['labels'] translated labels (optional) * @param object options['data'] preload data {id, name, prefix} (optional) * @param string options['data'][id] * @param string options['data'][name] * @param string options['data'][prefix] (optional) * @param bool options['data'][inaccessible] (optional) * @param bool options['data'][disabled] (optional) * @param string options['placeholder'] set custom placeholder (optional) * @param array options['excludeids'] the list of excluded ids (optional) * @param string options['defaultValue'] default value for input element (optional) * @param bool options['disabled'] turn on/off readonly state (optional) * @param bool options['hidden'] hide element (optional) * @param bool options['addNew'] allow user to create new names (optional) * @param int options['selectedLimit'] how many items can be selected (optional) * @param int options['limit'] how many available items can be received from backend (optional) * @param object options['popup'] popup data {parameters, width, height} (optional) * @param string options['popup']['parameters'] * @param string options['popup']['filter_preselect'] * @param string options['popup']['filter_preselect']['id'] * @param string options['popup']['filter_preselect']['submit_as'] * @param object options['popup']['filter_preselect']['submit_parameters'] * @param bool options['popup']['filter_preselect']['multiple'] * @param int options['popup']['width'] * @param int options['popup']['height'] * @param object options['autosuggest'] autosuggest options (optional) * @param object options['autosuggest']['filter_preselect'] * @param string options['autosuggest']['filter_preselect']['id'] * @param string options['autosuggest']['filter_preselect']['submit_as'] * @param object options['autosuggest']['filter_preselect']['submit_parameters'] * @param bool options['autosuggest']['filter_preselect']['multiple'] * @param string options['styles'] additional style for multiselect wrapper HTML element (optional) * @param string options['styles']['property'] * @param string options['styles']['value'] * * @return object */ $.fn.multiSelect = function(options) { // Call a public method. if (methods[options]) { return methods[options].apply(this, Array.prototype.slice.call(arguments, 1)); } var defaults = { url: '', name: '', labels: { 'No matches found': t('No matches found'), 'More matches found...': t('More matches found...'), 'type here to search': t('type here to search'), 'new': t('new'), 'Select': t('Select') }, placeholder: t('type here to search'), data: [], excludeids: [], addNew: false, defaultValue: null, disabled: false, selectedLimit: 0, limit: 20, popup: {}, styles: {} }; options = $.extend({}, defaults, options); return this.each(function() { var $obj = $(this); if ($obj.data('multiSelect') !== undefined) { return; } options.required_str = $obj.attr('aria-required') === undefined ? 'false' : $obj.attr('aria-required'); $obj.removeAttr('aria-required'); var ms = { options: options, values: { search: '', searches: {}, searching: {}, selected: {}, available: {}, available_div: $('