js/bootstrap-tooltip.js
changeset 0 ba8ab09f730e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/bootstrap-tooltip.js	Fri Jul 04 16:42:41 2014 +0400
     1.3 @@ -0,0 +1,361 @@
     1.4 +/* ===========================================================
     1.5 + * bootstrap-tooltip.js v2.3.1
     1.6 + * http://twitter.github.com/bootstrap/javascript.html#tooltips
     1.7 + * Inspired by the original jQuery.tipsy by Jason Frame
     1.8 + * ===========================================================
     1.9 + * Copyright 2012 Twitter, Inc.
    1.10 + *
    1.11 + * Licensed under the Apache License, Version 2.0 (the "License");
    1.12 + * you may not use this file except in compliance with the License.
    1.13 + * You may obtain a copy of the License at
    1.14 + *
    1.15 + * http://www.apache.org/licenses/LICENSE-2.0
    1.16 + *
    1.17 + * Unless required by applicable law or agreed to in writing, software
    1.18 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.19 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.20 + * See the License for the specific language governing permissions and
    1.21 + * limitations under the License.
    1.22 + * ========================================================== */
    1.23 +
    1.24 +
    1.25 +!function ($) {
    1.26 +
    1.27 +  "use strict"; // jshint ;_;
    1.28 +
    1.29 +
    1.30 + /* TOOLTIP PUBLIC CLASS DEFINITION
    1.31 +  * =============================== */
    1.32 +
    1.33 +  var Tooltip = function (element, options) {
    1.34 +    this.init('tooltip', element, options)
    1.35 +  }
    1.36 +
    1.37 +  Tooltip.prototype = {
    1.38 +
    1.39 +    constructor: Tooltip
    1.40 +
    1.41 +  , init: function (type, element, options) {
    1.42 +      var eventIn
    1.43 +        , eventOut
    1.44 +        , triggers
    1.45 +        , trigger
    1.46 +        , i
    1.47 +
    1.48 +      this.type = type
    1.49 +      this.$element = $(element)
    1.50 +      this.options = this.getOptions(options)
    1.51 +      this.enabled = true
    1.52 +
    1.53 +      triggers = this.options.trigger.split(' ')
    1.54 +
    1.55 +      for (i = triggers.length; i--;) {
    1.56 +        trigger = triggers[i]
    1.57 +        if (trigger == 'click') {
    1.58 +          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
    1.59 +        } else if (trigger != 'manual') {
    1.60 +          eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
    1.61 +          eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
    1.62 +          this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
    1.63 +          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
    1.64 +        }
    1.65 +      }
    1.66 +
    1.67 +      this.options.selector ?
    1.68 +        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
    1.69 +        this.fixTitle()
    1.70 +    }
    1.71 +
    1.72 +  , getOptions: function (options) {
    1.73 +      options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
    1.74 +
    1.75 +      if (options.delay && typeof options.delay == 'number') {
    1.76 +        options.delay = {
    1.77 +          show: options.delay
    1.78 +        , hide: options.delay
    1.79 +        }
    1.80 +      }
    1.81 +
    1.82 +      return options
    1.83 +    }
    1.84 +
    1.85 +  , enter: function (e) {
    1.86 +      var defaults = $.fn[this.type].defaults
    1.87 +        , options = {}
    1.88 +        , self
    1.89 +
    1.90 +      this._options && $.each(this._options, function (key, value) {
    1.91 +        if (defaults[key] != value) options[key] = value
    1.92 +      }, this)
    1.93 +
    1.94 +      self = $(e.currentTarget)[this.type](options).data(this.type)
    1.95 +
    1.96 +      if (!self.options.delay || !self.options.delay.show) return self.show()
    1.97 +
    1.98 +      clearTimeout(this.timeout)
    1.99 +      self.hoverState = 'in'
   1.100 +      this.timeout = setTimeout(function() {
   1.101 +        if (self.hoverState == 'in') self.show()
   1.102 +      }, self.options.delay.show)
   1.103 +    }
   1.104 +
   1.105 +  , leave: function (e) {
   1.106 +      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
   1.107 +
   1.108 +      if (this.timeout) clearTimeout(this.timeout)
   1.109 +      if (!self.options.delay || !self.options.delay.hide) return self.hide()
   1.110 +
   1.111 +      self.hoverState = 'out'
   1.112 +      this.timeout = setTimeout(function() {
   1.113 +        if (self.hoverState == 'out') self.hide()
   1.114 +      }, self.options.delay.hide)
   1.115 +    }
   1.116 +
   1.117 +  , show: function () {
   1.118 +      var $tip
   1.119 +        , pos
   1.120 +        , actualWidth
   1.121 +        , actualHeight
   1.122 +        , placement
   1.123 +        , tp
   1.124 +        , e = $.Event('show')
   1.125 +
   1.126 +      if (this.hasContent() && this.enabled) {
   1.127 +        this.$element.trigger(e)
   1.128 +        if (e.isDefaultPrevented()) return
   1.129 +        $tip = this.tip()
   1.130 +        this.setContent()
   1.131 +
   1.132 +        if (this.options.animation) {
   1.133 +          $tip.addClass('fade')
   1.134 +        }
   1.135 +
   1.136 +        placement = typeof this.options.placement == 'function' ?
   1.137 +          this.options.placement.call(this, $tip[0], this.$element[0]) :
   1.138 +          this.options.placement
   1.139 +
   1.140 +        $tip
   1.141 +          .detach()
   1.142 +          .css({ top: 0, left: 0, display: 'block' })
   1.143 +
   1.144 +        this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
   1.145 +
   1.146 +        pos = this.getPosition()
   1.147 +
   1.148 +        actualWidth = $tip[0].offsetWidth
   1.149 +        actualHeight = $tip[0].offsetHeight
   1.150 +
   1.151 +        switch (placement) {
   1.152 +          case 'bottom':
   1.153 +            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
   1.154 +            break
   1.155 +          case 'top':
   1.156 +            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
   1.157 +            break
   1.158 +          case 'left':
   1.159 +            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
   1.160 +            break
   1.161 +          case 'right':
   1.162 +            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
   1.163 +            break
   1.164 +        }
   1.165 +
   1.166 +        this.applyPlacement(tp, placement)
   1.167 +        this.$element.trigger('shown')
   1.168 +      }
   1.169 +    }
   1.170 +
   1.171 +  , applyPlacement: function(offset, placement){
   1.172 +      var $tip = this.tip()
   1.173 +        , width = $tip[0].offsetWidth
   1.174 +        , height = $tip[0].offsetHeight
   1.175 +        , actualWidth
   1.176 +        , actualHeight
   1.177 +        , delta
   1.178 +        , replace
   1.179 +
   1.180 +      $tip
   1.181 +        .offset(offset)
   1.182 +        .addClass(placement)
   1.183 +        .addClass('in')
   1.184 +
   1.185 +      actualWidth = $tip[0].offsetWidth
   1.186 +      actualHeight = $tip[0].offsetHeight
   1.187 +
   1.188 +      if (placement == 'top' && actualHeight != height) {
   1.189 +        offset.top = offset.top + height - actualHeight
   1.190 +        replace = true
   1.191 +      }
   1.192 +
   1.193 +      if (placement == 'bottom' || placement == 'top') {
   1.194 +        delta = 0
   1.195 +
   1.196 +        if (offset.left < 0){
   1.197 +          delta = offset.left * -2
   1.198 +          offset.left = 0
   1.199 +          $tip.offset(offset)
   1.200 +          actualWidth = $tip[0].offsetWidth
   1.201 +          actualHeight = $tip[0].offsetHeight
   1.202 +        }
   1.203 +
   1.204 +        this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
   1.205 +      } else {
   1.206 +        this.replaceArrow(actualHeight - height, actualHeight, 'top')
   1.207 +      }
   1.208 +
   1.209 +      if (replace) $tip.offset(offset)
   1.210 +    }
   1.211 +
   1.212 +  , replaceArrow: function(delta, dimension, position){
   1.213 +      this
   1.214 +        .arrow()
   1.215 +        .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
   1.216 +    }
   1.217 +
   1.218 +  , setContent: function () {
   1.219 +      var $tip = this.tip()
   1.220 +        , title = this.getTitle()
   1.221 +
   1.222 +      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
   1.223 +      $tip.removeClass('fade in top bottom left right')
   1.224 +    }
   1.225 +
   1.226 +  , hide: function () {
   1.227 +      var that = this
   1.228 +        , $tip = this.tip()
   1.229 +        , e = $.Event('hide')
   1.230 +
   1.231 +      this.$element.trigger(e)
   1.232 +      if (e.isDefaultPrevented()) return
   1.233 +
   1.234 +      $tip.removeClass('in')
   1.235 +
   1.236 +      function removeWithAnimation() {
   1.237 +        var timeout = setTimeout(function () {
   1.238 +          $tip.off($.support.transition.end).detach()
   1.239 +        }, 500)
   1.240 +
   1.241 +        $tip.one($.support.transition.end, function () {
   1.242 +          clearTimeout(timeout)
   1.243 +          $tip.detach()
   1.244 +        })
   1.245 +      }
   1.246 +
   1.247 +      $.support.transition && this.$tip.hasClass('fade') ?
   1.248 +        removeWithAnimation() :
   1.249 +        $tip.detach()
   1.250 +
   1.251 +      this.$element.trigger('hidden')
   1.252 +
   1.253 +      return this
   1.254 +    }
   1.255 +
   1.256 +  , fixTitle: function () {
   1.257 +      var $e = this.$element
   1.258 +      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
   1.259 +        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
   1.260 +      }
   1.261 +    }
   1.262 +
   1.263 +  , hasContent: function () {
   1.264 +      return this.getTitle()
   1.265 +    }
   1.266 +
   1.267 +  , getPosition: function () {
   1.268 +      var el = this.$element[0]
   1.269 +      return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
   1.270 +        width: el.offsetWidth
   1.271 +      , height: el.offsetHeight
   1.272 +      }, this.$element.offset())
   1.273 +    }
   1.274 +
   1.275 +  , getTitle: function () {
   1.276 +      var title
   1.277 +        , $e = this.$element
   1.278 +        , o = this.options
   1.279 +
   1.280 +      title = $e.attr('data-original-title')
   1.281 +        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
   1.282 +
   1.283 +      return title
   1.284 +    }
   1.285 +
   1.286 +  , tip: function () {
   1.287 +      return this.$tip = this.$tip || $(this.options.template)
   1.288 +    }
   1.289 +
   1.290 +  , arrow: function(){
   1.291 +      return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
   1.292 +    }
   1.293 +
   1.294 +  , validate: function () {
   1.295 +      if (!this.$element[0].parentNode) {
   1.296 +        this.hide()
   1.297 +        this.$element = null
   1.298 +        this.options = null
   1.299 +      }
   1.300 +    }
   1.301 +
   1.302 +  , enable: function () {
   1.303 +      this.enabled = true
   1.304 +    }
   1.305 +
   1.306 +  , disable: function () {
   1.307 +      this.enabled = false
   1.308 +    }
   1.309 +
   1.310 +  , toggleEnabled: function () {
   1.311 +      this.enabled = !this.enabled
   1.312 +    }
   1.313 +
   1.314 +  , toggle: function (e) {
   1.315 +      var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
   1.316 +      self.tip().hasClass('in') ? self.hide() : self.show()
   1.317 +    }
   1.318 +
   1.319 +  , destroy: function () {
   1.320 +      this.hide().$element.off('.' + this.type).removeData(this.type)
   1.321 +    }
   1.322 +
   1.323 +  }
   1.324 +
   1.325 +
   1.326 + /* TOOLTIP PLUGIN DEFINITION
   1.327 +  * ========================= */
   1.328 +
   1.329 +  var old = $.fn.tooltip
   1.330 +
   1.331 +  $.fn.tooltip = function ( option ) {
   1.332 +    return this.each(function () {
   1.333 +      var $this = $(this)
   1.334 +        , data = $this.data('tooltip')
   1.335 +        , options = typeof option == 'object' && option
   1.336 +      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
   1.337 +      if (typeof option == 'string') data[option]()
   1.338 +    })
   1.339 +  }
   1.340 +
   1.341 +  $.fn.tooltip.Constructor = Tooltip
   1.342 +
   1.343 +  $.fn.tooltip.defaults = {
   1.344 +    animation: true
   1.345 +  , placement: 'top'
   1.346 +  , selector: false
   1.347 +  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
   1.348 +  , trigger: 'hover focus'
   1.349 +  , title: ''
   1.350 +  , delay: 0
   1.351 +  , html: false
   1.352 +  , container: false
   1.353 +  }
   1.354 +
   1.355 +
   1.356 + /* TOOLTIP NO CONFLICT
   1.357 +  * =================== */
   1.358 +
   1.359 +  $.fn.tooltip.noConflict = function () {
   1.360 +    $.fn.tooltip = old
   1.361 +    return this
   1.362 +  }
   1.363 +
   1.364 +}(window.jQuery);