I am writing my own tooltip plugin for my portfolio website that I am currently working on. It works rather well, however, I feel that there is a lot I could improve. This is one of my bigger jQuery plugins that I have written.
(function($) {
// Used as a template for addTooltip()
var tooltipDefaults = {
'class': null,
'showOn': 'mouseenter',
'hideOn': 'mouseleave',
'direction': 'top',
'offset': null
}
// Store generated IDs to avoid conflicting IDs
var tooltipIds = new Array();
// Keep track of displayed popups
var displayedTooltips = new Array();
function generateUniqueId()
{
var id;
do {
id = Math.floor(Math.random()*90000) + 10000;
} while ($.inArray(id, tooltipIds) !== -1);
tooltipIds.push(id);
return id;
}
function getUniqueId(id)
{
return parseInt(id.substr(0, 5));
}
function isUniqueId(id)
{
return !NaN(getUniqueId(id));
}
function removeUniqueId(id)
{
var id = getUniqueId(id);
var idIndex = $.inArray(id, tooltipIds);
if (idIndex !== -1) {
tooltipIds.splice(idIndex);
}
}
$.fn.displayTooltip = function()
{
var element = $(this);
var tooltip = $('#' + element.attr('data-tooltip-id'));
var config = element.data('config');
var offset = element.offset();
var left;
var top;
switch (config.direction) {
case 'left':
top = offset.top + "px";
left = offset.left - tooltip.outerWidth() - config.offset + "px";
break;
case 'top':
top = offset.top - element.outerHeight() - config.offset + "px";
left = offset.left + ((element.outerWidth() / 2) - (tooltip.outerWidth() / 2)) + "px";
break;
case 'right':
top = offset.top + "px";
left = offset.left + element.outerWidth() + config.offset + "px";
break;
case 'bottom':
top = offset.top + element.outerHeight() + config.offset + "px";
left = offset.left + ((element.outerWidth() / 2) - (tooltip.outerWidth() / 2)) + "px";
break;
}
tooltip.css({
'position': 'absolute',
'left': left,
'top': top,
'z-index': 5000
});
if (element.isTooltipDisplayed()) {
return;
}
tooltip.show();
displayedTooltips.push(element.attr('id'));
}
$.fn.hideTooltip = function()
{
var element = $(this);
var idIndex = $.inArray(element.attr('id'), displayedTooltips);
if (idIndex !== -1) {
displayedTooltips.splice(idIndex);
}
$('#' + element.attr('data-tooltip-id')).hide();
}
$.fn.addTooltip = function(content, params)
{
var config = $.extend(tooltipDefaults, params);
return this.each(function() {
var element = $(this);
// If the element already has a tooltip change the content inside of it
if (element.hasTooltip()) {
$('#' + element.attr('data-tooltip-id')).html(content);
return;
}
var tooltipId = (element.is('[id]') ? element.attr('id') : generateUniqueId()) + '-tooltip';
element.attr('data-tooltip-id', tooltipId);
var tooltip = $('<div>', {
id: tooltipId,
role: 'tooltip',
class: config.class
}).html(content);
$('body').append(tooltip);
/**
* If showOn and hideOn are the same events bind a toggle
* listener else bind the individual listeners
*/
if (config.showOn === config.hideOn) {
element.on(config.showOn, function() {
if (!element.isTooltipDisplayed()) {
element.displayTooltip();
} else {
element.hideTooltip();
}
});
} else {
element.on(config.showOn, function() {
element.displayTooltip();
}).on(config.hideOn, function() {
element.hideTooltip();
});
}
// Store config for other functions use
element.data('config', config);
// Saftey check incase the element recieved focus from the code running above
element.hideTooltip();
});
}
$.fn.hasTooltip = function()
{
return $(this).is('[data-tooltip-id]');
}
$.fn.isTooltipDisplayed = function()
{
var element = $(this);
if (!element.hasTooltip()) {
return false;
}
return ($.inArray(element.attr('id'), displayedTooltips) === -1) ? false : true;
}
$.fn.removeTooltip= function()
{
return this.each(function() {
var element = $(this);
var tooltipId = element.attr('data-tooltip-id');
var config = element.data('config');
$('#' + tooltipId).remove();
if (isUniqueId(tooltpId)) {
removeUniqueId(tooltipId);
}
element.removeAttr('data-tooltip-id');
if (config.showOn === config.hideOn) {
element.off(config.showOn);
} else {
element.off(config.showOn);
element.off(config.hideOn);
}
element.removeData('config');
});
}
// Reposition tooltip on window resize
$(window).on('resize', function() {
if (displayedTooltips.length < 1) {
return;
}
for (var i = 0; i < displayedTooltips.length; i++) {
$('#' + displayedTooltips[i]).displayTooltip();
console.log(displayedTooltips);
}
});
}(jQuery));
new Array()
->[]
\$\endgroup\$if (element.isTooltipDisplayed()) { return; }
could probably called before all left & top calculations... \$\endgroup\$indexOf()
\$\endgroup\$