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.
477 lines
13 KiB
477 lines
13 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.
|
||
|
**/
|
||
|
|
||
|
|
||
|
(function($) {
|
||
|
|
||
|
window.flickerfreeScreen = {
|
||
|
|
||
|
screens: [],
|
||
|
responsiveness: 10000,
|
||
|
|
||
|
/**
|
||
|
* Set or reset UI in progress state for element with id.
|
||
|
*
|
||
|
* @param {boolean} in_progress
|
||
|
* @param {string} id
|
||
|
*/
|
||
|
setElementProgressState: function(id, in_progress) {
|
||
|
var elm = $('#flickerfreescreen_'+id);
|
||
|
|
||
|
if (in_progress) {
|
||
|
elm.addClass('is-loading is-loading-fadein delayed-15s');
|
||
|
}
|
||
|
else {
|
||
|
elm.removeClass('is-loading is-loading-fadein delayed-15s');
|
||
|
}
|
||
|
},
|
||
|
|
||
|
add: function(screen) {
|
||
|
// switch off time control refreshing using full page refresh
|
||
|
timeControl.refreshPage = false;
|
||
|
|
||
|
// init screen item
|
||
|
this.screens[screen.id] = screen;
|
||
|
this.screens[screen.id].interval = (screen.interval > 0) ? screen.interval * 1000 : 0;
|
||
|
this.screens[screen.id].timestamp = 0;
|
||
|
this.screens[screen.id].timestampResponsiveness = 0;
|
||
|
this.screens[screen.id].timestampActual = 0;
|
||
|
this.screens[screen.id].isRefreshing = false;
|
||
|
this.screens[screen.id].isReRefreshRequire = false;
|
||
|
this.screens[screen.id].error = 0;
|
||
|
|
||
|
// SCREEN_RESOURCE_MAP
|
||
|
if (screen.resourcetype == 2) {
|
||
|
this.screens[screen.id].data = new SVGMap(this.screens[screen.id].data);
|
||
|
$(screen.data.container).attr({'aria-label': screen.data.options.aria_label, 'tabindex': 0})
|
||
|
.find('svg').attr('aria-hidden', 'true');
|
||
|
}
|
||
|
|
||
|
// init refresh plan
|
||
|
if (screen.isFlickerfree && screen.interval > 0) {
|
||
|
this.screens[screen.id].timeoutHandler = window.setTimeout(
|
||
|
function() {
|
||
|
window.flickerfreeScreen.refresh(screen.id);
|
||
|
},
|
||
|
this.screens[screen.id].interval
|
||
|
);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
remove: function(screen) {
|
||
|
if (typeof screen.id !== 'undefined' && typeof this.screens[screen.id] !== 'undefined') {
|
||
|
if (typeof this.screens[screen.id].timeoutHandler !== 'undefined') {
|
||
|
window.clearTimeout(this.screens[screen.id].timeoutHandler);
|
||
|
}
|
||
|
|
||
|
delete this.screens[screen.id];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
refresh: function(id) {
|
||
|
var screen = this.screens[id];
|
||
|
|
||
|
if (empty(screen.id)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Do not update screen if displaying static hintbox.
|
||
|
if ($('#flickerfreescreen_' + id + ' [data-expanded="true"]').length) {
|
||
|
if (screen.isFlickerfree && screen.interval > 0) {
|
||
|
clearTimeout(screen.timeoutHandler);
|
||
|
screen.timeoutHandler = setTimeout(() => flickerfreeScreen.refresh(id), 1000);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 17 SCREEN_RESOURCE_HISTORY
|
||
|
* 21 SCREEN_RESOURCE_HTTPTEST_DETAILS
|
||
|
* 22 SCREEN_RESOURCE_DISCOVERY
|
||
|
* 23 SCREEN_RESOURCE_HTTPTEST
|
||
|
*/
|
||
|
var type_params = {
|
||
|
'17': ['mode', 'resourcetype', 'pageFile', 'page'],
|
||
|
'21': ['mode', 'resourcetype', 'profileIdx2'],
|
||
|
'22': ['mode', 'resourcetype', 'data'],
|
||
|
'23': ['mode', 'resourcetype', 'data', 'page'],
|
||
|
'default': ['mode', 'screenid', 'groupid', 'hostid', 'pageFile', 'profileIdx', 'profileIdx2',
|
||
|
'screenitemid'
|
||
|
]
|
||
|
},
|
||
|
params_index = type_params[screen.resourcetype] ? screen.resourcetype : 'default',
|
||
|
self = this;
|
||
|
|
||
|
const ajax_url = new Curl('jsrpc.php');
|
||
|
const post_data = {
|
||
|
type: 9, // PAGE_TYPE_TEXT
|
||
|
method: 'screen.get',
|
||
|
|
||
|
// TODO: remove, do not use timestamp passing to server and back to ensure newest content will be shown.
|
||
|
timestamp: screen.timestampActual
|
||
|
};
|
||
|
|
||
|
$.each(type_params[params_index], function (i, name) {
|
||
|
if (!empty(screen[name])) {
|
||
|
post_data[name] = screen[name];
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// set actual timestamp
|
||
|
screen.timestampActual = new CDate().getTime();
|
||
|
|
||
|
// timeline params
|
||
|
// SCREEN_RESOURCE_HTTPTEST_DETAILS, SCREEN_RESOURCE_DISCOVERY, SCREEN_RESOURCE_HTTPTEST
|
||
|
if ($.inArray(screen.resourcetype, [21, 22, 23]) === -1) {
|
||
|
post_data.from = screen.timeline.from;
|
||
|
post_data.to = screen.timeline.to;
|
||
|
}
|
||
|
|
||
|
switch (parseInt(screen.resourcetype, 10)) {
|
||
|
// SCREEN_RESOURCE_GRAPH
|
||
|
// SCREEN_RESOURCE_SIMPLE_GRAPH
|
||
|
case 0:
|
||
|
case 1:
|
||
|
self.refreshImg(id, function() {
|
||
|
$('a', '#flickerfreescreen_' + id).each(function() {
|
||
|
var obj = $(this),
|
||
|
url = new Curl(obj.attr('href'));
|
||
|
|
||
|
url.setArgument('from', screen.timeline.from);
|
||
|
url.setArgument('to', screen.timeline.to);
|
||
|
|
||
|
obj.attr('href', url.getUrl());
|
||
|
});
|
||
|
});
|
||
|
break;
|
||
|
|
||
|
// SCREEN_RESOURCE_MAP
|
||
|
case 2:
|
||
|
self.refreshMap(id);
|
||
|
break;
|
||
|
|
||
|
// SCREEN_RESOURCE_HISTORY
|
||
|
case 17:
|
||
|
if (screen.data.action == 'showgraph') {
|
||
|
self.refreshImg(id);
|
||
|
}
|
||
|
else {
|
||
|
if ('itemids' in screen.data) {
|
||
|
$.each(screen.data.itemids, function (i, value) {
|
||
|
if (!empty(value)) {
|
||
|
post_data['itemids[' + value + ']'] = value;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
post_data['graphid'] = screen.data.graphid;
|
||
|
}
|
||
|
|
||
|
$.each({
|
||
|
'filter': screen.data.filter,
|
||
|
'filter_task': screen.data.filterTask,
|
||
|
'mark_color': screen.data.markColor,
|
||
|
'action': screen.data.action
|
||
|
}, function (ajax_key, value) {
|
||
|
if (!empty(value)) {
|
||
|
post_data[ajax_key] = value;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
self.refreshHtml(id, ajax_url, post_data);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
self.refreshHtml(id, ajax_url, post_data);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// set next refresh execution time
|
||
|
if (screen.isFlickerfree && screen.interval > 0) {
|
||
|
clearTimeout(screen.timeoutHandler);
|
||
|
screen.timeoutHandler = setTimeout(() => flickerfreeScreen.refresh(id), screen.interval);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
refreshAll: function(time_object) {
|
||
|
for (var id in this.screens) {
|
||
|
var screen = this.screens[id];
|
||
|
|
||
|
if (!empty(screen.id) && typeof screen.timeline !== 'undefined') {
|
||
|
screen.timeline = $.extend(screen.timeline, {
|
||
|
from: time_object.from,
|
||
|
to: time_object.to,
|
||
|
from_ts: time_object.from_ts,
|
||
|
to_ts: time_object.to_ts
|
||
|
});
|
||
|
|
||
|
// Reset pager on time range update (SCREEN_RESOURCE_HISTORY).
|
||
|
if (screen.resourcetype == 17) {
|
||
|
screen.page = 1;
|
||
|
}
|
||
|
|
||
|
// restart refresh execution starting from Now
|
||
|
clearTimeout(screen.timeoutHandler);
|
||
|
this.refresh(id);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
refreshHtml: function(id, ajaxUrl, post_data = {}) {
|
||
|
var screen = this.screens[id],
|
||
|
request_start = new CDate().getTime();
|
||
|
|
||
|
if (screen.isRefreshing) {
|
||
|
this.calculateReRefresh(id);
|
||
|
}
|
||
|
else {
|
||
|
screen.isRefreshing = true;
|
||
|
screen.timestampResponsiveness = new CDate().getTime();
|
||
|
this.setElementProgressState(id, true);
|
||
|
|
||
|
var ajaxRequest = $.ajax({
|
||
|
url: ajaxUrl.getUrl(),
|
||
|
type: 'post',
|
||
|
cache: false,
|
||
|
data: post_data,
|
||
|
dataType: 'html',
|
||
|
success: function(html) {
|
||
|
var html = $(html);
|
||
|
|
||
|
// Replace existing markup with server response.
|
||
|
if (request_start > screen.timestamp) {
|
||
|
screen.timestamp = request_start;
|
||
|
screen.isRefreshing = false;
|
||
|
|
||
|
$('.wrapper > .msg-bad').remove();
|
||
|
$('#flickerfreescreen_' + id).replaceWith(html);
|
||
|
html.filter('.msg-bad').insertBefore('.wrapper main');
|
||
|
window.flickerfreeScreen.setElementProgressState(id, false);
|
||
|
}
|
||
|
else if (!html.length) {
|
||
|
$('#flickerfreescreen_' + id).remove();
|
||
|
}
|
||
|
|
||
|
chkbxRange.init();
|
||
|
},
|
||
|
error: function() {
|
||
|
window.flickerfreeScreen.calculateReRefresh(id);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
$.when(ajaxRequest).always(function() {
|
||
|
if (screen.isReRefreshRequire) {
|
||
|
screen.isReRefreshRequire = false;
|
||
|
window.flickerfreeScreen.refresh(id);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
refreshMap: function(id) {
|
||
|
var screen = this.screens[id];
|
||
|
|
||
|
if (screen.isRefreshing) {
|
||
|
this.calculateReRefresh(id);
|
||
|
}
|
||
|
else {
|
||
|
screen.isRefreshing = true;
|
||
|
screen.error = 0;
|
||
|
screen.timestampResponsiveness = new CDate().getTime();
|
||
|
|
||
|
this.setElementProgressState(id, true);
|
||
|
|
||
|
var url = new Curl(screen.data.options.refresh);
|
||
|
url.setArgument('curtime', new CDate().getTime());
|
||
|
|
||
|
$.ajax({
|
||
|
'url': url.getUrl()
|
||
|
})
|
||
|
.fail(function() {
|
||
|
screen.error++;
|
||
|
window.flickerfreeScreen.calculateReRefresh(id);
|
||
|
})
|
||
|
.done(function(data) {
|
||
|
data.show_timestamp = screen.data.options.show_timestamp;
|
||
|
screen.isRefreshing = false;
|
||
|
screen.data.update(data);
|
||
|
$(screen.data.container).attr('aria-label', data.aria_label);
|
||
|
screen.timestamp = screen.timestampActual;
|
||
|
window.flickerfreeScreen.setElementProgressState(id, false);
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
refreshImg: function(id, successAction) {
|
||
|
var screen = this.screens[id],
|
||
|
request_start = new CDate().getTime();
|
||
|
|
||
|
if (screen.isRefreshing) {
|
||
|
this.calculateReRefresh(id);
|
||
|
}
|
||
|
else {
|
||
|
screen.isRefreshing = true;
|
||
|
screen.error = 0;
|
||
|
screen.timestampResponsiveness = new CDate().getTime();
|
||
|
|
||
|
this.setElementProgressState(id, true);
|
||
|
|
||
|
$('img', '#flickerfreescreen_' + id).each(function() {
|
||
|
var domImg = $(this),
|
||
|
url = new Curl(domImg.attr('src')),
|
||
|
zbx_sbox = domImg.data('zbx_sbox');
|
||
|
|
||
|
if (zbx_sbox && zbx_sbox.prevent_refresh) {
|
||
|
screen.isRefreshing = false;
|
||
|
window.flickerfreeScreen.setElementProgressState(id, false);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
url.setArgument('screenid', empty(screen.screenid) ? null : screen.screenid);
|
||
|
url.setArgument('from', screen.timeline.from);
|
||
|
url.setArgument('to', screen.timeline.to);
|
||
|
// Prevent image caching.
|
||
|
url.setArgument('_', request_start.toString(34));
|
||
|
|
||
|
// Create temp image in buffer.
|
||
|
var img = $('<img>', {
|
||
|
class: domImg.attr('class'),
|
||
|
id: domImg.attr('id'),
|
||
|
name: domImg.attr('name'),
|
||
|
border: domImg.attr('border'),
|
||
|
usemap: domImg.attr('usemap'),
|
||
|
alt: domImg.attr('alt')
|
||
|
})
|
||
|
.on('error', function() {
|
||
|
screen.error++;
|
||
|
window.flickerfreeScreen.calculateReRefresh(id);
|
||
|
})
|
||
|
.on('load', function() {
|
||
|
if (screen.error > 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
screen.isRefreshing = false;
|
||
|
window.flickerfreeScreen.setElementProgressState(id, false);
|
||
|
|
||
|
if (request_start > screen.timestamp) {
|
||
|
screen.timestamp = request_start;
|
||
|
|
||
|
domImg.replaceWith(img);
|
||
|
|
||
|
// Callback function on success.
|
||
|
if (!empty(successAction)) {
|
||
|
successAction();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (screen.isReRefreshRequire) {
|
||
|
screen.isReRefreshRequire = false;
|
||
|
window.flickerfreeScreen.refresh(id);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
var async = flickerfreeScreen.getImageSboxHeight(url, function(height) {
|
||
|
zbx_sbox.height = parseInt(height, 10);
|
||
|
// 'src' should be added only here to trigger load event after new height is received.
|
||
|
img.data('zbx_sbox', zbx_sbox)
|
||
|
.attr('src', url.getUrl());
|
||
|
});
|
||
|
|
||
|
if (async === null) {
|
||
|
img.attr('src', url.getUrl());
|
||
|
}
|
||
|
|
||
|
if (zbx_sbox) {
|
||
|
img.data('zbx_sbox', $.extend(zbx_sbox, {
|
||
|
from: screen.timeline.from,
|
||
|
from_ts: screen.timeline.from_ts,
|
||
|
to: screen.timeline.to,
|
||
|
to_ts: screen.timeline.to_ts
|
||
|
}));
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Getting shadow box height of graph image, asynchronous. Only for line graphs on dashboard.
|
||
|
* Will return xhr request for line graphs.
|
||
|
*
|
||
|
* @param {Curl} url Curl object for image request.
|
||
|
* Endpoint should support returning height via HTTP header.
|
||
|
* @param {function} cb Callable, will be called with value of shadow box height.
|
||
|
*
|
||
|
* @return {object|null}
|
||
|
*/
|
||
|
getImageSboxHeight: function (url, cb) {
|
||
|
if (['chart.php', 'chart2.php', 'chart3.php'].indexOf(url.getPath()) > -1
|
||
|
&& url.getArgument('outer') === '1') {
|
||
|
// Prevent request caching.
|
||
|
url.setArgument('_', (new Date).getTime().toString(34));
|
||
|
|
||
|
return $.get(url.getUrl(), {'onlyHeight': 1}, 'json')
|
||
|
.done(function(response, status, xhr) {
|
||
|
cb(xhr.getResponseHeader('X-ZBX-SBOX-HEIGHT'))
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
},
|
||
|
|
||
|
calculateReRefresh: function(id) {
|
||
|
var screen = this.screens[id],
|
||
|
time = new CDate().getTime();
|
||
|
|
||
|
if (screen.timestamp + this.responsiveness < time
|
||
|
&& screen.timestampResponsiveness + this.responsiveness < time) {
|
||
|
// take of busy flags
|
||
|
screen.isRefreshing = false;
|
||
|
screen.isReRefreshRequire = false;
|
||
|
|
||
|
// refresh anyway
|
||
|
window.flickerfreeScreen.refresh(id);
|
||
|
}
|
||
|
else {
|
||
|
screen.isReRefreshRequire = true;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
cleanAll: function() {
|
||
|
for (var id in this.screens) {
|
||
|
var screen = this.screens[id];
|
||
|
|
||
|
if (!empty(screen.id)) {
|
||
|
clearTimeout(screen.timeoutHandler);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.screens = [];
|
||
|
|
||
|
for (var id in timeControl.objectList) {
|
||
|
if (timeControl.objectList.hasOwnProperty(id)) {
|
||
|
timeControl.removeObject(id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}(jQuery));
|