﻿/* ==========================================================
* 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);
