Tonight I decided to revamp some code I wrote a few months ago. One part of that was to do with showing (and hiding) tooltips. The functions are called with:
jQuery(element).showTooltip('HTML');
jQuery(element).hideTooltip();
The old code
$.fn.showTooltip = function(text)
{
/* Remove any existing tooltip. */
$(this).removeTooltip();
/* Generate a unique reference for the tooltip. */
var ref = $(this).attr('name');
/* Create the tooltip and add it after the element. */
$tooltip = $('<span class="tooltip" data-ref="' + ref + '"></span>')
.html(text)
.css('display','none')
.insertAfter($(this))
.fadeIn(animationSpeed);
}
$.fn.removeTooltip = function()
{
var ref = $(this).attr('name');
/* Remove the tooltip. */
$('span[data-ref="' + ref + '"]')
.stop()
.fadeOut(animationSpeed, function() {
$(this).remove();
});
}
This code did the trick, but the were a few occasions where a tooltip either wouldn't appear or disappear when required. Equally the animations were a bit off.
The new revamped code
$.fn.showTooltip = function(html) {
var
/* Create a unique reference to the element to be used in the
* tooltip. */
tooltipRef = $(this).attr('name'),
/* Create a reference to any current tooltip for the element. */
existingTooltip = $('[data-ref="' + tooltipRef + '"]'),
/* Create a variable to be used to hold the new tooltip. */
$tooltip
;
/* If existingTooltip doesn't match an existing object then create
* the new tooltip object, asigning its HTML and hiding it before
* inserting it after the element. */
if(typeof existingTooltip != 'object'
|| typeof existingTooltip.length != 'number'
|| existingTooltip.length === 0)
$tooltip = $('<span class="tooltip"></span>')
.attr('data-ref', tooltipRef)
.html(html)
.hide()
.insertAfter($(this));
/* If existingTooltip is visible and that contains the same html
* which is being passed in then there is no need to recreate. */
else if(existingTooltip.is(':visible')
&& existingTooltip.html() === html)
return;
/* If existingTooltip is visible but does not contain the same html
* then hide existingTooltip then set its HTML and set $tooltip as
* existingTooltip. */
else if(existingTooltip.is(':visible'))
{
$(this).hideTooltip();
$tooltip = existingTooltip;
$tooltip.queue(function() {
$tooltip.html(html);
$(this).dequeue();
});
}
/* If existingTooltip isn't visible but contains the same HTML, set
* $tooltip as existingTooltip. */
else if(existingTooltip.html() === html)
$tooltip = existingTooltip;
/* If existingTooltip isn't visible and doesn't contain the same
* HTML, set its HTML and set $tooltip as existingTooltip. */
else if(existingTooltip.html() !== html)
{
existingTooltip.html(html);
$tooltip = existingTooltip;
}
/* If none of the above applies then something has gone wrong. */
else
return;
/* Ensure any current animation isn't occuring before displaying
* the new (or modified) tooltip. */
$tooltip.queue(function() {
$(this)
.stop()
.fadeIn(global.animationSpeed);
$(this).dequeue();
});
};
$.fn.hideTooltip = function() {
var
/* Get the unique reference from the element to be used to
* get the tooltip object. */
tooltipRef = $(this).attr('name'),
/* Use the above reference to get the tooltip object. */
$tooltip = $('span[data-ref="' + tooltipRef + '"]')
;
/* If there is no tooltip then there is no need to proceed. */
if(typeof $tooltip != 'object'
|| typeof $tooltip.length != 'number'
|| $tooltip.length === 0
|| !$tooltip.is(':visible'))
return;
/* Hide the tooltip. */
$tooltip
.stop()
.fadeOut(global.animationSpeed);
}
The main flaw that I'm currently aware of with this (which I'll sort out tomorrow) is that the element currently requires a name
in order for the tooltip to work.
I think I've covered all bases with the large if
statement within the showTooltip
function, but I'm not sure if maybe I've gone too overboard with it. Is there any way I could condense the code?
I'm certainly no JavaScript expert, so any criticism would be very welcome!
Here's a JSFiddle example: http://jsfiddle.net/UPAXV/
Many thanks.