vendor: 4,560 bytes, lines 1-156
1/* ======================================================================== 2 * Bootstrap: tooltip.js v3.2.0 3 * http://getbootstrap.com/javascript/#tooltip 4 * Inspired by the original jQuery.tipsy by Jason Frame 5 * ======================================================================== 6 * Copyright 2011-2014 Twitter, Inc. 7 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 8 * ======================================================================== */ 9 10 11+function ($) { 12 'use strict'; 13 14 // TOOLTIP PUBLIC CLASS DEFINITION 15 // =============================== 16 17 var Tooltip = function (element, options) { 18 this.type = 19 this.options = 20 this.enabled = 21 this.timeout = 22 this.hoverState = 23 this.$element = null 24 25 this.init('tooltip', element, options) 26 } 27 28 Tooltip.VERSION = '3.2.0' 29 30 Tooltip.DEFAULTS = { 31 animation: true, 32 placement: 'top', 33 selector: false, 34 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 35 trigger: 'hover focus', 36 title: '', 37 delay: 0, 38 html: false, 39 container: false, 40 viewport: { 41 selector: 'body', 42 padding: 0 43 } 44 } 45 46 Tooltip.prototype.init = function (type, element, options) { 47 this.enabled = true 48 this.type = type 49 this.$element = $(element) 50 this.options = this.getOptions(options) 51 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 52 53 var triggers = this.options.trigger.split(' ') 54 55 for (var i = triggers.length; i--;) { 56 var trigger = triggers[i] 57 58 if (trigger == 'click') { 59 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 60 } else if (trigger != 'manual') { 61 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 62 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 63 64 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 65 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 66 } 67 } 68 69 this.options.selector ? 70 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 71 this.fixTitle() 72 } 73 74 Tooltip.prototype.getDefaults = function () { 75 return Tooltip.DEFAULTS 76 } 77 78 Tooltip.prototype.getOptions = function (options) { 79 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 80 81 if (options.delay && typeof options.delay == 'number') { 82 options.delay = { 83 show: options.delay, 84 hide: options.delay 85 } 86 } 87 88 return options 89 } 90 91 Tooltip.prototype.getDelegateOptions = function () { 92 var options = {} 93 var defaults = this.getDefaults() 94 95 this._options && $.each(this._options, function (key, value) { 96 if (defaults[key] != value) options[key] = value 97 }) 98 99 return options 100 } 101 102 Tooltip.prototype.enter = function (obj) { 103 var self = obj instanceof this.constructor ? 104 obj : $(obj.currentTarget).data('bs.' + this.type) 105 106 if (!self) { 107 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 108 $(obj.currentTarget).data('bs.' + this.type, self) 109 } 110 111 clearTimeout(self.timeout) 112 113 self.hoverState = 'in' 114 115 if (!self.options.delay || !self.options.delay.show) return self.show() 116 117 self.timeout = setTimeout(function () { 118 if (self.hoverState == 'in') self.show() 119 }, self.options.delay.show) 120 } 121 122 Tooltip.prototype.leave = function (obj) { 123 var self = obj instanceof this.constructor ? 124 obj : $(obj.currentTarget).data('bs.' + this.type) 125 126 if (!self) { 127 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 128 $(obj.currentTarget).data('bs.' + this.type, self) 129 } 130 131 clearTimeout(self.timeout) 132 133 self.hoverState = 'out' 134 135 if (!self.options.delay || !self.options.delay.hide) return self.hide() 136 137 self.timeout = setTimeout(function () { 138 if (self.hoverState == 'out') self.hide() 139 }, self.options.delay.hide) 140 } 141 142 Tooltip.prototype.show = function () { 143 var e = $.Event('show.bs.' + this.type) 144 145 if (this.hasContent() && this.enabled) { 146 this.$element.trigger(e) 147 148 var inDom = $.contains(document.documentElement, this.$element[0]) 149 if (e.isDefaultPrevented() || !inDom) return 150 var that = this 151 152 var $tip = this.tip() 153 154 var tipId = this.getUID(this.type) 155 156 this.setContent()
157 $tip.attr('id', tipId) 158 this.$element.attr('aria-describedby', tipId) 159 160 if (this.options.animation) $tip.addClass('fade') 161 162 var placement = typeof this.options.placement == 'function' ? 163 this.options.placement.call(this, $tip[0], this.$element[0]) : 164 this.options.placement 165 166 var autoToken = /\s?auto?\s?/i 167 var autoPlace = autoToken.test(placement) 168 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 169 170 $tip 171 .detach() 172 .css({ top: 0, left: 0, display: 'block' }) 173 .addClass(placement) 174 .data('bs.' + this.type, this) 175 176 this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 177 178 var pos = this.getPosition() 179 var actualWidth = $tip[0].offsetWidth 180 var actualHeight = $tip[0].offsetHeight 181 182 if (autoPlace) { 183 var orgPlacement = placement 184 var $parent = this.$element.parent() 185 var parentDim = this.getPosition($parent) 186 187 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 188 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 189 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 190 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 191 placement 192 193 $tip 194 .removeClass(orgPlacement) 195 .addClass(placement) 196 } 197 198 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 199 200 this.applyPlacement(calculatedOffset, placement) 201 202 var complete = function () { 203 that.$element.trigger('shown.bs.' + that.type) 204 that.hoverState = null 205 } 206 207 $.support.transition && this.$tip.hasClass('fade') ? 208 $tip 209 .one('bsTransitionEnd', complete) 210 .emulateTransitionEnd(150) : 211 complete() 212 } 213 } 214 215 Tooltip.prototype.applyPlacement = function (offset, placement) { 216 var $tip = this.tip() 217 var width = $tip[0].offsetWidth 218 var height = $tip[0].offsetHeight 219 220 // manually read margins because getBoundingClientRect includes difference 221 var marginTop = parseInt($tip.css('margin-top'), 10) 222 var marginLeft = parseInt($tip.css('margin-left'), 10) 223 224 // we must check for NaN for ie 8/9 225 if (isNaN(marginTop)) marginTop = 0 226 if (isNaN(marginLeft)) marginLeft = 0 227 228 offset.top = offset.top + marginTop 229 offset.left = offset.left + marginLeft 230 231 // $.fn.offset doesn't round pixel values 232 // so we use setOffset directly with our own function B-0 233 $.offset.setOffset($tip[0], $.extend({ 234 using: function (props) { 235 $tip.css({ 236 top: Math.round(props.top), 237 left: Math.round(props.left) 238 }) 239 } 240 }, offset), 0) 241 242 $tip.addClass('in') 243 244 // check to see if placing tip in new offset caused the tip to resize itself 245 var actualWidth = $tip[0].offsetWidth 246 var actualHeight = $tip[0].offsetHeight 247 248 if (placement == 'top' && actualHeight != height) { 249 offset.top = offset.top + height - actualHeight 250 } 251 252 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 253 254 if (delta.left) offset.left += delta.left 255 else offset.top += delta.top 256 257 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 258 var arrowPosition = delta.left ? 'left' : 'top' 259 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 260 261 $tip.offset(offset) 262 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 263 } 264 265 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 266 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 267 } 268 269 Tooltip.prototype.setContent = function () { 270 var $tip = this.tip() 271 var title = this.getTitle() 272 273 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 274 $tip.removeClass('fade in top bottom left right') 275 } 276 277 Tooltip.prototype.hide = function () { 278 var that = this 279 var $tip = this.tip() 280 var e = $.Event('hide.bs.' + this.type) 281 282 this.$element.removeAttr('aria-describedby') 283 284 function complete() { 285 if (that.hoverState != 'in') $tip.detach() 286 that.$element.trigger('hidden.bs.' + that.type) 287 } 288 289 this.$element.trigger(e) 290 291 if (e.isDefaultPrevented()) return 292 293 $tip.removeClass('in') 294 295 $.support.transition && this.$tip.hasClass('fade') ? 296 $tip 297 .one('bsTransitionEnd', complete) 298 .emulateTransitionEnd(150) : 299 complete() 300 301 this.hoverState = null 302 303 return this 304 } 305 306 Tooltip.prototype.fixTitle = function () { 307 var $e = this.$element 308 if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') { 309 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 310 } 311 } 312 313 Tooltip.prototype.hasContent = function () { 314 return this.getTitle() 315 } 316 317 Tooltip.prototype.getPosition = function ($element) { 318 $element = $element || this.$element 319 var el = $element[0] 320 var isBody = el.tagName == 'BODY' 321 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 322 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 323 width: isBody ? $(window).width() : $element.outerWidth(), 324 height: isBody ? $(window).height() : $element.outerHeight() 325 }, isBody ? { top: 0, left: 0 } : $element.offset()) 326 } 327 328 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 329 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 330 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 331 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 332 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 333 334 } 335 336 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 337 var delta = { top: 0, left: 0 } 338 if (!this.$viewport) return delta 339 340 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 341 var viewportDimensions = this.getPosition(this.$viewport) 342 343 if (/right|left/.test(placement)) { 344 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 345 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 346 if (topEdgeOffset < viewportDimensions.top) { // top overflow 347 delta.top = viewportDimensions.top - topEdgeOffset 348 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 349 delta.top = viewportDimensions.top + viewportDimensions.height - bottom
349EdgeOffset 350 } 351 } else { 352 var leftEdgeOffset = pos.left - viewportPadding 353 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 354 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 355 delta.left = viewportDimensions.left - leftEdgeOffset 356 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 357 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 358 } 359 } 360 361 return delta 362 } 363 364 Tooltip.prototype.getTitle = function () { 365 var title 366 var $e = this.$element 367 var o = this.options 368 369 title = $e.attr('data-original-title') 370 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 371 372 return title 373 } 374 375 Tooltip.prototype.getUID = function (prefix) { 376 do prefix += ~~(Math.random() * 1000000) 377 while (document.getElementById(prefix)) 378 return prefix 379 } 380 381 Tooltip.prototype.tip = function () { 382 return (this.$tip = this.$tip || $(this.options.template)) 383 } 384 385 Tooltip.prototype.arrow = function () { 386 return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 387 } 388 389 Tooltip.prototype.validate = function () { 390 if (!this.$element[0].parentNode) { 391 this.hide() 392 this.$element = null 393 this.options = null 394 } 395 } 396 397 Tooltip.prototype.enable = function () { 398 this.enabled = true 399 } 400 401 Tooltip.prototype.disable = function () { 402 this.enabled = false 403 } 404 405 Tooltip.prototype.toggleEnabled = function () { 406 this.enabled = !this.enabled 407 } 408 409 Tooltip.prototype.toggle = function (e) { 410 var self = this 411 if (e) { 412 self = $(e.currentTarget).data('bs.' + this.type) 413 if (!self) { 414 self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 415 $(e.currentTarget).data('bs.' + this.type, self) 416 } 417 } 418 419 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 420 } 421 422 Tooltip.prototype.destroy = function () { 423 clearTimeout(this.timeout) 424 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 425 } 426 427 428 // TOOLTIP PLUGIN DEFINITION 429 // ========================= 430 431 function Plugin(option) { 432 return this.each(function () { 433 var $this = $(this) 434 var data = $this.data('bs.tooltip') 435 var options = typeof option == 'object' && option 436 437 if (!data && option == 'destroy') return 438 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 439 if (typeof option == 'string') data[option]() 440 }) 441 } 442 443 var old = $.fn.tooltip 444 445 $.fn.tooltip = Plugin 446 $.fn.tooltip.Constructor = Tooltip 447 448 449 // TOOLTIP NO CONFLICT 450 // =================== 451 452 $.fn.tooltip.noConflict = function () { 453 $.fn.tooltip = old 454 return this 455 } 456 457}(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.