--- /dev/null
+/* ==========================================================
+ * bootstrap-twipsy.js v1.4.0
+ * http://twitter.github.com/bootstrap/javascript.html#twipsy
+ * Adapted from the original jQuery.tipsy by Jason Frame
+ * ==========================================================
+ * Copyright 2011 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================== */
+
+
+!function( $ ) {
+
+ "use strict"
+
+ /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
+ * ======================================================= */
+
+ var transitionEnd
+
+ $(document).ready(function () {
+
+ $.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
+ })()
+
+ // 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 pos
+ , actualWidth
+ , actualHeight
+ , placement
+ , $tip
+ , tp
+
+ if (this.hasContent() && this.enabled) {
+ $tip = this.tip()
+ this.setContent()
+
+ if (this.options.animate) {
+ $tip.addClass('fade')
+ }
+
+ $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, [ $tip[0], 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('in')
+ }
+ }
+
+ , setContent: function () {
+ var $tip = this.tip()
+ $tip.find('.twipsy-inner')[this.options.html ? 'html' : 'text'](this.getTitle())
+ $tip[0].className = 'twipsy'
+ }
+
+ , hide: function() {
+ var that = this
+ , $tip = this.tip()
+
+ $tip.removeClass('in')
+
+ function removeElement () {
+ $tip.remove()
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $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')
+ }
+ }
+
+ , hasContent: function () {
+ return this.getTitle()
+ }
+
+ , 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() {
+ return this.$tip = this.$tip || $('<div class="twipsy" />').html(this.options.template)
+ }
+
+ , 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
+ }
+
+ , toggle: function () {
+ this[this.tip().hasClass('in') ? 'hide' : 'show']()
+ }
+
+ }
+
+
+ /* TWIPSY PRIVATE METHODS
+ * ====================== */
+
+ function maybeCall ( thing, ctx, args ) {
+ return typeof thing == 'function' ? thing.apply(ctx, args) : thing
+ }
+
+ /* TWIPSY PLUGIN DEFINITION
+ * ======================== */
+
+ $.fn.twipsy = function (options) {
+ $.fn.twipsy.initWith.call(this, options, Twipsy, 'twipsy')
+ return this
+ }
+
+ $.fn.twipsy.initWith = function (options, Constructor, name) {
+ var twipsy
+ , binder
+ , eventIn
+ , eventOut
+
+ if (options === true) {
+ return this.data(name)
+ } else if (typeof options == 'string') {
+ twipsy = this.data(name)
+ if (twipsy) {
+ twipsy[options]()
+ }
+ return this
+ }
+
+ options = $.extend({}, $.fn[name].defaults, options)
+
+ function get(ele) {
+ var twipsy = $.data(ele, name)
+
+ if (!twipsy) {
+ twipsy = new Constructor(ele, $.fn.twipsy.elementOptions(ele, options))
+ $.data(ele, name, 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.Twipsy = Twipsy
+
+ $.fn.twipsy.defaults = {
+ animate: true
+ , delayIn: 0
+ , delayOut: 0
+ , fallback: ''
+ , placement: 'above'
+ , html: false
+ , live: false
+ , offset: 0
+ , title: 'title'
+ , trigger: 'hover'
+ , template: '<div class="twipsy-arrow"></div><div class="twipsy-inner"></div>'
+ }
+
+ $.fn.twipsy.rejectAttrOptions = [ 'title' ]
+
+ $.fn.twipsy.elementOptions = function(ele, options) {
+ var data = $(ele).data()
+ , rejects = $.fn.twipsy.rejectAttrOptions
+ , i = rejects.length
+
+ while (i--) {
+ delete data[rejects[i]]
+ }
+
+ return $.extend({}, options, data)
+ }
+
+}( window.jQuery || window.ender );
\ No newline at end of file