2012-03-06 14:22:01 +01:00
|
|
|
/**
|
|
|
|
* EGroupware clientside API object
|
|
|
|
*
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package etemplate
|
|
|
|
* @subpackage api
|
|
|
|
* @link http://www.egroupware.org
|
|
|
|
* @author Andreas Stöckel (as AT stylite.de)
|
|
|
|
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
|
|
|
* @version $Id$
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*egw:uses
|
2016-06-06 17:38:20 +02:00
|
|
|
vendor.bower-asset.jquery.dist.jquery;
|
2012-03-06 14:22:01 +01:00
|
|
|
egw_core;
|
|
|
|
*/
|
2021-06-05 20:39:39 +02:00
|
|
|
import './egw_core.js';
|
2012-03-06 14:22:01 +01:00
|
|
|
|
2016-02-29 16:50:24 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {string} _app application name object is instanciated for
|
|
|
|
* @param {object} _wnd window object is instanciated for
|
|
|
|
*/
|
|
|
|
egw.extend('tooltip', egw.MODULE_WND_LOCAL, function(_app, _wnd)
|
|
|
|
{
|
|
|
|
"use strict";
|
2012-03-06 14:22:01 +01:00
|
|
|
|
|
|
|
var tooltip_div = null;
|
|
|
|
var current_elem = null;
|
|
|
|
|
|
|
|
var time_delta = 100;
|
|
|
|
var show_delta = 0;
|
2015-10-20 01:57:07 +02:00
|
|
|
var show_delay = 200;
|
2012-03-06 14:22:01 +01:00
|
|
|
|
|
|
|
var x = 0;
|
|
|
|
var y = 0;
|
|
|
|
|
2022-06-02 17:55:40 +02:00
|
|
|
var optionsDefault = {
|
|
|
|
hideonhover: true,
|
2022-09-08 16:16:34 +02:00
|
|
|
position:'right',
|
2022-06-02 17:55:40 +02:00
|
|
|
open: function(){},
|
|
|
|
close: function(){}
|
|
|
|
};
|
|
|
|
|
2012-03-06 14:22:01 +01:00
|
|
|
/**
|
|
|
|
* Removes the tooltip_div from the DOM if it does exist.
|
|
|
|
*/
|
|
|
|
function hide()
|
|
|
|
{
|
|
|
|
if (tooltip_div != null)
|
|
|
|
{
|
|
|
|
tooltip_div = null;
|
|
|
|
}
|
2024-04-17 17:47:24 +02:00
|
|
|
_wnd.document.querySelectorAll("body > .egw_tooltip").forEach(t => t.remove());
|
2012-03-06 14:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Shows the tooltip at the current cursor position.
|
|
|
|
*/
|
2022-06-02 17:55:40 +02:00
|
|
|
function show(node, event, options)
|
2012-03-06 14:22:01 +01:00
|
|
|
{
|
2016-01-25 21:04:16 +01:00
|
|
|
if (tooltip_div && typeof x !== 'undefined' && typeof y !== 'undefined')
|
2012-03-06 14:22:01 +01:00
|
|
|
{
|
2022-06-02 17:55:40 +02:00
|
|
|
options.open.call(node, event, tooltip_div);
|
2012-03-06 14:22:01 +01:00
|
|
|
//Calculate the cursor_rectangle - this is a space the tooltip might
|
|
|
|
//not overlap with
|
|
|
|
var cursor_rect = {
|
|
|
|
left: (x - 8),
|
|
|
|
top: (y - 8),
|
2022-09-08 16:16:34 +02:00
|
|
|
right: (x + (options.position == "center" ? -1 * tooltip_div.width()/2 : 8)),
|
2012-03-06 14:22:01 +01:00
|
|
|
bottom: (y + 8)
|
|
|
|
};
|
|
|
|
|
|
|
|
//Calculate how much space is left on each side of the rectangle
|
2016-06-02 16:51:15 +02:00
|
|
|
var window_width = jQuery(_wnd.document).width();
|
|
|
|
var window_height = jQuery(_wnd.document).height();
|
2012-03-06 14:22:01 +01:00
|
|
|
var space_left = {
|
|
|
|
left: (cursor_rect.left),
|
|
|
|
top: (cursor_rect.top),
|
|
|
|
right: (window_width - cursor_rect.right),
|
|
|
|
bottom: (window_height - cursor_rect.bottom)
|
|
|
|
};
|
|
|
|
|
|
|
|
//Get the width and the height of the tooltip
|
|
|
|
var tooltip_width = tooltip_div.width();
|
|
|
|
if (tooltip_width > 300) tooltip_width = 300;
|
|
|
|
var tooltip_height = tooltip_div.height();
|
|
|
|
|
|
|
|
if (space_left.right < tooltip_width) {
|
2014-11-27 18:38:37 +01:00
|
|
|
tooltip_div.css('left', Math.max(0,cursor_rect.left - tooltip_width));
|
2012-03-06 14:22:01 +01:00
|
|
|
} else if (space_left.left >= tooltip_width) {
|
|
|
|
tooltip_div.css('left', cursor_rect.right);
|
|
|
|
} else {
|
|
|
|
tooltip_div.css('left', cursor_rect.right);
|
|
|
|
tooltip_div.css('max-width', space_left.right);
|
|
|
|
}
|
|
|
|
|
2016-05-07 18:56:18 +02:00
|
|
|
// tooltip does fit neither above nor below: put him vertical centered left or right of cursor
|
|
|
|
if (space_left.bottom < tooltip_height && space_left.top < tooltip_height) {
|
|
|
|
if (tooltip_height > window_height-20) {
|
|
|
|
tooltip_div.css('max-height', tooltip_height=window_height-20);
|
|
|
|
}
|
|
|
|
tooltip_div.css('top', (window_height-tooltip_height)/2);
|
|
|
|
} else if (space_left.bottom < tooltip_height) {
|
2012-03-06 14:22:01 +01:00
|
|
|
tooltip_div.css('top', cursor_rect.top - tooltip_height);
|
2016-05-07 18:56:18 +02:00
|
|
|
} else {
|
2012-03-06 14:22:01 +01:00
|
|
|
tooltip_div.css('top', cursor_rect.bottom);
|
|
|
|
}
|
|
|
|
tooltip_div.fadeIn(100);
|
2022-06-02 17:55:40 +02:00
|
|
|
|
2012-03-06 14:22:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates the tooltip_div with the given text.
|
2016-02-29 16:50:24 +01:00
|
|
|
*
|
|
|
|
* @param {string} _html
|
2017-09-05 19:04:45 +02:00
|
|
|
* @param {boolean} _isHtml if set to true content gets appended as html
|
2012-03-06 14:22:01 +01:00
|
|
|
*/
|
2022-06-02 17:59:43 +02:00
|
|
|
function prepare(_html, _isHtml, _options)
|
2012-03-06 14:22:01 +01:00
|
|
|
{
|
|
|
|
// Free and null the old tooltip_div
|
|
|
|
hide();
|
|
|
|
|
|
|
|
//Generate the tooltip div, set it's text and append it to the body tag
|
2016-06-02 16:51:15 +02:00
|
|
|
tooltip_div = jQuery(_wnd.document.createElement('div'));
|
2012-03-06 14:22:01 +01:00
|
|
|
tooltip_div.hide();
|
2017-09-05 19:04:45 +02:00
|
|
|
if (_isHtml)
|
|
|
|
{
|
|
|
|
tooltip_div.append(_html);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tooltip_div.text(_html)
|
|
|
|
}
|
2012-03-06 14:22:01 +01:00
|
|
|
tooltip_div.addClass("egw_tooltip");
|
2016-06-02 16:51:15 +02:00
|
|
|
jQuery(_wnd.document.body).append(tooltip_div);
|
2012-03-06 14:22:01 +01:00
|
|
|
|
|
|
|
//The tooltip should automatically hide when the mouse comes over it
|
|
|
|
tooltip_div.mouseenter(function() {
|
2022-06-02 17:59:43 +02:00
|
|
|
if (_options.hideonhover) hide();
|
2012-03-06 14:22:01 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* showTooltipTimeout is used to prepare showing the tooltip.
|
|
|
|
*/
|
2022-06-02 17:55:40 +02:00
|
|
|
function showTooltipTimeout(node, event, options)
|
2012-03-06 14:22:01 +01:00
|
|
|
{
|
|
|
|
if (current_elem != null)
|
|
|
|
{
|
|
|
|
show_delta += time_delta;
|
|
|
|
if (show_delta < show_delay)
|
|
|
|
{
|
|
|
|
//Repeat the call of timeout
|
2022-06-02 17:55:40 +02:00
|
|
|
_wnd.setTimeout(function(){showTooltipTimeout(this, event, options)}.bind(node), time_delta);
|
2012-03-06 14:22:01 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
show_delta = 0;
|
2022-06-02 17:55:40 +02:00
|
|
|
show(node, event, options);
|
2012-03-06 14:22:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
/**
|
|
|
|
* Binds a tooltip to the given DOM-Node with the given html.
|
|
|
|
* It is important to remove all tooltips from all elements which are
|
|
|
|
* no longer needed, in order to prevent memory leaks.
|
2016-02-29 16:50:24 +01:00
|
|
|
*
|
2021-07-23 18:18:45 +02:00
|
|
|
* @param _elem is the element to which the tooltip should get bound.
|
2012-03-06 14:22:01 +01:00
|
|
|
* @param _html is the html code which should be shown as tooltip.
|
2022-06-02 17:55:40 +02:00
|
|
|
* @param _options
|
2012-03-06 14:22:01 +01:00
|
|
|
*/
|
2022-06-02 17:55:40 +02:00
|
|
|
tooltipBind: function(_elem, _html, _isHtml, _options) {
|
|
|
|
|
|
|
|
var options = {...optionsDefault, ...(_options||{})};
|
|
|
|
|
2021-07-23 18:18:45 +02:00
|
|
|
_elem = jQuery(_elem);
|
2024-07-27 12:52:14 +02:00
|
|
|
if (_html && !egwIsMobile())
|
2012-03-06 14:22:01 +01:00
|
|
|
{
|
|
|
|
_elem.bind('mouseenter.tooltip', function(e) {
|
|
|
|
if (_elem != current_elem)
|
|
|
|
{
|
|
|
|
//Prepare the tooltip
|
2022-06-02 17:59:43 +02:00
|
|
|
prepare(_html, _isHtml, options);
|
2012-03-06 14:22:01 +01:00
|
|
|
|
|
|
|
// Set the current element the mouse is over and
|
|
|
|
// initialize the position variables
|
|
|
|
current_elem = _elem;
|
|
|
|
show_delta = 0;
|
|
|
|
x = e.clientX;
|
|
|
|
y = e.clientY;
|
2022-06-02 17:55:40 +02:00
|
|
|
let self = this;
|
2012-03-06 14:22:01 +01:00
|
|
|
// Create the timeout for showing the timeout
|
2022-06-02 17:55:40 +02:00
|
|
|
_wnd.setTimeout(function(){showTooltipTimeout(self, e, options)}, time_delta);
|
2012-03-06 14:22:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2022-06-02 17:55:40 +02:00
|
|
|
_elem.bind('mouseleave.tooltip', function(e) {
|
2012-03-06 14:22:01 +01:00
|
|
|
current_elem = null;
|
|
|
|
show_delta = 0;
|
2022-06-02 17:55:40 +02:00
|
|
|
if (options.close.call(this, e, tooltip_div)) return;
|
2012-03-06 14:22:01 +01:00
|
|
|
if (tooltip_div)
|
|
|
|
{
|
|
|
|
tooltip_div.fadeOut(100);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
_elem.bind('mousemove.tooltip', function(e) {
|
|
|
|
//Calculate the distance the mouse took since the last call of mousemove
|
|
|
|
var dx = x - e.clientX;
|
|
|
|
var dy = y - e.clientY;
|
|
|
|
var movedist = Math.sqrt(dx * dx + dy * dy);
|
|
|
|
|
|
|
|
//Block appereance of the tooltip on fast movements (with small movedistances)
|
|
|
|
if (movedist > 2)
|
|
|
|
{
|
|
|
|
show_delta = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
x = e.clientX;
|
|
|
|
y = e.clientY;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unbinds the tooltip from the given DOM-Node.
|
2016-02-29 16:50:24 +01:00
|
|
|
*
|
2012-03-06 14:22:01 +01:00
|
|
|
* @param _elem is the element from which the tooltip should get
|
|
|
|
* removed. _elem has to be a jQuery node.
|
|
|
|
*/
|
|
|
|
tooltipUnbind: function(_elem) {
|
2021-07-23 18:18:45 +02:00
|
|
|
_elem = jQuery(_elem);
|
2022-06-02 17:55:40 +02:00
|
|
|
if (current_elem == _elem) {
|
2012-03-06 14:22:01 +01:00
|
|
|
hide();
|
|
|
|
current_elem = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unbind all "tooltip" events from the given element
|
|
|
|
_elem.unbind('.tooltip');
|
2022-06-02 17:55:40 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
tooltipDestroy: function () {
|
|
|
|
if (tooltip_div)
|
|
|
|
{
|
|
|
|
tooltip_div.fadeOut(100);
|
|
|
|
tooltip_div.remove();
|
|
|
|
}
|
2023-09-13 22:05:50 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hide tooltip, cancel the timer
|
|
|
|
*/
|
|
|
|
tooltipCancel: function ()
|
|
|
|
{
|
|
|
|
hide();
|
|
|
|
current_elem = null;
|
2012-03-06 14:22:01 +01:00
|
|
|
}
|
2016-02-29 16:50:24 +01:00
|
|
|
};
|
2012-03-06 14:22:01 +01:00
|
|
|
|
2024-07-27 12:52:14 +02:00
|
|
|
});
|