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