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);