You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

458 lines
11 KiB

/*
** 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) {
$('<input>', {'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 $('<div>', {
'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);
});
});