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.
1191 lines
29 KiB
1191 lines
29 KiB
1 year ago
|
/*
|
||
|
** 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.
|
||
|
**/
|
||
|
|
||
|
const ZBX_STYLE_COLLAPSED = 'collapsed';
|
||
|
|
||
|
const ZBX_STYLE_BTN_ICON = 'btn-icon';
|
||
|
|
||
|
const ZBX_ICON_BELL = 'zi-bell';
|
||
|
const ZBX_ICON_BELL_OFF = 'zi-bell-off';
|
||
|
const ZBX_ICON_CHECK = 'zi-check';
|
||
|
const ZBX_ICON_CHEVRON_DOWN = 'zi-chevron-down';
|
||
|
const ZBX_ICON_CHEVRON_LEFT = 'zi-chevron-left';
|
||
|
const ZBX_ICON_CHEVRON_RIGHT = 'zi-chevron-right';
|
||
|
const ZBX_ICON_CHEVRON_UP = 'zi-chevron-up';
|
||
|
const ZBX_ICON_COG_FILLED = 'zi-cog-filled';
|
||
|
const ZBX_ICON_COPY = 'zi-copy';
|
||
|
const ZBX_ICON_EYE_OFF = 'zi-eye-off';
|
||
|
const ZBX_ICON_FILTER = 'zi-filter';
|
||
|
const ZBX_ICON_HELP_SMALL = 'zi-help-small';
|
||
|
const ZBX_ICON_HOME = 'zi-home';
|
||
|
const ZBX_ICON_LOCK = 'zi-lock';
|
||
|
const ZBX_ICON_MORE = 'zi-more';
|
||
|
const ZBX_ICON_PAUSE = 'zi-pause';
|
||
|
const ZBX_ICON_PENCIL = 'zi-pencil';
|
||
|
const ZBX_ICON_PLAY = 'zi-play';
|
||
|
const ZBX_ICON_PLUS = 'zi-plus';
|
||
|
const ZBX_ICON_REMOVE_SMALL = 'zi-remove-small';
|
||
|
const ZBX_ICON_REMOVE_SMALLER = 'zi-remove-smaller';
|
||
|
const ZBX_ICON_SPEAKER = 'zi-speaker';
|
||
|
const ZBX_ICON_SPEAKER_OFF = 'zi-speaker-off';
|
||
|
const ZBX_ICON_TEXT = 'zi-text';
|
||
|
|
||
|
const KEY_ARROW_DOWN = 40;
|
||
|
const KEY_ARROW_LEFT = 37;
|
||
|
const KEY_ARROW_RIGHT = 39;
|
||
|
const KEY_ARROW_UP = 38;
|
||
|
const KEY_BACKSPACE = 8;
|
||
|
const KEY_DELETE = 46;
|
||
|
const KEY_ENTER = 13;
|
||
|
const KEY_ESCAPE = 27;
|
||
|
const KEY_TAB = 9;
|
||
|
const KEY_PAGE_UP = 33;
|
||
|
const KEY_PAGE_DOWN = 34;
|
||
|
const KEY_END = 35;
|
||
|
const KEY_HOME = 36;
|
||
|
const KEY_SPACE = 32;
|
||
|
|
||
|
/**
|
||
|
* jQuery based publish/subscribe handler.
|
||
|
*
|
||
|
* - $.subscribe(event_name, callback)
|
||
|
* - $.unsubscribe(event_name, callback)
|
||
|
* - $.publish(event_name, data_object)
|
||
|
*
|
||
|
*/
|
||
|
(function($) {
|
||
|
var pubsub = $({});
|
||
|
|
||
|
$.subscribe = function() {
|
||
|
pubsub.on.apply(pubsub, arguments);
|
||
|
};
|
||
|
|
||
|
$.unsubscribe = function() {
|
||
|
pubsub.off.apply(pubsub, arguments);
|
||
|
};
|
||
|
|
||
|
$.publish = function() {
|
||
|
pubsub.trigger.apply(pubsub, arguments);
|
||
|
};
|
||
|
}(jQuery));
|
||
|
|
||
|
var overlays_stack = new OverlayCollection();
|
||
|
|
||
|
function isset(key, obj) {
|
||
|
return (is_null(key) || is_null(obj)) ? false : (typeof(obj[key]) != 'undefined');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deprecated use strict comparison instead
|
||
|
*
|
||
|
* @param obj
|
||
|
* @returns {*}
|
||
|
*/
|
||
|
function empty(obj) {
|
||
|
if (is_null(obj)) {
|
||
|
return true;
|
||
|
}
|
||
|
if (obj === false) {
|
||
|
return true;
|
||
|
}
|
||
|
if (is_string(obj) && obj === '') {
|
||
|
return true;
|
||
|
}
|
||
|
if (typeof(obj) == 'undefined') {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return is_array(obj) && obj.length == 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deprecated use === null instead
|
||
|
*
|
||
|
* @param obj
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
function is_null(obj) {
|
||
|
return (obj == null);
|
||
|
}
|
||
|
|
||
|
function is_number(obj) {
|
||
|
return isNaN(obj) ? false : (typeof(obj) === 'number');
|
||
|
}
|
||
|
|
||
|
function is_object(obj, instance) {
|
||
|
if (typeof(instance) === 'object' || typeof(instance) === 'function') {
|
||
|
if (typeof(obj) === 'object' && obj instanceof instance) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (typeof(obj) === 'object') {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function is_string(obj) {
|
||
|
return (typeof(obj) === 'string');
|
||
|
}
|
||
|
|
||
|
function is_array(obj) {
|
||
|
return (obj != null) && (typeof obj == 'object') && ('splice' in obj) && ('join' in obj);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get elements existing exclusively in one of both arrays.
|
||
|
* @deprecated
|
||
|
*
|
||
|
* @param {Array} arr
|
||
|
*
|
||
|
* @returns {Array}
|
||
|
*/
|
||
|
Array.prototype.xor = function(arr) {
|
||
|
var merged_arr = this.concat(arr);
|
||
|
|
||
|
return merged_arr.filter(function(e) {
|
||
|
return (merged_arr.indexOf(e) === merged_arr.lastIndexOf(e));
|
||
|
});
|
||
|
};
|
||
|
|
||
|
function addListener(element, eventname, expression, bubbling) {
|
||
|
bubbling = bubbling || false;
|
||
|
element = $(element)[0];
|
||
|
|
||
|
if (element.addEventListener) {
|
||
|
element.addEventListener(eventname, expression, bubbling);
|
||
|
return true;
|
||
|
}
|
||
|
else if (element.attachEvent) {
|
||
|
element.attachEvent('on' + eventname, expression);
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function removeListener(element, eventname, expression, bubbling) {
|
||
|
bubbling = bubbling || false;
|
||
|
element = $(element);
|
||
|
|
||
|
if (element.removeEventListener) {
|
||
|
element.removeEventListener(eventname, expression, bubbling);
|
||
|
return true;
|
||
|
}
|
||
|
else if (element.detachEvent) {
|
||
|
element.detachEvent('on' + eventname, expression);
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function cancelEvent(e) {
|
||
|
if (!e) {
|
||
|
e = window.event;
|
||
|
}
|
||
|
|
||
|
e.stopPropagation();
|
||
|
e.preventDefault();
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function checkAll(form_name, chkMain, shkName) {
|
||
|
var frmForm = document.forms[form_name],
|
||
|
value = frmForm.elements[chkMain].checked;
|
||
|
|
||
|
chkbxRange.checkObjectAll(shkName, value);
|
||
|
chkbxRange.update(shkName);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function Confirm(msg) {
|
||
|
return confirm(msg);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function removes input elements in specified form that matches given selector.
|
||
|
*
|
||
|
* @param {object}|{string} form_name Form element in which input elements will be selected. If given value is 'null',
|
||
|
* the DOM document object will be used.
|
||
|
* @param {string} selector String containing one or more commas separated CSS selectors.
|
||
|
*
|
||
|
* @returns {bool}
|
||
|
*/
|
||
|
function removeVarsBySelector(form_name, selector) {
|
||
|
if (form_name !== null) {
|
||
|
var source = is_string(form_name) ? document.forms[form_name] : form_name;
|
||
|
}
|
||
|
else {
|
||
|
var source = document;
|
||
|
}
|
||
|
|
||
|
if (!source) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
var inputs = source.querySelectorAll(selector);
|
||
|
|
||
|
if (inputs.length) {
|
||
|
for (var i in inputs) {
|
||
|
if (typeof inputs[i] === 'object') {
|
||
|
inputs[i].parentNode.removeChild(inputs[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function create_var(form_name, var_name, var_value, doSubmit) {
|
||
|
var objForm = is_string(form_name) ? document.forms[form_name] : form_name;
|
||
|
if (!objForm) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var objVar = (typeof(objForm[var_name]) != 'undefined') ? objForm[var_name] : null;
|
||
|
if (is_null(objVar)) {
|
||
|
objVar = document.createElement('input');
|
||
|
objVar.setAttribute('type', 'hidden');
|
||
|
if (!objVar) {
|
||
|
return;
|
||
|
}
|
||
|
objVar.setAttribute('name', var_name);
|
||
|
objVar.setAttribute('id', var_name.replace(']', '').replace('[', '_'));
|
||
|
objForm.appendChild(objVar);
|
||
|
}
|
||
|
|
||
|
if (is_null(var_value)) {
|
||
|
objVar.parentNode.removeChild(objVar);
|
||
|
}
|
||
|
else {
|
||
|
objVar.value = var_value;
|
||
|
}
|
||
|
|
||
|
if (doSubmit) {
|
||
|
objForm.submit();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getDimensions(obj) {
|
||
|
var dim = {
|
||
|
left: 0,
|
||
|
top: 0,
|
||
|
right: 0,
|
||
|
bottom: 0,
|
||
|
width: 0,
|
||
|
height: 0,
|
||
|
offsetleft: 0
|
||
|
};
|
||
|
|
||
|
if (!is_null(obj) && typeof(obj.offsetParent) != 'undefined') {
|
||
|
var dim = {
|
||
|
left: parseInt(obj.style.left, 10),
|
||
|
top: parseInt(obj.style.top, 10),
|
||
|
width: parseInt(obj.style.width, 10),
|
||
|
height: parseInt(obj.style.height, 10),
|
||
|
offsetleft: parseInt(jQuery(obj).offset().left, 10)
|
||
|
};
|
||
|
|
||
|
if (!is_number(dim.top)) {
|
||
|
dim.top = parseInt(obj.offsetTop, 10);
|
||
|
}
|
||
|
if (!is_number(dim.left)) {
|
||
|
dim.left = parseInt(obj.offsetLeft, 10);
|
||
|
}
|
||
|
if (!is_number(dim.width)) {
|
||
|
dim.width = parseInt(obj.offsetWidth, 10);
|
||
|
}
|
||
|
if (!is_number(dim.height)) {
|
||
|
dim.height = parseInt(obj.offsetHeight, 10);
|
||
|
}
|
||
|
|
||
|
dim.right = dim.left + dim.width;
|
||
|
dim.bottom = dim.top + dim.height;
|
||
|
}
|
||
|
|
||
|
return dim;
|
||
|
}
|
||
|
|
||
|
function getPosition(obj) {
|
||
|
var pos = {top: 0, left: 0};
|
||
|
|
||
|
if (!is_null(obj) && typeof(obj.offsetParent) != 'undefined') {
|
||
|
pos.left = obj.offsetLeft;
|
||
|
pos.top = obj.offsetTop;
|
||
|
|
||
|
try {
|
||
|
while (!is_null(obj.offsetParent)) {
|
||
|
obj = obj.offsetParent;
|
||
|
pos.left += obj.offsetLeft;
|
||
|
pos.top += obj.offsetTop;
|
||
|
}
|
||
|
} catch(e) {
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Opens popup content in overlay dialogue.
|
||
|
*
|
||
|
* @param {string} action Popup controller related action.
|
||
|
* @param {array|object} parameters Array with key/value pairs that will be used as query for popup
|
||
|
* request.
|
||
|
*
|
||
|
* @param {string} dialogue_class CSS class, usually based on .modal-popup and .modal-popup-{size}.
|
||
|
* @param {string|null} dialogueid ID of overlay dialogue.
|
||
|
* @param {HTMLElement|null} trigger_element UI element which was clicked to open overlay dialogue.
|
||
|
* @param {bool} prevent_navigation Show warning when navigating away from an active dialogue.
|
||
|
*
|
||
|
* @returns {Overlay}
|
||
|
*/
|
||
|
function PopUp(action, parameters, {
|
||
|
dialogueid = null,
|
||
|
dialogue_class = '',
|
||
|
trigger_element = document.activeElement,
|
||
|
prevent_navigation = false
|
||
|
} = {}) {
|
||
|
hintBox.deleteAll();
|
||
|
|
||
|
let overlay = overlays_stack.getById(dialogueid);
|
||
|
|
||
|
if (!overlay) {
|
||
|
overlay = overlayDialogue({
|
||
|
dialogueid,
|
||
|
title: '',
|
||
|
doc_url: '',
|
||
|
content: jQuery('<div>', {'height': '68px', class: 'is-loading'}),
|
||
|
class: 'modal-popup ' + dialogue_class,
|
||
|
buttons: [],
|
||
|
element: trigger_element,
|
||
|
type: 'popup',
|
||
|
prevent_navigation
|
||
|
});
|
||
|
}
|
||
|
|
||
|
overlay
|
||
|
.load(action, parameters)
|
||
|
.then(function(resp) {
|
||
|
if ('error' in resp) {
|
||
|
overlay.setProperties({
|
||
|
title: resp.header !== undefined ? resp.header : '',
|
||
|
content: makeMessageBox('bad', resp.error.messages, resp.error.title, false),
|
||
|
buttons: [
|
||
|
{
|
||
|
'title': t('Cancel'),
|
||
|
'class': 'btn-alt js-cancel',
|
||
|
'cancel': true,
|
||
|
'action': function() {}
|
||
|
}
|
||
|
]
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
var buttons = resp.buttons !== null ? resp.buttons : [];
|
||
|
|
||
|
switch (action) {
|
||
|
case 'popup.scheduledreport.list':
|
||
|
case 'popup.scheduledreport.test':
|
||
|
case 'popup.scriptexec':
|
||
|
buttons.push({
|
||
|
'title': t('Ok'),
|
||
|
'cancel': true,
|
||
|
'action': (typeof resp.cancel_action !== 'undefined') ? resp.cancel_action : function() {}
|
||
|
});
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
buttons.push({
|
||
|
'title': t('Cancel'),
|
||
|
'class': 'btn-alt js-cancel',
|
||
|
'cancel': true,
|
||
|
'action': (typeof resp.cancel_action !== 'undefined') ? resp.cancel_action : function() {}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
overlay.setProperties({
|
||
|
title: resp.header,
|
||
|
doc_url: resp.doc_url,
|
||
|
content: resp.body,
|
||
|
controls: resp.controls,
|
||
|
buttons,
|
||
|
debug: resp.debug,
|
||
|
script_inline: resp.script_inline,
|
||
|
data: resp.data || null
|
||
|
});
|
||
|
|
||
|
for (const grid of overlay.$dialogue.$body[0].querySelectorAll('form .form-grid')) {
|
||
|
new ResizeObserver(() => {
|
||
|
for (const label of grid.querySelectorAll(':scope > label')) {
|
||
|
const rect = label.getBoundingClientRect();
|
||
|
|
||
|
if (rect.width > 0) {
|
||
|
grid.style.setProperty('--label-width', Math.ceil(rect.width) + 'px');
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}).observe(grid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
overlay.recoverFocus();
|
||
|
overlay.containFocus();
|
||
|
})
|
||
|
.fail((resp) => {
|
||
|
const error = resp.responseJSON !== undefined && resp.responseJSON.error !== undefined
|
||
|
? resp.responseJSON.error
|
||
|
: {title: t('Unexpected server error.')};
|
||
|
|
||
|
overlay.setProperties({
|
||
|
content: makeMessageBox('bad', error.messages, error.title, false),
|
||
|
buttons: [
|
||
|
{
|
||
|
'title': t('Cancel'),
|
||
|
'class': 'btn-alt js-cancel',
|
||
|
'cancel': true,
|
||
|
'action': function() {}
|
||
|
}
|
||
|
]
|
||
|
});
|
||
|
|
||
|
overlay.recoverFocus();
|
||
|
overlay.containFocus();
|
||
|
});
|
||
|
|
||
|
addToOverlaysStack(overlay);
|
||
|
|
||
|
return overlay;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Open "Update problem" dialog and manage URL change.
|
||
|
*
|
||
|
* @param {Object} parameters
|
||
|
* @param {array} parameters['eventids'] Eventids to update.
|
||
|
* @param {object} trigger_element (optional) UI element which was clicked to open overlay dialogue.
|
||
|
*
|
||
|
* @returns {Overlay}
|
||
|
*/
|
||
|
function acknowledgePopUp(parameters, trigger_element) {
|
||
|
var overlay = PopUp('popup.acknowledge.edit', parameters, {trigger_element}),
|
||
|
backurl = location.href;
|
||
|
|
||
|
overlay.trigger_parents = $(trigger_element).parents();
|
||
|
|
||
|
overlay.xhr.then(function() {
|
||
|
var url = new Curl('zabbix.php');
|
||
|
url.setArgument('action', 'popup');
|
||
|
url.setArgument('popup_action', 'acknowledge.edit');
|
||
|
url.setArgument('eventids', parameters.eventids);
|
||
|
|
||
|
history.replaceState({}, '', url.getUrl());
|
||
|
});
|
||
|
|
||
|
overlay.$dialogue[0].addEventListener('dialogue.close', () => {
|
||
|
history.replaceState({}, '', backurl);
|
||
|
}, {once: true});
|
||
|
|
||
|
return overlay;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function to add details about overlay UI elements in global overlays_stack variable.
|
||
|
*
|
||
|
* @param {string|Overlay} id Unique overlay element identifier or Overlay object.
|
||
|
* @param {object} element UI element which must be focused when overlay UI element will be closed.
|
||
|
* @param {object} type Type of overlay UI element.
|
||
|
* @param {object} xhr (optional) XHR request used to load content. Used to abort loading. Currently used
|
||
|
* with type 'popup' only.
|
||
|
*/
|
||
|
function addToOverlaysStack(id, element, type, xhr) {
|
||
|
if (id instanceof Overlay) {
|
||
|
overlays_stack.pushUnique(id);
|
||
|
}
|
||
|
else {
|
||
|
overlays_stack.pushUnique({
|
||
|
dialogueid: id.toString(),
|
||
|
element: element,
|
||
|
type: type,
|
||
|
xhr: xhr
|
||
|
});
|
||
|
}
|
||
|
|
||
|
jQuery(document)
|
||
|
.off('keydown', closeDialogHandler)
|
||
|
.on('keydown', closeDialogHandler);
|
||
|
}
|
||
|
|
||
|
// Keydown handler. Closes last opened overlay UI element.
|
||
|
function closeDialogHandler(event) {
|
||
|
if (event.which == 27) { // ESC
|
||
|
var dialog = overlays_stack.end();
|
||
|
if (typeof dialog !== 'undefined') {
|
||
|
switch (dialog.type) {
|
||
|
// Close overlay popup.
|
||
|
case 'popup':
|
||
|
overlayDialogueDestroy(dialog.dialogueid);
|
||
|
break;
|
||
|
|
||
|
// Close overlay hintbox.
|
||
|
case 'hintbox':
|
||
|
hintBox.hideHint(dialog.element, true);
|
||
|
break;
|
||
|
|
||
|
// Close popup menu overlays.
|
||
|
case 'menu-popup':
|
||
|
jQuery('.menu-popup.menu-popup-top:visible').menuPopup('close', dialog.element);
|
||
|
break;
|
||
|
|
||
|
// Close context menu preloader.
|
||
|
case 'preloader':
|
||
|
overlayPreloaderDestroy(dialog.dialogueid);
|
||
|
break;
|
||
|
|
||
|
// Close overlay time picker.
|
||
|
case 'clndr':
|
||
|
CLNDR.clndrhide();
|
||
|
break;
|
||
|
|
||
|
// Close overlay message.
|
||
|
case 'message':
|
||
|
jQuery(ZBX_MESSAGES).each(function(i, msg) {
|
||
|
msg.closeAllMessages();
|
||
|
});
|
||
|
break;
|
||
|
|
||
|
// Close overlay color picker.
|
||
|
case 'color_picker':
|
||
|
jQuery.colorpicker('hide');
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removed overlay from overlays stack and sets focus to source element.
|
||
|
*
|
||
|
* @param {string} dialogueid Id of dialogue, that is being closed.
|
||
|
* @param {boolean} return_focus If not FALSE, the element stored in overlay.element will be focused.
|
||
|
*
|
||
|
* @return {object|undefined|null} Overlay object, if found.
|
||
|
*/
|
||
|
function removeFromOverlaysStack(dialogueid, return_focus) {
|
||
|
if (return_focus !== false) {
|
||
|
return_focus = true;
|
||
|
}
|
||
|
|
||
|
const overlay = overlays_stack.removeById(dialogueid);
|
||
|
|
||
|
if (overlay && return_focus) {
|
||
|
if (overlay.element !== undefined) {
|
||
|
const element = overlay.element instanceof jQuery ? overlay.element[0] : overlay.element;
|
||
|
|
||
|
element.focus({preventScroll: true});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Remove event listener.
|
||
|
if (overlays_stack.length == 0) {
|
||
|
jQuery(document).off('keydown', closeDialogHandler);
|
||
|
}
|
||
|
|
||
|
return overlay;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reload content of Modal Overlay dialogue without closing it.
|
||
|
*
|
||
|
* @param {object} form Filter form in which element has been changed. Assumed that form is inside Overlay Dialogue.
|
||
|
* @param {string} action (optional) action value that is used in CRouter. Default value is 'popup.generic'.
|
||
|
*/
|
||
|
function reloadPopup(form, action) {
|
||
|
const dialogueid = form.closest('[data-dialogueid]').dataset.dialogueid;
|
||
|
const dialogue_class = jQuery(form).closest('[data-dialogueid]').prop('class');
|
||
|
const parameters = getFormFields(form);
|
||
|
|
||
|
action = action || 'popup.generic';
|
||
|
|
||
|
PopUp(action, parameters, {dialogueid, dialogue_class});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Pass value to add.popup trigger.
|
||
|
*
|
||
|
* @param {string} object refers to destination object
|
||
|
* @param {string} single_value value passed to destination object
|
||
|
* @param {string} parentid parent id
|
||
|
*/
|
||
|
function addValue(object, single_value, parentid) {
|
||
|
var overlay = overlays_stack.end(),
|
||
|
value = {};
|
||
|
|
||
|
if (isset(single_value, overlay.data)) {
|
||
|
value = overlay.data[single_value];
|
||
|
}
|
||
|
else {
|
||
|
value[object] = single_value;
|
||
|
}
|
||
|
|
||
|
if (typeof parentid === 'undefined') {
|
||
|
var parentid = null;
|
||
|
}
|
||
|
var data = {
|
||
|
object: object,
|
||
|
values: [value],
|
||
|
parentId: parentid
|
||
|
};
|
||
|
|
||
|
jQuery(document).trigger('add.popup', data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds multiple values to destination form.
|
||
|
*
|
||
|
* @param {string} frame refers to destination form
|
||
|
* @param {object} values values added to destination form
|
||
|
*/
|
||
|
function addValues(frame, values) {
|
||
|
var forms = document.getElementsByTagName('FORM')[frame],
|
||
|
frm_storage = null;
|
||
|
|
||
|
for (var key in values) {
|
||
|
if (values[key] === null) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (typeof forms !== 'undefined') {
|
||
|
frm_storage = jQuery(forms).find('#' + key).get(0);
|
||
|
}
|
||
|
if (typeof frm_storage === 'undefined' || frm_storage === null) {
|
||
|
frm_storage = document.getElementById(key);
|
||
|
}
|
||
|
|
||
|
if (jQuery(frm_storage).is(':input')) {
|
||
|
jQuery(frm_storage).val(values[key]).change();
|
||
|
}
|
||
|
else {
|
||
|
jQuery(frm_storage).html(values[key]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Collects checked values and passes them to add.popup trigger.
|
||
|
*
|
||
|
* @param {string} object refers to object that is selected from popup
|
||
|
* @param {string} parentid parent id
|
||
|
*/
|
||
|
function addSelectedValues(object, parentid) {
|
||
|
if (typeof parentid === 'undefined') {
|
||
|
var parentid = null;
|
||
|
}
|
||
|
|
||
|
var data = {object: object, values: [], parentId: parentid},
|
||
|
overlay = overlays_stack.end();
|
||
|
|
||
|
overlay.$dialogue.find('input[type="checkbox"]').filter(':checked').each((i, c) => {
|
||
|
if (c.name.indexOf('all_') == -1) {
|
||
|
data['values'].push(overlay.data[c.value] || c.value);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
jQuery(document).trigger('add.popup', data);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add media.
|
||
|
*
|
||
|
* @param {string} formname name of destination form
|
||
|
* @param {integer} media media id. If -1, then assumes that this is new media
|
||
|
* @param {integer} mediatypeid media type id
|
||
|
* @param {string} sendto media sendto value
|
||
|
* @param {string} period media period value
|
||
|
* @param {string} active media active value
|
||
|
* @param {string} severity media severity value
|
||
|
*
|
||
|
* @returns true
|
||
|
*/
|
||
|
function add_media(formname, media, mediatypeid, sendto, period, active, severity) {
|
||
|
var form = window.document.forms[formname];
|
||
|
var media_name = (media > -1) ? 'medias[' + media + ']' : 'new_media';
|
||
|
|
||
|
window.create_var(form, media_name + '[mediatypeid]', mediatypeid);
|
||
|
if (typeof sendto === "object") {
|
||
|
window.removeVarsBySelector(form, 'input[name^="'+media_name+'[sendto]"]');
|
||
|
jQuery(sendto).each(function(i, st) {
|
||
|
window.create_var(form, media_name + '[sendto]['+i+']', st);
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
window.create_var(form, media_name + '[sendto]', sendto);
|
||
|
}
|
||
|
window.create_var(form, media_name + '[period]', period);
|
||
|
window.create_var(form, media_name + '[active]', active);
|
||
|
window.create_var(form, media_name + '[severity]', severity);
|
||
|
|
||
|
form.submit();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send trigger expression form data to server for validation before adding it to trigger expression field.
|
||
|
*
|
||
|
* @param {Overlay} overlay
|
||
|
*/
|
||
|
function validate_trigger_expression(overlay) {
|
||
|
var $form = overlay.$dialogue.find('form'),
|
||
|
url = new Curl($form.attr('action'));
|
||
|
|
||
|
url.setArgument('add', 1);
|
||
|
|
||
|
overlay.setLoading();
|
||
|
overlay.xhr = jQuery.ajax({
|
||
|
url: url.getUrl(),
|
||
|
data: $form.serialize(),
|
||
|
complete: function() {
|
||
|
overlay.unsetLoading();
|
||
|
},
|
||
|
success: function(ret) {
|
||
|
overlay.$dialogue.find('.msg-bad, .msg-good').remove();
|
||
|
|
||
|
if ('error' in ret) {
|
||
|
const message_box = makeMessageBox('bad', ret.error.messages, ret.error.title);
|
||
|
|
||
|
message_box.insertBefore($form);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var form = window.document.forms[ret.dstfrm];
|
||
|
var obj = (typeof form !== 'undefined')
|
||
|
? jQuery(form).find('#' + ret.dstfld1).get(0)
|
||
|
: document.getElementById(ret.dstfld1);
|
||
|
|
||
|
if (ret.dstfld1 === 'expression' || ret.dstfld1 === 'recovery_expression') {
|
||
|
jQuery(obj).val(jQuery(obj).val() + ret.expression);
|
||
|
}
|
||
|
else {
|
||
|
jQuery(obj).val(ret.expression);
|
||
|
}
|
||
|
|
||
|
overlayDialogueDestroy(overlay.dialogueid);
|
||
|
},
|
||
|
dataType: 'json',
|
||
|
type: 'POST'
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function redirect(uri, method, needle, invert_needle, allow_empty) {
|
||
|
method = (method || 'get').toLowerCase();
|
||
|
|
||
|
var url = new Curl(uri);
|
||
|
|
||
|
if (method == 'get') {
|
||
|
window.location = url.getUrl();
|
||
|
}
|
||
|
else {
|
||
|
// useless param just for easier loop
|
||
|
var action = '';
|
||
|
var domBody = document.getElementsByTagName('body')[0];
|
||
|
var postForm = document.createElement('form');
|
||
|
domBody.appendChild(postForm);
|
||
|
postForm.setAttribute('method', 'post');
|
||
|
|
||
|
invert_needle = (typeof(invert_needle) != 'undefined' && invert_needle);
|
||
|
|
||
|
var args = url.getArguments();
|
||
|
for (var key in args) {
|
||
|
if (!allow_empty && empty(args[key])) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var is_needle = (typeof(needle) != 'undefined' && key.indexOf(needle) > -1);
|
||
|
|
||
|
if ((is_needle && !invert_needle) || (!is_needle && invert_needle)) {
|
||
|
if (Array.isArray(args[key])) {
|
||
|
for (var i = 0, l = args[key].length; i < l; i++) {
|
||
|
action += '&' + key + '[]=' + args[key][i];
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
action += '&' + key + '=' + args[key];
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var hInput = document.createElement('input');
|
||
|
hInput.setAttribute('type', 'hidden');
|
||
|
postForm.appendChild(hInput);
|
||
|
|
||
|
if (Array.isArray(args[key])) {
|
||
|
hInput.setAttribute('name', key + '[]');
|
||
|
for (var i = 0, l = args[key].length; i < l; i++) {
|
||
|
hInput.setAttribute('value', args[key][i]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
hInput.setAttribute('name', key);
|
||
|
hInput.setAttribute('value', args[key]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
postForm.setAttribute('action', url.getPath() + '?' + action.substr(1));
|
||
|
postForm.submit();
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Send parameters to given url using natural HTML form submission.
|
||
|
*
|
||
|
* @param {string} url
|
||
|
* @param {Object} params
|
||
|
* @param {boolean} allow_empty
|
||
|
*
|
||
|
* @return {boolean}
|
||
|
*/
|
||
|
function post(url, params) {
|
||
|
function addVars(post_form, name, value) {
|
||
|
if (Array.isArray(value)) {
|
||
|
for (let i = 0; i < value.length; i++) {
|
||
|
addVars(post_form, `${name}[]`, value[i]);
|
||
|
}
|
||
|
}
|
||
|
else if (typeof value === 'object' && value !== null) {
|
||
|
for (const [key, _value] of Object.entries(value)) {
|
||
|
addVars(post_form, `${name}[${key}]`, _value);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
addVar(post_form, name, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function addVar(post_form, name, value) {
|
||
|
const is_multiline = /\r|\n/.exec(value);
|
||
|
let input;
|
||
|
|
||
|
if (is_multiline) {
|
||
|
input = document.createElement('textarea');
|
||
|
}
|
||
|
else {
|
||
|
input = document.createElement('input');
|
||
|
input.type = 'hidden';
|
||
|
}
|
||
|
|
||
|
input.name = name;
|
||
|
input.value = value;
|
||
|
post_form.appendChild(input);
|
||
|
}
|
||
|
|
||
|
const dom_body = document.getElementsByTagName('body')[0];
|
||
|
const post_form = document.createElement('form');
|
||
|
post_form.setAttribute('action', url);
|
||
|
post_form.setAttribute('method', 'post');
|
||
|
post_form.style.display = 'none';
|
||
|
|
||
|
for (const [key, value] of Object.entries(params)) {
|
||
|
addVars(post_form, key, value);
|
||
|
}
|
||
|
|
||
|
dom_body.appendChild(post_form);
|
||
|
post_form.submit();
|
||
|
}
|
||
|
|
||
|
function showHide(obj) {
|
||
|
if (jQuery(obj).is(':hidden')) {
|
||
|
jQuery(obj).css('display', 'block');
|
||
|
}
|
||
|
else {
|
||
|
jQuery(obj).css('display', 'none');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function showHideVisible(obj) {
|
||
|
if (is_string(obj)) {
|
||
|
obj = document.getElementById(obj);
|
||
|
}
|
||
|
if (!obj) {
|
||
|
throw 'showHideVisible(): Object not found.';
|
||
|
}
|
||
|
|
||
|
if (obj.style.visibility != 'hidden') {
|
||
|
obj.style.visibility = 'hidden';
|
||
|
}
|
||
|
else {
|
||
|
obj.style.visibility = 'visible';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if element is visible.
|
||
|
*
|
||
|
* @param {object} element
|
||
|
*
|
||
|
* @return {boolean}
|
||
|
*/
|
||
|
function isVisible(element) {
|
||
|
return element.getClientRects().length > 0 && window.getComputedStyle(element).visibility !== 'hidden';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Switch element classes and return final class.
|
||
|
*
|
||
|
* @param object|string obj object or object id
|
||
|
* @param string class1
|
||
|
* @param string class2
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
function switchElementClass(obj, class1, class2) {
|
||
|
obj = (typeof obj === 'string') ? jQuery('#' + obj) : jQuery(obj);
|
||
|
|
||
|
if (obj.length > 0) {
|
||
|
if (obj.hasClass(class1)) {
|
||
|
obj.removeClass(class1);
|
||
|
obj.addClass(class2);
|
||
|
|
||
|
return class2;
|
||
|
}
|
||
|
else if (obj.hasClass(class2)) {
|
||
|
obj.removeClass(class2);
|
||
|
obj.addClass(class1);
|
||
|
|
||
|
return class1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the file name of the given path.
|
||
|
*
|
||
|
* @param string path
|
||
|
* @param string suffix
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
function basename(path, suffix) {
|
||
|
var name = path.replace(/^.*[\/\\]/g, '');
|
||
|
|
||
|
if (typeof suffix === 'string' && name.substr(name.length - suffix.length) == suffix) {
|
||
|
name = name.substr(0, name.length - suffix.length);
|
||
|
}
|
||
|
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Transform datetime parts to two digits e.g., 2 becomes 02.
|
||
|
*
|
||
|
* @param int val
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
function appendZero(val) {
|
||
|
return val < 10 ? '0' + val : val;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Trims selected element values.
|
||
|
*
|
||
|
* @param array selectors
|
||
|
*/
|
||
|
jQuery.fn.trimValues = function(selectors) {
|
||
|
var form = this,
|
||
|
obj;
|
||
|
|
||
|
jQuery.each(selectors, function(i, value) {
|
||
|
obj = jQuery(value, form);
|
||
|
|
||
|
jQuery(obj).each(function() {
|
||
|
jQuery(this).val(jQuery.trim(jQuery(this).val()));
|
||
|
});
|
||
|
});
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Inserts hidden input into a form
|
||
|
*
|
||
|
* @param string form_name
|
||
|
* @param string input_name
|
||
|
* @param string input_value
|
||
|
*/
|
||
|
function submitFormWithParam(form_name, input_name, input_value) {
|
||
|
var input = document.createElement('input');
|
||
|
input.setAttribute('type', 'hidden');
|
||
|
input.setAttribute('name', input_name);
|
||
|
input.setAttribute('value', input_value);
|
||
|
document.forms[form_name].appendChild(input);
|
||
|
jQuery(document.forms[form_name]).trigger('submit');
|
||
|
}
|
||
|
|
||
|
if (typeof Element.prototype.remove === 'undefined') {
|
||
|
Element.prototype.remove = function() {
|
||
|
this.parentNode.removeChild(this);
|
||
|
return this;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @deprecated use native bind method
|
||
|
*/
|
||
|
Function.prototype.bindAsEventListener = function (context) {
|
||
|
var method = this, args = Array.prototype.slice.call(arguments, 1);
|
||
|
|
||
|
return function(event) {
|
||
|
return method.apply(context, [event || window.event].concat(args));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
function openMassupdatePopup(action, parameters = {}, {
|
||
|
dialogue_class = '',
|
||
|
trigger_element = document.activeElement
|
||
|
}) {
|
||
|
const form = trigger_element.closest('form');
|
||
|
|
||
|
switch (action) {
|
||
|
case 'popup.massupdate.host':
|
||
|
parameters.hostids = Object.keys(chkbxRange.getSelectedIds());
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
parameters.ids = Object.keys(chkbxRange.getSelectedIds());
|
||
|
}
|
||
|
|
||
|
switch (action) {
|
||
|
case 'popup.massupdate.item':
|
||
|
parameters.context = form.querySelector('#form_context').value;
|
||
|
parameters.prototype = 0;
|
||
|
break;
|
||
|
|
||
|
case 'popup.massupdate.trigger':
|
||
|
parameters.context = form.querySelector('#form_context').value;
|
||
|
break;
|
||
|
|
||
|
case 'popup.massupdate.itemprototype':
|
||
|
case 'popup.massupdate.triggerprototype':
|
||
|
parameters.parent_discoveryid = form.querySelector('#form_parent_discoveryid').value;
|
||
|
parameters.context = form.querySelector('#form_context').value;
|
||
|
parameters.prototype = 1;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return PopUp(action, parameters, {dialogue_class, trigger_element});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {boolean} value
|
||
|
* @param {string} objectid
|
||
|
* @param {string} replace_to
|
||
|
*/
|
||
|
function visibilityStatusChanges(value, objectid, replace_to) {
|
||
|
const obj = document.getElementById(objectid);
|
||
|
|
||
|
if (obj === null) {
|
||
|
throw `Cannot find objects with name [${objectid}]`;
|
||
|
}
|
||
|
|
||
|
if (replace_to && replace_to != '') {
|
||
|
if (obj.originalObject) {
|
||
|
const old_obj = obj.originalObject;
|
||
|
old_obj.originalObject = obj;
|
||
|
|
||
|
obj.parentNode.replaceChild(old_obj, obj);
|
||
|
}
|
||
|
else if (!value) {
|
||
|
const new_obj = document.createElement('span');
|
||
|
new_obj.classList.add('visibility-box-caption');
|
||
|
new_obj.setAttribute('id', obj.id);
|
||
|
new_obj.innerHTML = replace_to;
|
||
|
new_obj.originalObject = obj;
|
||
|
|
||
|
obj.parentNode.replaceChild(new_obj, obj);
|
||
|
}
|
||
|
else {
|
||
|
throw 'Missing originalObject for restoring';
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
obj.style.visibility = value ? 'visible' : 'hidden';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clears session storage from markers of checked table rows.
|
||
|
* Or keeps only accessible IDs in the list of checked rows.
|
||
|
*
|
||
|
* @param {string} page
|
||
|
* @param {array|Object} keepids
|
||
|
* @param {boolean} mvc
|
||
|
*/
|
||
|
function uncheckTableRows(page, keepids = [], mvc = true) {
|
||
|
const key = mvc ? 'cb_zabbix_'+page : 'cb_'+page;
|
||
|
|
||
|
if (keepids.length) {
|
||
|
let keepids_formatted = {};
|
||
|
const current = chkbxRange.getSelectedIds();
|
||
|
|
||
|
for (const id of Object.values(keepids)) {
|
||
|
keepids_formatted[id.toString()] = (id in current) ? current[id] : '';
|
||
|
}
|
||
|
|
||
|
sessionStorage.setItem(key, JSON.stringify(keepids_formatted));
|
||
|
}
|
||
|
else {
|
||
|
sessionStorage.removeItem(key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fix jQuery ui.sortable vertical positioning bug.
|
||
|
$.widget("ui.sortable", $.extend({}, $.ui.sortable.prototype, {
|
||
|
_getParentOffset: function () {
|
||
|
this.offsetParent = this.helper.offsetParent();
|
||
|
|
||
|
const pos = this.offsetParent.offset();
|
||
|
|
||
|
if (this.scrollParent[0] !== this.document[0]
|
||
|
&& $.contains(this.scrollParent[0], this.offsetParent[0])) {
|
||
|
pos.left += this.scrollParent.scrollLeft();
|
||
|
pos.top += this.scrollParent.scrollTop();
|
||
|
}
|
||
|
|
||
|
if ((this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === 'html' && $.ui.ie)
|
||
|
|| this.offsetParent[0] === this.document[0].body) {
|
||
|
pos = {top: 0, left: 0};
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
top: pos.top + (parseInt(this.offsetParent.css('borderTopWidth'), 10) || 0),
|
||
|
left: pos.left + (parseInt(this.offsetParent.css('borderLeftWidth'), 10) || 0)
|
||
|
};
|
||
|
}
|
||
|
}));
|