/* Based on the original tipsy by Jason Frame */ (function( $ ) { /* CSS TRANSITION SUPPORT (https://gist.github.com/373874) * ======================================================= */ $.support.transition = (function () { var thisBody = document.body || document.documentElement , thisStyle = thisBody.style , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined return support })() /* SHARED VARS * =========== */ var transitionEnd // set CSS transition event type if ( $.support.transition ) { transitionEnd = "TransitionEnd" if ( $.browser.webkit ) { transitionEnd = "webkitTransitionEnd" } else if ( $.browser.mozilla ) { transitionEnd = "transitionend" } else if ( $.browser.opera ) { transitionEnd = "oTransitionEnd" } } /* TWIPSY PUBLIC CLASS DEFINITION * ============================== */ var Twipsy = function ( element, options ) { this.$element = $(element) this.options = options this.enabled = true this.fixTitle() } Twipsy.prototype = { show: function() { var title = this.getTitle() , pos , actualWidth , actualHeight , placement , $tip , tp if (title && this.enabled) { $tip = this.tip() $tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](title) $tip[0].className = 'twipsy' $tip .remove() .css({ top: 0, left: 0, display: 'block' }) .prependTo(document.body) pos = $.extend({}, this.$element.offset(), { width: this.$element[0].offsetWidth , height: this.$element[0].offsetHeight }) actualWidth = $tip[0].offsetWidth actualHeight = $tip[0].offsetHeight placement = _.maybeCall(this.options.placement, this.$element[0]) switch (placement) { case 'below': tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2} break case 'above': tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2} break case 'left': tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset} break case 'right': tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset} break } $tip .css(tp) .addClass(placement) .addClass('show') } } , hide: function() { var that = this , $tip = this.tip() $tip.removeClass('show') function removeElement () { $tip.remove() } $.support.transition ? $tip.bind(transitionEnd, removeElement) : removeElement() } , fixTitle: function() { var $e = this.$element if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') } } , getTitle: function() { var title , $e = this.$element , o = this.options this.fixTitle() if (typeof o.title == 'string') { title = $e.attr(o.title == 'title' ? 'data-original-title' : o.title) } else if (typeof o.title == 'function') { title = o.title.call($e[0]) } title = ('' + title).replace(/(^\s*|\s*$)/, "") return title || o.fallback } , tip: function() { if (!this.$tip) { this.$tip = $('
').html('') } return this.$tip } , validate: function() { if (!this.$element[0].parentNode) { this.hide() this.$element = null this.options = null } } , enable: function() { this.enabled = true } , disable: function() { this.enabled = false } , toggleEnabled: function() { this.enabled = !this.enabled } } /* TWIPSY PRIVATE METHODS * ====================== */ var _ = { maybeCall: function ( thing, ctx ) { return (typeof thing == 'function') ? (thing.call(ctx)) : thing } } /* MODAL PLUGIN DEFINITION * ======================= */ $.fn.twipsy = function(options) { var twipsy , binder , eventIn , eventOut if (options === true) { return this.data('twipsy') } else if (typeof options == 'string') { twipsy = this.data('twipsy') if (twipsy) { twipsy[options]() } return this } options = $.extend({}, $.fn.twipsy.defaults, options) function get(ele) { var twipsy = $.data(ele, 'twipsy') if (!twipsy) { twipsy = new Twipsy(ele, $.fn.twipsy.elementOptions(ele, options)) $.data(ele, 'twipsy', twipsy) } return twipsy } function enter() { var twipsy = get(this) twipsy.hoverState = 'in' if (options.delayIn == 0) { twipsy.show() } else { twipsy.fixTitle() setTimeout(function() { if (twipsy.hoverState == 'in') { twipsy.show() } }, options.delayIn) } } function leave() { var twipsy = get(this) twipsy.hoverState = 'out' if (options.delayOut == 0) { twipsy.hide() } else { setTimeout(function() { if (twipsy.hoverState == 'out') { twipsy.hide() } }, options.delayOut) } } if (!options.live) { this.each(function() { get(this) }) } if (options.trigger != 'manual') { binder = options.live ? 'live' : 'bind' eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus' eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur' this[binder](eventIn, enter)[binder](eventOut, leave) } return this } $.fn.twipsy.defaults = { delayIn: 0 , delayOut: 0 , fallback: '' , placement: 'above' , html: false , live: false , offset: 0 , title: 'title' , trigger: 'hover' } $.fn.twipsy.elementOptions = function(ele, options) { return $.metadata ? $.extend({}, options, $(ele).metadata()) : options } })( jQuery || ender )