js/bootstrap-tooltip.js
author indvd00m (gotoindvdum[at]gmail[dot]com)
Fri, 04 Jul 2014 16:42:41 +0400
changeset 0 ba8ab09f730e
permissions -rw-r--r--
First home page
indvd00m@0
     1
/* ===========================================================
indvd00m@0
     2
 * bootstrap-tooltip.js v2.3.1
indvd00m@0
     3
 * http://twitter.github.com/bootstrap/javascript.html#tooltips
indvd00m@0
     4
 * Inspired by the original jQuery.tipsy by Jason Frame
indvd00m@0
     5
 * ===========================================================
indvd00m@0
     6
 * Copyright 2012 Twitter, Inc.
indvd00m@0
     7
 *
indvd00m@0
     8
 * Licensed under the Apache License, Version 2.0 (the "License");
indvd00m@0
     9
 * you may not use this file except in compliance with the License.
indvd00m@0
    10
 * You may obtain a copy of the License at
indvd00m@0
    11
 *
indvd00m@0
    12
 * http://www.apache.org/licenses/LICENSE-2.0
indvd00m@0
    13
 *
indvd00m@0
    14
 * Unless required by applicable law or agreed to in writing, software
indvd00m@0
    15
 * distributed under the License is distributed on an "AS IS" BASIS,
indvd00m@0
    16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
indvd00m@0
    17
 * See the License for the specific language governing permissions and
indvd00m@0
    18
 * limitations under the License.
indvd00m@0
    19
 * ========================================================== */
indvd00m@0
    20
indvd00m@0
    21
indvd00m@0
    22
!function ($) {
indvd00m@0
    23
indvd00m@0
    24
  "use strict"; // jshint ;_;
indvd00m@0
    25
indvd00m@0
    26
indvd00m@0
    27
 /* TOOLTIP PUBLIC CLASS DEFINITION
indvd00m@0
    28
  * =============================== */
indvd00m@0
    29
indvd00m@0
    30
  var Tooltip = function (element, options) {
indvd00m@0
    31
    this.init('tooltip', element, options)
indvd00m@0
    32
  }
indvd00m@0
    33
indvd00m@0
    34
  Tooltip.prototype = {
indvd00m@0
    35
indvd00m@0
    36
    constructor: Tooltip
indvd00m@0
    37
indvd00m@0
    38
  , init: function (type, element, options) {
indvd00m@0
    39
      var eventIn
indvd00m@0
    40
        , eventOut
indvd00m@0
    41
        , triggers
indvd00m@0
    42
        , trigger
indvd00m@0
    43
        , i
indvd00m@0
    44
indvd00m@0
    45
      this.type = type
indvd00m@0
    46
      this.$element = $(element)
indvd00m@0
    47
      this.options = this.getOptions(options)
indvd00m@0
    48
      this.enabled = true
indvd00m@0
    49
indvd00m@0
    50
      triggers = this.options.trigger.split(' ')
indvd00m@0
    51
indvd00m@0
    52
      for (i = triggers.length; i--;) {
indvd00m@0
    53
        trigger = triggers[i]
indvd00m@0
    54
        if (trigger == 'click') {
indvd00m@0
    55
          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
indvd00m@0
    56
        } else if (trigger != 'manual') {
indvd00m@0
    57
          eventIn = trigger == 'hover' ? 'mouseenter' : 'focus'
indvd00m@0
    58
          eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
indvd00m@0
    59
          this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
indvd00m@0
    60
          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
indvd00m@0
    61
        }
indvd00m@0
    62
      }
indvd00m@0
    63
indvd00m@0
    64
      this.options.selector ?
indvd00m@0
    65
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
indvd00m@0
    66
        this.fixTitle()
indvd00m@0
    67
    }
indvd00m@0
    68
indvd00m@0
    69
  , getOptions: function (options) {
indvd00m@0
    70
      options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options)
indvd00m@0
    71
indvd00m@0
    72
      if (options.delay && typeof options.delay == 'number') {
indvd00m@0
    73
        options.delay = {
indvd00m@0
    74
          show: options.delay
indvd00m@0
    75
        , hide: options.delay
indvd00m@0
    76
        }
indvd00m@0
    77
      }
indvd00m@0
    78
indvd00m@0
    79
      return options
indvd00m@0
    80
    }
indvd00m@0
    81
indvd00m@0
    82
  , enter: function (e) {
indvd00m@0
    83
      var defaults = $.fn[this.type].defaults
indvd00m@0
    84
        , options = {}
indvd00m@0
    85
        , self
indvd00m@0
    86
indvd00m@0
    87
      this._options && $.each(this._options, function (key, value) {
indvd00m@0
    88
        if (defaults[key] != value) options[key] = value
indvd00m@0
    89
      }, this)
indvd00m@0
    90
indvd00m@0
    91
      self = $(e.currentTarget)[this.type](options).data(this.type)
indvd00m@0
    92
indvd00m@0
    93
      if (!self.options.delay || !self.options.delay.show) return self.show()
indvd00m@0
    94
indvd00m@0
    95
      clearTimeout(this.timeout)
indvd00m@0
    96
      self.hoverState = 'in'
indvd00m@0
    97
      this.timeout = setTimeout(function() {
indvd00m@0
    98
        if (self.hoverState == 'in') self.show()
indvd00m@0
    99
      }, self.options.delay.show)
indvd00m@0
   100
    }
indvd00m@0
   101
indvd00m@0
   102
  , leave: function (e) {
indvd00m@0
   103
      var self = $(e.currentTarget)[this.type](this._options).data(this.type)
indvd00m@0
   104
indvd00m@0
   105
      if (this.timeout) clearTimeout(this.timeout)
indvd00m@0
   106
      if (!self.options.delay || !self.options.delay.hide) return self.hide()
indvd00m@0
   107
indvd00m@0
   108
      self.hoverState = 'out'
indvd00m@0
   109
      this.timeout = setTimeout(function() {
indvd00m@0
   110
        if (self.hoverState == 'out') self.hide()
indvd00m@0
   111
      }, self.options.delay.hide)
indvd00m@0
   112
    }
indvd00m@0
   113
indvd00m@0
   114
  , show: function () {
indvd00m@0
   115
      var $tip
indvd00m@0
   116
        , pos
indvd00m@0
   117
        , actualWidth
indvd00m@0
   118
        , actualHeight
indvd00m@0
   119
        , placement
indvd00m@0
   120
        , tp
indvd00m@0
   121
        , e = $.Event('show')
indvd00m@0
   122
indvd00m@0
   123
      if (this.hasContent() && this.enabled) {
indvd00m@0
   124
        this.$element.trigger(e)
indvd00m@0
   125
        if (e.isDefaultPrevented()) return
indvd00m@0
   126
        $tip = this.tip()
indvd00m@0
   127
        this.setContent()
indvd00m@0
   128
indvd00m@0
   129
        if (this.options.animation) {
indvd00m@0
   130
          $tip.addClass('fade')
indvd00m@0
   131
        }
indvd00m@0
   132
indvd00m@0
   133
        placement = typeof this.options.placement == 'function' ?
indvd00m@0
   134
          this.options.placement.call(this, $tip[0], this.$element[0]) :
indvd00m@0
   135
          this.options.placement
indvd00m@0
   136
indvd00m@0
   137
        $tip
indvd00m@0
   138
          .detach()
indvd00m@0
   139
          .css({ top: 0, left: 0, display: 'block' })
indvd00m@0
   140
indvd00m@0
   141
        this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
indvd00m@0
   142
indvd00m@0
   143
        pos = this.getPosition()
indvd00m@0
   144
indvd00m@0
   145
        actualWidth = $tip[0].offsetWidth
indvd00m@0
   146
        actualHeight = $tip[0].offsetHeight
indvd00m@0
   147
indvd00m@0
   148
        switch (placement) {
indvd00m@0
   149
          case 'bottom':
indvd00m@0
   150
            tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
indvd00m@0
   151
            break
indvd00m@0
   152
          case 'top':
indvd00m@0
   153
            tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
indvd00m@0
   154
            break
indvd00m@0
   155
          case 'left':
indvd00m@0
   156
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
indvd00m@0
   157
            break
indvd00m@0
   158
          case 'right':
indvd00m@0
   159
            tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
indvd00m@0
   160
            break
indvd00m@0
   161
        }
indvd00m@0
   162
indvd00m@0
   163
        this.applyPlacement(tp, placement)
indvd00m@0
   164
        this.$element.trigger('shown')
indvd00m@0
   165
      }
indvd00m@0
   166
    }
indvd00m@0
   167
indvd00m@0
   168
  , applyPlacement: function(offset, placement){
indvd00m@0
   169
      var $tip = this.tip()
indvd00m@0
   170
        , width = $tip[0].offsetWidth
indvd00m@0
   171
        , height = $tip[0].offsetHeight
indvd00m@0
   172
        , actualWidth
indvd00m@0
   173
        , actualHeight
indvd00m@0
   174
        , delta
indvd00m@0
   175
        , replace
indvd00m@0
   176
indvd00m@0
   177
      $tip
indvd00m@0
   178
        .offset(offset)
indvd00m@0
   179
        .addClass(placement)
indvd00m@0
   180
        .addClass('in')
indvd00m@0
   181
indvd00m@0
   182
      actualWidth = $tip[0].offsetWidth
indvd00m@0
   183
      actualHeight = $tip[0].offsetHeight
indvd00m@0
   184
indvd00m@0
   185
      if (placement == 'top' && actualHeight != height) {
indvd00m@0
   186
        offset.top = offset.top + height - actualHeight
indvd00m@0
   187
        replace = true
indvd00m@0
   188
      }
indvd00m@0
   189
indvd00m@0
   190
      if (placement == 'bottom' || placement == 'top') {
indvd00m@0
   191
        delta = 0
indvd00m@0
   192
indvd00m@0
   193
        if (offset.left < 0){
indvd00m@0
   194
          delta = offset.left * -2
indvd00m@0
   195
          offset.left = 0
indvd00m@0
   196
          $tip.offset(offset)
indvd00m@0
   197
          actualWidth = $tip[0].offsetWidth
indvd00m@0
   198
          actualHeight = $tip[0].offsetHeight
indvd00m@0
   199
        }
indvd00m@0
   200
indvd00m@0
   201
        this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
indvd00m@0
   202
      } else {
indvd00m@0
   203
        this.replaceArrow(actualHeight - height, actualHeight, 'top')
indvd00m@0
   204
      }
indvd00m@0
   205
indvd00m@0
   206
      if (replace) $tip.offset(offset)
indvd00m@0
   207
    }
indvd00m@0
   208
indvd00m@0
   209
  , replaceArrow: function(delta, dimension, position){
indvd00m@0
   210
      this
indvd00m@0
   211
        .arrow()
indvd00m@0
   212
        .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
indvd00m@0
   213
    }
indvd00m@0
   214
indvd00m@0
   215
  , setContent: function () {
indvd00m@0
   216
      var $tip = this.tip()
indvd00m@0
   217
        , title = this.getTitle()
indvd00m@0
   218
indvd00m@0
   219
      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
indvd00m@0
   220
      $tip.removeClass('fade in top bottom left right')
indvd00m@0
   221
    }
indvd00m@0
   222
indvd00m@0
   223
  , hide: function () {
indvd00m@0
   224
      var that = this
indvd00m@0
   225
        , $tip = this.tip()
indvd00m@0
   226
        , e = $.Event('hide')
indvd00m@0
   227
indvd00m@0
   228
      this.$element.trigger(e)
indvd00m@0
   229
      if (e.isDefaultPrevented()) return
indvd00m@0
   230
indvd00m@0
   231
      $tip.removeClass('in')
indvd00m@0
   232
indvd00m@0
   233
      function removeWithAnimation() {
indvd00m@0
   234
        var timeout = setTimeout(function () {
indvd00m@0
   235
          $tip.off($.support.transition.end).detach()
indvd00m@0
   236
        }, 500)
indvd00m@0
   237
indvd00m@0
   238
        $tip.one($.support.transition.end, function () {
indvd00m@0
   239
          clearTimeout(timeout)
indvd00m@0
   240
          $tip.detach()
indvd00m@0
   241
        })
indvd00m@0
   242
      }
indvd00m@0
   243
indvd00m@0
   244
      $.support.transition && this.$tip.hasClass('fade') ?
indvd00m@0
   245
        removeWithAnimation() :
indvd00m@0
   246
        $tip.detach()
indvd00m@0
   247
indvd00m@0
   248
      this.$element.trigger('hidden')
indvd00m@0
   249
indvd00m@0
   250
      return this
indvd00m@0
   251
    }
indvd00m@0
   252
indvd00m@0
   253
  , fixTitle: function () {
indvd00m@0
   254
      var $e = this.$element
indvd00m@0
   255
      if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
indvd00m@0
   256
        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
indvd00m@0
   257
      }
indvd00m@0
   258
    }
indvd00m@0
   259
indvd00m@0
   260
  , hasContent: function () {
indvd00m@0
   261
      return this.getTitle()
indvd00m@0
   262
    }
indvd00m@0
   263
indvd00m@0
   264
  , getPosition: function () {
indvd00m@0
   265
      var el = this.$element[0]
indvd00m@0
   266
      return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
indvd00m@0
   267
        width: el.offsetWidth
indvd00m@0
   268
      , height: el.offsetHeight
indvd00m@0
   269
      }, this.$element.offset())
indvd00m@0
   270
    }
indvd00m@0
   271
indvd00m@0
   272
  , getTitle: function () {
indvd00m@0
   273
      var title
indvd00m@0
   274
        , $e = this.$element
indvd00m@0
   275
        , o = this.options
indvd00m@0
   276
indvd00m@0
   277
      title = $e.attr('data-original-title')
indvd00m@0
   278
        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
indvd00m@0
   279
indvd00m@0
   280
      return title
indvd00m@0
   281
    }
indvd00m@0
   282
indvd00m@0
   283
  , tip: function () {
indvd00m@0
   284
      return this.$tip = this.$tip || $(this.options.template)
indvd00m@0
   285
    }
indvd00m@0
   286
indvd00m@0
   287
  , arrow: function(){
indvd00m@0
   288
      return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow")
indvd00m@0
   289
    }
indvd00m@0
   290
indvd00m@0
   291
  , validate: function () {
indvd00m@0
   292
      if (!this.$element[0].parentNode) {
indvd00m@0
   293
        this.hide()
indvd00m@0
   294
        this.$element = null
indvd00m@0
   295
        this.options = null
indvd00m@0
   296
      }
indvd00m@0
   297
    }
indvd00m@0
   298
indvd00m@0
   299
  , enable: function () {
indvd00m@0
   300
      this.enabled = true
indvd00m@0
   301
    }
indvd00m@0
   302
indvd00m@0
   303
  , disable: function () {
indvd00m@0
   304
      this.enabled = false
indvd00m@0
   305
    }
indvd00m@0
   306
indvd00m@0
   307
  , toggleEnabled: function () {
indvd00m@0
   308
      this.enabled = !this.enabled
indvd00m@0
   309
    }
indvd00m@0
   310
indvd00m@0
   311
  , toggle: function (e) {
indvd00m@0
   312
      var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this
indvd00m@0
   313
      self.tip().hasClass('in') ? self.hide() : self.show()
indvd00m@0
   314
    }
indvd00m@0
   315
indvd00m@0
   316
  , destroy: function () {
indvd00m@0
   317
      this.hide().$element.off('.' + this.type).removeData(this.type)
indvd00m@0
   318
    }
indvd00m@0
   319
indvd00m@0
   320
  }
indvd00m@0
   321
indvd00m@0
   322
indvd00m@0
   323
 /* TOOLTIP PLUGIN DEFINITION
indvd00m@0
   324
  * ========================= */
indvd00m@0
   325
indvd00m@0
   326
  var old = $.fn.tooltip
indvd00m@0
   327
indvd00m@0
   328
  $.fn.tooltip = function ( option ) {
indvd00m@0
   329
    return this.each(function () {
indvd00m@0
   330
      var $this = $(this)
indvd00m@0
   331
        , data = $this.data('tooltip')
indvd00m@0
   332
        , options = typeof option == 'object' && option
indvd00m@0
   333
      if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
indvd00m@0
   334
      if (typeof option == 'string') data[option]()
indvd00m@0
   335
    })
indvd00m@0
   336
  }
indvd00m@0
   337
indvd00m@0
   338
  $.fn.tooltip.Constructor = Tooltip
indvd00m@0
   339
indvd00m@0
   340
  $.fn.tooltip.defaults = {
indvd00m@0
   341
    animation: true
indvd00m@0
   342
  , placement: 'top'
indvd00m@0
   343
  , selector: false
indvd00m@0
   344
  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
indvd00m@0
   345
  , trigger: 'hover focus'
indvd00m@0
   346
  , title: ''
indvd00m@0
   347
  , delay: 0
indvd00m@0
   348
  , html: false
indvd00m@0
   349
  , container: false
indvd00m@0
   350
  }
indvd00m@0
   351
indvd00m@0
   352
indvd00m@0
   353
 /* TOOLTIP NO CONFLICT
indvd00m@0
   354
  * =================== */
indvd00m@0
   355
indvd00m@0
   356
  $.fn.tooltip.noConflict = function () {
indvd00m@0
   357
    $.fn.tooltip = old
indvd00m@0
   358
    return this
indvd00m@0
   359
  }
indvd00m@0
   360
indvd00m@0
   361
}(window.jQuery);