text: /*
   * bubbletip
   *
   * Copyright (c) 2009, UhLeeKa
   * Version:
   *      1.0.4
   * Licensed under the GPL license:
   *     http://www.gnu.org/licenses/gpl.html
   * Author Website:
   *     http://www.uhleeka.com
   * Description:
   *     A bubble-styled tooltip extension
   *      - multiple tips on a page
   *      - multiple tips per jQuery element
   *      - tips open outward in four directions:
   *         - up
   *         - down
   *         - left
   *         - right
   *      - tips can be:
   *         - anchored to the triggering jQuery element
   *         - absolutely positioned
   *         - opened at the current mouse coordinates
   *         - anchored to a specified jQuery element
   *      - IE png transparency is handled via filters
   */
  ; (function($) {
    var bindIndex = 0;
    $.fn.extend({
      bubbletip: function(tip, options) {
        // check to see if the tip is a descendant of
        // a table.bubbletip element and therefore
        // has already been instantiated as a bubbletip
        if ($('table.bubbletip #' + $(tip).id).length > 0) {
          return this;
        }
  
        var _this, _tip, _options, _calc, _timeoutAnimate, _timeoutRefresh, _isActive, _isHiding, _wrapper, _bindIndex;
  
        _this = $(this);
        _tip = $(tip);
        _bindIndex = bindIndex++;  // for window.resize namespace binding
        _options = {
          positionAt: 'element', // element | body | mouse
          positionAtElement: _this,
          offsetTop: 0,
          offsetLeft: 0,
          deltaPosition: 30,
          deltaDirection: 'up', // direction: up | down | left | right
          animationDuration: 250,
          animationEasing: 'swing', // linear | swing
          bindShow: 'mouseover', // mouseover | focus | click | etc.
          bindHide: 'mouseout', // mouseout | blur | etc.
          delayShow: 0,
          delayHide: 500
        };
        if (options) {
          _options = $.extend(_options, options);
        }
        // calculated values
        _calc = {
          top: 0,
          left: 0,
          delta: 0,
          mouseTop: 0,
          mouseLeft: 0,
          tipHeight: 0,
          bindShow: (_options.bindShow + ' ').replace(/ +/g, '.bubbletip' + _bindIndex),
          bindHide: (_options.bindHide + ' ').replace(/ +/g, '.bubbletip' + _bindIndex)
        };
        _timeoutAnimate = null;
        _timeoutRefresh = null;
        _isActive = false;
        _isHiding = false;
  
        // store the tip id for removeBubbletip
        if (!_this.data('bubbletip_tips')) {
          _this.data('bubbletip_tips', [[_tip.get(0).id, _calc.bindShow, _calc.bindHide, _bindIndex]]);
        } else {
          _this.data('bubbletip_tips', $.merge(_this.data('bubbletip_tips'), [[_tip.get(0).id, _calc.bindShow, _calc.bindHide, _bindIndex]]));
        }
  
  
        // validate _options
        if (!_options.positionAt.match(/^element|body|mouse$/i)) {
          _options.positionAt = 'element';
        }
        if (!_options.deltaDirection.match(/^up|down|left|right$/i)) {
          _options.deltaDirection = 'up';
        }
  
        // create the wrapper table element
        if (_options.deltaDirection.match(/^up$/i)) {
          _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-content"></td><td class="bt-right"></td></tr><tr><td class="bt-bottomleft"></td><td><table class="bt-bottom" cellspacing="0" cellpadding="0"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class="bt-bottomright"></td></tr></tbody></table>');
        } else if (_options.deltaDirection.match(/^down$/i)) {
          _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td><table class="bt-top" cellspacing="0" cellpadding="0"><tr><th></th><td><div></div></td><th></th></tr></table></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-content"></td><td class="bt-right"></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="bt-bottomright"></td></tr></tbody></table>');
        } else if (_options.deltaDirection.match(/^left$/i)) {
          _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="bt-topright"></td></tr><tr><td class="bt-left"></td><td class="bt-content"></td><td class="bt-right-tail"><div class="bt-right"></div><div class="bt-right-tail"></div><div class="bt-right"></div></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="bt-bottomright"></td></tr></tbody></table>');
        } else if (_options.deltaDirection.match(/^right$/i)) {
          _wrapper = $('<table class="bubbletip" cellspacing="0" cellpadding="0"><tbody><tr><td class="bt-topleft"></td><td class="bt-top"></td><td class="bt-topright"></td></tr><tr><td class="bt-left-tail"><div class="bt-left"></div><div class="bt-left-tail"></div><div class="bt-left"></div></td><td class="bt-content"></td><td class="bt-right"></td></tr><tr><td class="bt-bottomleft"></td><td class="bt-bottom"></td><td class="bt-bottomright"></td></tr></tbody></table>');
        }
  
        // append the wrapper to the document body
        _wrapper.appendTo('body');
  
        // apply IE filters to _wrapper elements
        if ((/msie/.test(navigator.userAgent.toLowerCase())) && (!/opera/.test(navigator.userAgent.toLowerCase()))) {
          $('*', _wrapper).each(function() {
            var image = $(this).css('background-image');
            if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) {
              image = RegExp.$1;
              $(this).css({
                'backgroundImage': 'none',
                'filter': 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=' + ($(this).css('backgroundRepeat') == 'no-repeat' ? 'crop' : 'scale') + ', src=\'' + image + '\')'
              }).each(function() {
                var position = $(this).css('position');
                if (position != 'absolute' && position != 'relative')
                  $(this).css('position', 'relative');
              });
            }
          });
        }
  
        // move the tip element into the content section of the wrapper
        $('.bt-content', _wrapper).append(_tip);
        // show the tip (in case it is hidden) so that we can calculate its dimensions
        _tip.show();
        // handle left|right delta
        if (_options.deltaDirection.match(/^left|right$/i)) {
          // tail is 40px, so divide height by two and subtract 20px;
          _calc.tipHeight = parseInt(_tip.height() / 2);
          // handle odd integer height
          if ((_tip.height() % 2) == 1) {
            _calc.tipHeight++;
          }
          _calc.tipHeight = (_calc.tipHeight < 20) ? 1 : _calc.tipHeight - 20;
          if (_options.deltaDirection.match(/^left$/i)) {
            $('div.bt-right', _wrapper).css('height', _calc.tipHeight + 'px');
          } else {
            $('div.bt-left', _wrapper).css('height', _calc.tipHeight + 'px');
          }
        }
        // set the opacity of the wrapper to 0
        _wrapper.css('opacity', 0);
        // execute initial calculations
        _Calculate();
  
        // handle window.resize
        $(window).bind('resize.bubbletip' + _bindIndex, function() {
          if (_timeoutRefresh) {
            clearTimeout(_timeoutRefresh);
          } else {
            _wrapper.hide();
          }
          _timeoutRefresh = setTimeout(function() {
            _Calculate();
          }, 250);
        });
  
        // handle mouseover and mouseout events
        $([_wrapper.get(0), this.get(0)]).bind(_calc.bindShow, function(e) {
          if (_timeoutAnimate) {
            clearTimeout(_timeoutAnimate);
          }
          _timeoutAnimate = setTimeout(function() {
            if (_isActive) {
              return;
            }
            _isActive = true;
            if (_isHiding) {
              _wrapper.stop(true, false);
            }
  
            var animation;
  
            if (_options.positionAt.match(/^element|body$/i)) {
              if (_options.deltaDirection.match(/^up|down$/i)) {
                if (!_isHiding) {
                  _wrapper.css('top', parseInt(_calc.top + _calc.delta) + 'px');
                }
                animation = { 'opacity': 1, 'top': _calc.top + 'px' };
              } else {
                if (!_isHiding) {
                  _wrapper.css('left', parseInt(_calc.left + _calc.delta) + 'px');
                }
                animation = { 'opacity': 1, 'left': _calc.left + 'px' };
              }
            } else {
              if (_options.deltaDirection.match(/^up|down$/i)) {
                if (!_isHiding) {
                  _calc.mouseTop = e.pageY + _calc.top;
                  _wrapper.css({ 'top': parseInt(_calc.mouseTop + _calc.delta) + 'px', 'left': parseInt(e.pageX - (_wrapper.width() / 2)) + 'px' });
                }
                animation = { 'opacity': 1, 'top': _calc.mouseTop + 'px' };
              } else {
                if (!_isHiding) {
                  _calc.mouseLeft = e.pageX + _calc.left;
                  _wrapper.css({ 'left': parseInt(_calc.mouseLeft + _calc.delta) + 'px', 'top': parseInt(e.pageY - (_wrapper.height() / 2)) + 'px' });
                }
                animation = { 'opacity': 1, 'left': _calc.left + 'px' };
              }
            }
            _isHiding = false;
            _wrapper.show();
            _wrapper.animate(animation, _options.animationDuration, _options.animationEasing, function() {
              _wrapper.css('opacity', '');
              _isActive = true;
            });
          }, _options.delayShow);
  
          return false;
        }).bind(_calc.bindHide, function() {
          if (_timeoutAnimate) {
            clearTimeout(_timeoutAnimate);
          }
          _timeoutAnimate = setTimeout(function() {
            var animation;
  
            _isActive = false;
            _isHiding = true;
            if (_options.positionAt.match(/^element|body$/i)) {
              if (_options.deltaDirection.match(/^up|down$/i)) {
                animation = { 'opacity': 0, 'top': parseInt(_calc.top - _calc.delta) + 'px' };
              } else {
                animation = { 'opacity': 0, 'left': parseInt(_calc.left - _calc.delta) + 'px' };
              }
            } else {
              if (_options.deltaDirection.match(/^up|down$/i)) {
                animation = { 'opacity': 0, 'top': parseInt(_calc.mouseTop - _calc.delta) + 'px' };
              } else {
                animation = { 'opacity': 0, 'left': parseInt(_calc.mouseLeft - _calc.delta) + 'px' };
              }
            }
            _wrapper.animate(animation, _options.animationDuration, _options.animationEasing, function() {
              _wrapper.hide();
              _isHiding = false;
            });
  
          }, _options.delayHide);
  
          return false;
        });
  
        function _Calculate() {
          // calculate values
          if (_options.positionAt.match(/^element$/i)) {
            var offset = _options.positionAtElement.offset();
            if (_options.deltaDirection.match(/^up$/i)) {
              _calc.top = offset.top + _options.offsetTop - _wrapper.height();
              _calc.left = offset.left + _options.offsetLeft + ((_options.positionAtElement.width() - _wrapper.width()) / 2);
              _calc.delta = _options.deltaPosition;
            } else if (_options.deltaDirection.match(/^down$/i)) {
              _calc.top = offset.top + _options.positionAtElement.height() + _options.offsetTop;
              _calc.left = offset.left + _options.offsetLeft + ((_options.positionAtElement.width() - _wrapper.width()) / 2);
              _calc.delta = -_options.deltaPosition;
            } else if (_options.deltaDirection.match(/^left$/i)) {
              _calc.top = offset.top + _options.offsetTop + ((_options.positionAtElement.height() - _wrapper.height()) / 2);
              _calc.left = offset.left + _options.offsetLeft - _wrapper.width();
              _calc.delta = _options.deltaPosition;
            } else if (_options.deltaDirection.match(/^right$/i)) {
              _calc.top = offset.top + _options.offsetTop + ((_options.positionAtElement.height() - _wrapper.height()) / 2);
              _calc.left = offset.left + _options.positionAtElement.width() + _options.offsetLeft;
              _calc.delta = -_options.deltaPosition;
            }
          } else if (_options.positionAt.match(/^body$/i)) {
            if (_options.deltaDirection.match(/^up|left$/i)) {
              _calc.top = _options.offsetTop;
              _calc.left = _options.offsetLeft;
              // up or left
              _calc.delta = _options.deltaPosition;
            } else {
              if (_options.deltaDirection.match(/^down$/i)) {
                _calc.top = parseInt(_options.offsetTop + _wrapper.height());
                _calc.left = _options.offsetLeft;
              } else {
                _calc.top = _options.offsetTop;
                _calc.left = parseInt(_options.offsetLeft + _wrapper.width());
              }
              // down or right
              _calc.delta = -_options.deltaPosition;
            }
          } else if (_options.positionAt.match(/^mouse$/i)) {
            if (_options.deltaDirection.match(/^up|left$/i)) {
              if (_options.deltaDirection.match(/^up$/i)) {
                _calc.top = -(_options.offsetTop + _wrapper.height());
                _calc.left = _options.offsetLeft;
              } else if (_options.deltaDirection.match(/^left$/i)) {
                _calc.top = _options.offsetTop;
                _calc.left = -(_options.offsetLeft + _wrapper.width());
              }
              // up or left
              _calc.delta = _options.deltaPosition;
            } else {
              _calc.top = _options.offsetTop;
              _calc.left = _options.offsetLeft;
              // down or right
              _calc.delta = -_options.deltaPosition;
            }
          }
          // hide
          _wrapper.hide();
          // handle the wrapper (element|body) positioning
          if (_options.positionAt.match(/^element|body$/i)) {
            _wrapper.css({
              'position': 'absolute',
              'top': _calc.top + 'px',
              'left': _calc.left + 'px'
            });
          }
        };
        return this;
      },
      removeBubbletip: function(tips) {
        var tipsActive;
        var tipsToRemove = new Array();
        var arr, i, ix;
        var elem;
  
        tipsActive = $.makeArray($(this).data('bubbletip_tips'));
  
        // convert the parameter array of tip id's or elements to id's
        arr = $.makeArray(tips);
        for (i = 0; i < arr.length; i++) {
          tipsToRemove.push($(arr[i]).get(0).id);
        }
  
        for (i = 0; i < tipsActive.length; i++) {
          ix = null;
          if ((tipsToRemove.length == 0) || ((ix = $.inArray(tipsActive[i][0], tipsToRemove)) >= 0)) {
            // remove all tips if there are none specified
            // otherwise, remove only specified tips
  
            // find the surrounding table.bubbletip
            elem = $('#' + tipsActive[i][0]).get(0).parentNode;
            while (elem.tagName.toLowerCase() != 'table') {
              elem = elem.parentNode;
            }
            // attach the tip element to body and hide
            $(tipsActive[i][0]).appendTo('body').hide();
            // remove the surrounding table.bubbletip
            $(elem).remove();
  
            // unbind show/hide events
            $(this).unbind(tipsActive[i][1]).unbind([i][2]);
  
            // unbind window.resize event
            $(window).unbind('resize.bubbletip' + tipsActive[i][3]);
          }
        }
  
        return this;
      }
    });
  })(jQuery);
  