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.

405 lines
13 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.
**/
const ZBX_TEXTAREA_COLOR_WIDTH = 96;
(function($) {
var overlay,
colorbox,
input,
$overlay_input,
$overlay_colorbox,
$button_use_default,
defaults = {
palette: [
['FF0000', 'FF0080', 'BF00FF', '4000FF', '0040FF', '0080FF', '00BFFF', '00FFFF', '00FFBF', '00FF00', '80FF00', 'BFFF00', 'FFFF00', 'FFBF00', 'FF8000', 'FF4000', 'CC6600', '666699'],
['000000', '0F0F0F', '1E1E1E', '2D2D2D', '3C3C3C', '4B4B4B', '5A5A5A', '696969', '787878', '878787', '969696', 'A5A5A5', 'B4B4B4', 'C3C3C3', 'D2D2D2', 'E1E1E1', 'F0F0F0', 'FFFFFF'],
['FFEBEE', 'FCE4EC', 'F3E5F5', 'EDE7F6', 'E8EAF6', 'E3F2FD', 'E1F5FE', 'E0F7FA', 'E0F2F1', 'E8F5E9', 'F1F8E9', 'F9FBE7', 'FFFDE7', 'FFF8E1', 'FFF3E0', 'FBE9E7', 'EFEBE9', 'ECEFF1'],
['FFCDD2', 'F8BBD0', 'E1BEE7', 'D1C4E9', 'C5CAE9', 'BBDEFB', 'B3E5FC', 'B2EBF2', 'B2DFDB', 'C8E6C9', 'DCEDC8', 'F0F4C3', 'FFF9C4', 'FFECB3', 'FFE0B2', 'FFCCBC', 'D7CCC8', 'CFD8DC'],
['EF9A9A', 'F48FB1', 'CE93D8', 'B39DDB', '9FA8DA', '90CAF9', '81D4FA', '80DEEA', '80CBC4', 'A5D6A7', 'C5E1A5', 'E6EE9C', 'FFF59D', 'FFE082', 'FFCC80', 'FFAB91', 'BCAAA4', 'B0BEC5'],
['E57373', 'F06292', 'BA68C8', '9575CD', '7986CB', '64B5F6', '4FC3F7', '4DD0E1', '4DB6AC', '81C784', 'AED581', 'DCE775', 'FFF176', 'FFD54F', 'FFB74D', 'FF8A65', 'A1887F', '90A4AE'],
['EF5350', 'EC407A', 'AB47BC', '7E57C2', '5C6BC0', '42A5F5', '29B6F6', '26C6DA', '26A69A', '66BB6A', '9CCC65', 'D4E157', 'FFEE58', 'FFCA28', 'FFA726', 'FF7043', '8D6E63', '78909C'],
['F44336', 'E91E63', '9C27B0', '673AB7', '3F51B5', '2196F3', '03A9F4', '00BCD4', '009688', '4CAF50', '8BC34A', 'CDDC39', 'FFEB3B', 'FFC107', 'FF9800', 'FF5722', '795548', '607D8B'],
['E53935', 'D81B60', '8E24AA', '5E35B1', '3949AB', '1E88E5', '039BE5', '00ACC1', '00897B', '43A047', '7CB342', 'C0CA33', 'FDD835', 'FFB300', 'FB8C00', 'F4511E', '6D4C41', '546E7A'],
['D32F2F', 'C2185B', '7B1FA2', '512DA8', '303F9F', '1976D2', '0288D1', '0097A7', '00796B', '388E3C', '689F38', 'AFB42B', 'FBC02D', 'FFA000', 'F57C00', 'E64A19', '5D4037', '455A64'],
['C62828', 'AD1457', '6A1B9A', '4527A0', '283593', '1565C0', '0277BD', '00838F', '00695C', '2E7D32', '558B2F', '9E9D24', 'F9A825', 'FF8F00', 'EF6C00', 'D84315', '4E342E', '37474F'],
['B71C1C', '880E4F', '4A148C', '311B92', '1A237E', '0D47A1', '01579B', '006064', '004D40', '1B5E20', '33691E', '827717', 'F57F17', 'FF6F00', 'E65100', 'BF360C', '3E2723', '263238'],
['891515', '660A3B', '370F69', '24146D', '131A5E', '093578', '044174', '00484B', '003930', '144618', '264E16', '615911', 'B75F11', 'BF5300', 'AC3C00', '8F2809', '2E1D1A', '1C252A'],
['5B0E0E', '440727', '250A46', '180D49', '0D113F', '062350', '002B4D', '003032', '002620', '0D2F10', '19340F', '413B0B', '7A3F0B', '7F3700', '732800', '5F1B06', '1F1311', '13191C'],
['2D0707', '220313', '120523', '0C0624', '06081F', '031128', '001526', '001819', '00131D', '061708', '0C1A07', '201D05', '3D1F05', '3F1B00', '391400', '2F0D03', '0F0908', '090C0E'],
],
appendTo: 'body',
use_default: false,
onUpdate: null
},
/**
* Click handler for every colorpicker cell.
*
* @param {string} color
*/
setColorHandler = function (color) {
methods.set_color(color);
input.trigger('change');
methods.hide();
},
/**
* Set color to the overlay input colorbox.
*
* @param {string} color
*/
setPreviewColor = function (color) {
color = $.trim(color).toUpperCase();
if (input.data('use_default') && color.length == 0) {
$overlay_colorbox
.css({'background': ''})
.attr('title', t('Use default'))
.addClass('use-default')
.removeClass('use-transparent');
}
else if (/^[0-9A-F]{6}$/i.test(color)) {
$overlay_colorbox
.css({'background': '#' + color})
.attr('title', '#' + color)
.removeClass(['use-default', 'use-transparent']);
}
else {
$overlay_colorbox
.css({'background': ''})
.attr('title', t('Use default'))
.addClass('use-transparent')
.removeClass('use-default');
}
},
/**
* Calculates top and left position for colorpicker overlay element.
*/
getOverlayPosition = function(id) {
var colorbox = $('#lbl_' + id),
pos = colorbox.offset(),
dialog = colorbox.closest('.overlay-dialogue'),
overlay = $('#color_picker'),
min_outline = 10,
frame_dims = {
top: 0,
left: 0,
bottom: window.screen.height,
right: window.screen.width
},
left = pos.left + colorbox.outerWidth(),
top = pos.top;
// If colorpicker is located in dialog, use dialog as a frame.
if (overlay.parents('.overlay-dialogue').length) {
frame_dims.left = dialog.offset().left;
frame_dims.top = dialog.offset().top;
frame_dims.bottom = dialog.outerHeight() + frame_dims.top;
frame_dims.right = dialog.outerWidth() + frame_dims.left;
}
// Make sure that overlay is inside frame.
if (top + overlay.outerHeight() + min_outline > frame_dims.bottom) {
top = frame_dims.bottom - overlay.outerHeight() - min_outline;
}
if (left + overlay.outerWidth() + min_outline > frame_dims.right) {
left = frame_dims.right - overlay.outerWidth() - min_outline;
}
return {
top: top - frame_dims.top,
left: left - frame_dims.left
};
},
methods = {
/**
* Initialization of colorpicker overlay.
*
* @param object options
* @param array options.palette Every nested array contains hex color for one cell.
* @param string|object options.appendTo Target element where overlay should be appended.
*/
init: function(options) {
$overlay_input = $('<input>', {
type: 'text',
autofocus: 'autofocus',
maxlength: 6
})
.css('width', ZBX_TEXTAREA_COLOR_WIDTH + 'px')
.on('input keydown paste', (e) => {
const color = e.target.value;
if (color.length == 0 || color.length == 6) {
setPreviewColor(color);
}
})
.on('keypress', (e) => {
const color = e.target.value;
if (e.keyCode == KEY_ENTER && (color.length == 0 || color.length == 6)) {
setColorHandler(e.target.value);
}
});
const $close = $('<button>', {
type: 'button',
class: 'btn-overlay-close',
title: t('S_CLOSE')
})
.on('click', (e) => {
let color = $overlay_input.val();
if (color.length == 0 || color.length == 6) {
setColorHandler(color);
}
else {
methods.hide();
}
});
$overlay_colorbox = $('<div>', {
class: 'color-picker-preview',
'data-use-default': t('D')
});
$button_use_default = $('<button>', {
type: 'button',
class: 'btn-alt',
title: t('Use default'),
'aria-label': t('Use default')
})
.html(t('Use default'))
.on('click', () => setColorHandler(''));
overlay = $('<div>', {
class: 'overlay-dialogue color-picker-dialogue',
id: 'color_picker'
})
.append($close)
.append($('<div>').append([
$('<div>', {class: 'color-picker-input'}).append([$overlay_colorbox, $overlay_input]),
$button_use_default
]))
.append(
$.map(options.palette, (colors) => {
return $('<div>').append(
$.map(colors, (color) => {
return $('<button>', {'title': '#' + color, type: 'button', 'data-color': color})
.css('background', '#' + color)
})
);
})
)
.on('click', '[data-color]', function () {
setColorHandler($(this).data('color'));
});
overlay.appendTo($(options.appendTo));
methods.hide();
},
destroy: function(element) {
const id = $(element).attr('id');
if ($('#lbl_' + id).length == 0) {
return;
}
element.next().remove();
$(element)
.off('change')
.data('use_default', null);
},
/**
* Hide colorpicker overlay.
*/
hide: function() {
colorbox = null;
input = null;
overlay.css({
'zIndex': 1000,
'display': 'none',
'left': '-' + (overlay.width() ? overlay.width() : 100) + 'px'
});
removeFromOverlaysStack('color_picker');
},
/**
* Show colorpicker for specific element.
*
* @param string id Id of input element which will be associated with opened colorpicker instance.
* @param object target jQuery element (colorbox) which triggered show action.
*/
show: function(id, target) {
this.hide();
input = $('#' + id);
colorbox = $('#lbl_' + id);
if (input.is(':disabled,[readonly]')) {
return;
}
const pos = getOverlayPosition(id);
overlay.css({
'left': pos.left + 'px',
'top': pos.top + 'px',
'display': 'block'
});
if (input.data('use_default')) {
$button_use_default.show();
}
else {
$button_use_default.hide();
}
$overlay_input.val(input.val());
setPreviewColor(input.val());
addToOverlaysStack('color_picker', target, 'color_picker');
Overlay.prototype.recoverFocus.call({'$dialogue': overlay});
Overlay.prototype.containFocus.call({'$dialogue': overlay});
},
/**
* Set color as background color value of colorbox and as value for input.
*
* @param string color Desired hex color.
*/
set_color: function(color) {
color = $.trim(color).toUpperCase();
if (input.data('use_default') && color.length == 0) {
colorbox
.css({'background': ''})
.attr('title', t('Use default'))
.addClass('use-default')
.removeClass('use-transparent');
}
else if (/^[0-9A-F]{6}$/i.test(color)) {
colorbox
.css({'background': '#' + color})
.attr('title', '#' + color)
.removeClass(['use-default', 'use-transparent']);
}
else {
colorbox
.css({'background': ''})
.attr('title', t('Use default'))
.addClass('use-transparent')
.removeClass('use-default');
}
input.val(color);
},
/**
* Set desired color to input element and colorbox associated with input element.
*
* @param string id Id of input element.
* @param string color Hex color value.
*/
set_color_by_id: function(id, color) {
colorbox = $('#lbl_' + id);
input = $('#' + id);
methods.set_color(color);
}
};
$.colorpicker = function(method) {
if (methods[method]) {
if (!overlay) {
methods.init();
}
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
}
else {
$.error('Invalid method "' + method + '".');
}
}
$.fn.colorpicker = function(options) {
options = $.extend({}, defaults, options || {});
/**
* Initialize colorpicker overlay if it is not initialized.
*/
if (!overlay || !$('#color_picker').length) {
methods.init(options);
}
/*
* Initialization of each separate colorpicker element.
*
* @param {object} options
* @param {bool} options.use_default Target element where overlay should be appended.
* @param {callable} options.onUpdate Callback function to execute once color has changed.
*/
return this.each(function (_, element) {
const id = element.id;
if ($('#lbl_' + id).length) {
return;
}
$('<button>', {
id: 'lbl_' + id,
type: 'button',
class: 'color-picker-preview',
title: element.value ? '#' + element.value : '',
'data-use-default': t('D')
})
.on('keydown', function (e) {
if (e.keyCode == KEY_ENTER || e.keyCode == KEY_SPACE) {
e.preventDefault();
methods.show(element.id, e.target);
}
})
.on('click', function (e) {
methods.show(element.id, e.target);
})
.insertAfter(element);
$(element)
.data('use_default', options.use_default)
.change(function () {
methods.set_color_by_id(element.id, this.value);
if (options.onUpdate !== null) {
options.onUpdate.call(element, this.value);
}
});
methods.set_color_by_id(id, element.value);
});
}
})(jQuery);