/* ** 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. **/ /** * An object that is used to namespace objects, allows to retrieve and write objects via arbitrary path. */ window.ZABBIX = Object.create({ /** * @param {string} path Dot separated path. Each segment is used as object key. * @param {mixed} value Optional value to be written into path only if path held undefined before. * * @return {mixed} Value underlying the path is returned. */ namespace: function(path, value) { return path.split('.').reduce(function(obj, pt, idx, src) { var last = (idx + 1 == src.length); if (typeof obj[pt] === 'undefined') { obj[pt] = last ? value : {}; } return obj[pt]; }, this); }, /** * Logs user out, also, handles side effects before that. */ logout: function(event) { cancelEvent(event); var ls = this.namespace('instances.localStorage'); ls && ls.destruct(); redirect('index.php?reconnect=1', 'post', 'sid', true); } }); jQuery(function($) { $.propHooks.disabled = { set: function (el, val) { if (el.disabled !== val) { el.disabled = val; $(el).trigger(val ? 'disable' : 'enable'); } } }; var $search = $('#search'); if ($search.length) { createSuggest('search'); var $search_icon = $search.siblings('.js-search'); $search.on('keyup', function() { $search_icon.prop('disabled', $.trim($search.val()) === ''); }); $search.closest('form').on('submit', function() { return ($.trim($search.val()) !== ''); }); $search_icon.on('click', function() { if ($('.sidebar').is('.is-compact:not(.is-opened)')) { $search.focus(); return false; } }); } function uncheckedHandler($checkbox) { var $hidden = $checkbox.prev('input[type=hidden][name="' + $checkbox.prop('name') + '"]'); if ($checkbox.is(':checked') || $checkbox.prop('disabled')) { $hidden.remove(); } else if (!$hidden.length) { $('', {'type': 'hidden', 'name': $checkbox.prop('name')}) .val($checkbox.attr('unchecked-value')) .insertBefore($checkbox); } } $('input[unchecked-value]').each(function() { var $this = $(this); uncheckedHandler($this); $this.on('change enable disable', function () { uncheckedHandler($(this)) }) }); function showMenuPopup($obj, data, event, options) { var sections; switch (data.type) { case 'history': sections = getMenuPopupHistory(data); break; case 'host': sections = getMenuPopupHost(data, $obj); break; case 'map_element_submap': sections = getMenuPopupMapElementSubmap(data); break; case 'map_element_group': sections = getMenuPopupMapElementGroup(data); break; case 'map_element_trigger': sections = getMenuPopupMapElementTrigger(data); break; case 'map_element_image': sections = getMenuPopupMapElementImage(data); break; case 'trigger': sections = getMenuPopupTrigger(data, $obj); break; case 'trigger_macro': sections = getMenuPopupTriggerMacro(data); break; case 'dashboard': sections = getMenuPopupDashboard(data, $obj); break; case 'item': sections = getMenuPopupItem(data); break; case 'item_prototype': sections = getMenuPopupItemPrototype(data); break; case 'dropdown': sections = getMenuPopupDropdown(data, $obj); break; case 'submenu': sections = getMenuPopupSubmenu(data); break; default: return; } $obj.menuPopup(sections, event, options); } /** * Create preloader elements for the menu popup. */ function createMenuPopupPreloader() { return $('
', { 'id': 'menu-popup-preloader', 'class': 'is-loading menu-popup-preloader' }) .appendTo($('body')) .on('click', function(e) { e.stopPropagation(); }) .hide(); } /** * Event handler for the preloader elements destroy. */ function menuPopupPreloaderCloseHandler(event) { overlayPreloaderDestroy(event.data.id); } /** * Is request to a server required to process and update the data passed to the popup menu? * * @param string type A menu popup type. * * @returns boolean */ function isServerRequestRequired(type) { switch (type) { case 'dashboard': case 'dropdown': case 'submenu': return false; default: return true; } } /** * Make a default position object for the menu popup, based on it's type. * * @param object $obj Menu popup opener object. * @param object data Menu popup data object. * @param object event Original opener event. */ function makeDefaultPosition($obj, data, event) { switch (data.type) { case 'dropdown': return { of: $obj, my: 'left top', at: 'left bottom' }; case 'submenu': return { of: $obj, my: 'left top', at: 'left bottom+10' }; default: // Should match the default algorithm used in $.menuPopup(). return { of: (['click', 'mouseup', 'mousedown'].includes(event.type) && event.originalEvent.detail) ? event : event.target, my: 'left top', at: 'left bottom', using: (pos, data) => { let max_left = data.horizontal === 'left' ? document.querySelector('.wrapper').clientWidth : document.querySelector('.wrapper').clientWidth - data.element.width; pos.top = Math.max(0, pos.top); pos.left = Math.max(0, Math.min(max_left, pos.left)); data.element.element[0].style.top = `${pos.top}px`; data.element.element[0].style.left = `${pos.left}px`; } }; } } /** * Build menu popup for given elements. */ $(document).on('keydown click', '[data-menu-popup]', function(event) { var $obj = $(this), data = $obj.data('menu-popup'); if (event.type === 'keydown' && event.which != 13) { return; } // Manually trigger event for menuPopupPreloaderCloseHandler call for the previous preloader. if ($('#menu-popup-preloader').length) { $(document).trigger('click'); } // Close other action menus and prevent focus jumping before opening a new popup. $('.menu-popup-top').menuPopup('close', null, false); // Create options object based on original options. var options = $.extend({ position: makeDefaultPosition($obj, data, event) }, data.options || {}); if (isServerRequestRequired(data.type)) { if (data.type === 'trigger') { // Add additional IDs from checkboxes and pass them to popup menu. data.data.ids = Object.keys(chkbxRange.getSelectedIds()); } var url = new Curl('zabbix.php'); url.setArgument('action', 'menu.popup'); url.setArgument('type', data.type); var xhr = $.ajax({ url: url.getUrl(), method: 'POST', data: { data: data.data }, dataType: 'json' }); var $preloader = createMenuPopupPreloader(); setTimeout(function() { $preloader.fadeIn(200).position(options.position); }, 500); addToOverlaysStack($preloader.prop('id'), event.target, 'preloader', xhr); xhr.done(function(resp) { overlayPreloaderDestroy($preloader.prop('id')); if ('error' in resp) { clearMessages(); const message_box = makeMessageBox('bad', resp.error.messages, resp.error.title); addMessage(message_box); return; } showMenuPopup($obj, jQuery.extend({context: data.context}, resp.data), event, options); }); $(document) .off('click', menuPopupPreloaderCloseHandler) .on('click', {id: $preloader.prop('id')}, menuPopupPreloaderCloseHandler); } else { showMenuPopup($obj, jQuery.extend({type: data.type}, data.data), event, options); } return false; }); /** * add.popup event * * Call multiselect method 'addData' if parent was multiselect, execute addPopupValues function * or just update input field value * * @param object data * @param string data.object object name * @param array data.values values * @param string data.parentId parent id */ $(document).on('add.popup', function(e, data) { // multiselect check if ($('#' + data.parentId).hasClass('multiselect')) { var items = []; for (var i = 0; i < data.values.length; i++) { if (typeof data.values[i].id !== 'undefined') { var item = { 'id': data.values[i].id, 'name': data.values[i].name, 'query': data.values[i].query }; if (typeof data.values[i].prefix !== 'undefined') { item.prefix = data.values[i].prefix; } items.push(item); } } $('#' + data.parentId).multiSelect('addData', items); } else if (typeof window.addPopupValues !== 'undefined') { // execute function if they exist window.addPopupValues(data); } else if (typeof view.addPopupValues !== 'undefined') { view.addPopupValues(data); } else { $('#' + data.parentId).val(data.values[0].name); } }); // redirect buttons $('button[data-url]').click(function() { var button = $(this); var confirmation = button.attr('data-confirmation'); if (typeof confirmation === 'undefined' || (typeof confirmation !== 'undefined' && confirm(confirmation))) { if (button.attr('data-post')) { return redirect(button.attr('data-url'), 'post', '_csrf_token', true); } window.location = button.attr('data-url'); } }); // Initialize hintBox event handlers. hintBox.bindEvents(); // Simulate Safari behaviour when text in a text field with autofocus becomes selected after page has loaded. if (!SF) { $('input[type=text][autofocus=autofocus]').filter(':visible').select(); } /** * @param {boolean} preserve_state Preserve current state of the debug button. * * @returns {boolean} false */ function debug_click_handler(preserve_state) { var $button = $(this), visible = sessionStorage.getItem('debug-info-visible') === '1'; if (preserve_state !== true) { visible = !visible; sessionStorage.setItem('debug-info-visible', visible ? '1' : '0'); } $button.text(visible ? t('Hide debug') : t('Debug')); var style = $button.data('debug-info-style'); if (style) { style.sheet.deleteRule(0); } else { style = document.createElement('style'); $button.data('debug-info-style', style); document.head.appendChild(style); } // ZBX_STYLE_DEBUG_OUTPUT style.sheet.insertRule('.debug-output { display: ' + (visible ? 'block' : 'none') + '; }', 0); if (preserve_state !== true) { $.publish('debug.click', { visible: visible }); } return false; } // Initialize ZBX_STYLE_BTN_DEBUG debug button and debug info state. $('.btn-debug').each(function(index, button) { $(button) .on('click', debug_click_handler) .addClass('visible'); debug_click_handler.call(button, true); }); });