Issues (4542)

js/tooltip.js (29 issues)

1
/* ========================================================================
2
 * Bootstrap: tooltip.js v3.3.6
3
 * http://getbootstrap.com/javascript/#tooltip
4
 * Inspired by the original jQuery.tipsy by Jason Frame
5
 * ========================================================================
6
 * Copyright 2011-2016 Twitter, Inc.
7
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
8
 * ======================================================================== */
9
10
11 View Code Duplication
+function ($) {
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
12
  'use strict';
13
14
  // TOOLTIP PUBLIC CLASS DEFINITION
15
  // ===============================
16
17
  var Tooltip = function (element, options) {
18
    this.type       = null
19
    this.options    = null
20
    this.enabled    = null
21
    this.timeout    = null
22
    this.hoverState = null
23
    this.$element   = null
24
    this.inState    = null
25
26
    this.init('tooltip', element, options)
27
  }
28
29
  Tooltip.VERSION  = '3.3.6'
30
31
  Tooltip.TRANSITION_DURATION = 150
32
33
  Tooltip.DEFAULTS = {
34
    animation: true,
35
    placement: 'top',
36
    selector: false,
37
    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
38
    trigger: 'hover focus',
39
    title: '',
40
    delay: 0,
41
    html: false,
42
    container: false,
43
    viewport: {
44
      selector: 'body',
45
      padding: 0
46
    }
47
  }
48
49
  Tooltip.prototype.init = function (type, element, options) {
50
    this.enabled   = true
51
    this.type      = type
52
    this.$element  = $(element)
53
    this.options   = this.getOptions(options)
54
    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
55
    this.inState   = { click: false, hover: false, focus: false }
56
57
    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
58
      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
59
    }
60
61
    var triggers = this.options.trigger.split(' ')
62
63
    for (var i = triggers.length; i--;) {
64
      var trigger = triggers[i]
65
66
      if (trigger == 'click') {
67
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
68
      } else if (trigger != 'manual') {
69
        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
70
        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
71
72
        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
73
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
74
      }
75
    }
76
77
    this.options.selector ?
78
      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
79
      this.fixTitle()
80
  }
81
82
  Tooltip.prototype.getDefaults = function () {
83
    return Tooltip.DEFAULTS
84
  }
85
86
  Tooltip.prototype.getOptions = function (options) {
87
    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
88
89
    if (options.delay && typeof options.delay == 'number') {
90
      options.delay = {
91
        show: options.delay,
92
        hide: options.delay
93
      }
94
    }
95
96
    return options
97
  }
98
99
  Tooltip.prototype.getDelegateOptions = function () {
100
    var options  = {}
101
    var defaults = this.getDefaults()
102
103
    this._options && $.each(this._options, function (key, value) {
104
      if (defaults[key] != value) options[key] = value
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
105
    })
106
107
    return options
108
  }
109
110
  Tooltip.prototype.enter = function (obj) {
111
    var self = obj instanceof this.constructor ?
112
      obj : $(obj.currentTarget).data('bs.' + this.type)
113
114
    if (!self) {
115
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
116
      $(obj.currentTarget).data('bs.' + this.type, self)
117
    }
118
119
    if (obj instanceof $.Event) {
120
      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
121
    }
122
123
    if (self.tip().hasClass('in') || self.hoverState == 'in') {
124
      self.hoverState = 'in'
125
      return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
126
    }
127
128
    clearTimeout(self.timeout)
129
130
    self.hoverState = 'in'
131
132
    if (!self.options.delay || !self.options.delay.show) return self.show()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
133
134
    self.timeout = setTimeout(function () {
135
      if (self.hoverState == 'in') self.show()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
136
    }, self.options.delay.show)
137
  }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
138
139
  Tooltip.prototype.isInStateTrue = function () {
140
    for (var key in this.inState) {
0 ignored issues
show
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
141
      if (this.inState[key]) return true
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
142
    }
143
144
    return false
145
  }
146
147
  Tooltip.prototype.leave = function (obj) {
148
    var self = obj instanceof this.constructor ?
149
      obj : $(obj.currentTarget).data('bs.' + this.type)
150
151
    if (!self) {
152
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
153
      $(obj.currentTarget).data('bs.' + this.type, self)
154
    }
155
156
    if (obj instanceof $.Event) {
157
      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
158
    }
159
160
    if (self.isInStateTrue()) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
161
162
    clearTimeout(self.timeout)
163
164
    self.hoverState = 'out'
165
166
    if (!self.options.delay || !self.options.delay.hide) return self.hide()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
167
168
    self.timeout = setTimeout(function () {
169
      if (self.hoverState == 'out') self.hide()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
170
    }, self.options.delay.hide)
171
  }
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
172
173
  Tooltip.prototype.show = function () {
174
    var e = $.Event('show.bs.' + this.type)
175
176
    if (this.hasContent() && this.enabled) {
177
      this.$element.trigger(e)
178
179
      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
180
      if (e.isDefaultPrevented() || !inDom) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
181
      var that = this
182
183
      var $tip = this.tip()
184
185
      var tipId = this.getUID(this.type)
186
187
      this.setContent()
188
      $tip.attr('id', tipId)
189
      this.$element.attr('aria-describedby', tipId)
190
191
      if (this.options.animation) $tip.addClass('fade')
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
192
193
      var placement = typeof this.options.placement == 'function' ?
194
        this.options.placement.call(this, $tip[0], this.$element[0]) :
195
        this.options.placement
196
197
      var autoToken = /\s?auto?\s?/i
198
      var autoPlace = autoToken.test(placement)
199
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
200
201
      $tip
202
        .detach()
203
        .css({ top: 0, left: 0, display: 'block' })
204
        .addClass(placement)
205
        .data('bs.' + this.type, this)
206
207
      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
208
      this.$element.trigger('inserted.bs.' + this.type)
209
210
      var pos          = this.getPosition()
211
      var actualWidth  = $tip[0].offsetWidth
212
      var actualHeight = $tip[0].offsetHeight
213
214
      if (autoPlace) {
215
        var orgPlacement = placement
216
        var viewportDim = this.getPosition(this.$viewport)
217
218
        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
219
                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
220
                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
221
                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
222
                    placement
223
224
        $tip
225
          .removeClass(orgPlacement)
226
          .addClass(placement)
227
      }
228
229
      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
230
231
      this.applyPlacement(calculatedOffset, placement)
232
233
      var complete = function () {
234
        var prevHoverState = that.hoverState
235
        that.$element.trigger('shown.bs.' + that.type)
236
        that.hoverState = null
237
238
        if (prevHoverState == 'out') that.leave(that)
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
239
      }
240
241
      $.support.transition && this.$tip.hasClass('fade') ?
242
        $tip
243
          .one('bsTransitionEnd', complete)
244
          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
245
        complete()
246
    }
247
  }
248
249
  Tooltip.prototype.applyPlacement = function (offset, placement) {
250
    var $tip   = this.tip()
251
    var width  = $tip[0].offsetWidth
252
    var height = $tip[0].offsetHeight
253
254
    // manually read margins because getBoundingClientRect includes difference
255
    var marginTop = parseInt($tip.css('margin-top'), 10)
256
    var marginLeft = parseInt($tip.css('margin-left'), 10)
257
258
    // we must check for NaN for ie 8/9
259
    if (isNaN(marginTop))  marginTop  = 0
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
260
    if (isNaN(marginLeft)) marginLeft = 0
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
261
262
    offset.top  += marginTop
263
    offset.left += marginLeft
264
265
    // $.fn.offset doesn't round pixel values
266
    // so we use setOffset directly with our own function B-0
267
    $.offset.setOffset($tip[0], $.extend({
268
      using: function (props) {
269
        $tip.css({
270
          top: Math.round(props.top),
271
          left: Math.round(props.left)
272
        })
273
      }
274
    }, offset), 0)
275
276
    $tip.addClass('in')
277
278
    // check to see if placing tip in new offset caused the tip to resize itself
279
    var actualWidth  = $tip[0].offsetWidth
280
    var actualHeight = $tip[0].offsetHeight
281
282
    if (placement == 'top' && actualHeight != height) {
283
      offset.top = offset.top + height - actualHeight
284
    }
285
286
    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
287
288
    if (delta.left) offset.left += delta.left
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
289
    else offset.top += delta.top
290
291
    var isVertical          = /top|bottom/.test(placement)
292
    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
293
    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
294
295
    $tip.offset(offset)
296
    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
297
  }
298
299
  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
300
    this.arrow()
301
      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
302
      .css(isVertical ? 'top' : 'left', '')
303
  }
304
305
  Tooltip.prototype.setContent = function () {
306
    var $tip  = this.tip()
307
    var title = this.getTitle()
308
309
    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
310
    $tip.removeClass('fade in top bottom left right')
311
  }
312
313
  Tooltip.prototype.hide = function (callback) {
314
    var that = this
315
    var $tip = $(this.$tip)
316
    var e    = $.Event('hide.bs.' + this.type)
317
318
    function complete() {
319
      if (that.hoverState != 'in') $tip.detach()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
320
      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
321
        that.$element
322
          .removeAttr('aria-describedby')
323
          .trigger('hidden.bs.' + that.type)
324
      }
325
      callback && callback()
326
    }
327
328
    this.$element.trigger(e)
329
330
    if (e.isDefaultPrevented()) return
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
331
332
    $tip.removeClass('in')
333
334
    $.support.transition && $tip.hasClass('fade') ?
335
      $tip
336
        .one('bsTransitionEnd', complete)
337
        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
338
      complete()
339
340
    this.hoverState = null
341
342
    return this
343
  }
344
345
  Tooltip.prototype.fixTitle = function () {
346
    var $e = this.$element
347
    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
348
      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
349
    }
350
  }
351
352
  Tooltip.prototype.hasContent = function () {
353
    return this.getTitle()
354
  }
355
356
  Tooltip.prototype.getPosition = function ($element) {
357
    $element   = $element || this.$element
358
359
    var el     = $element[0]
360
    var isBody = el.tagName == 'BODY'
361
362
    var elRect    = el.getBoundingClientRect()
363
    if (elRect.width == null) {
364
      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
365
      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
366
    }
367
    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
368
    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
369
    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
370
371
    return $.extend({}, elRect, scroll, outerDims, elOffset)
372
  }
373
374
  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
375
    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
376
           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
377
           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
378
        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
379
380
  }
381
382
  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
383
    var delta = { top: 0, left: 0 }
384
    if (!this.$viewport) return delta
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
385
386
    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
387
    var viewportDimensions = this.getPosition(this.$viewport)
388
389
    if (/right|left/.test(placement)) {
390
      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
391
      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
392
      if (topEdgeOffset < viewportDimensions.top) { // top overflow
393
        delta.top = viewportDimensions.top - topEdgeOffset
394
      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
395
        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
396
      }
397
    } else {
398
      var leftEdgeOffset  = pos.left - viewportPadding
399
      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
400
      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
401
        delta.left = viewportDimensions.left - leftEdgeOffset
402
      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
403
        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
404
      }
405
    }
406
407
    return delta
408
  }
409
410
  Tooltip.prototype.getTitle = function () {
411
    var title
412
    var $e = this.$element
413
    var o  = this.options
414
415
    title = $e.attr('data-original-title')
416
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
417
418
    return title
419
  }
420
421
  Tooltip.prototype.getUID = function (prefix) {
422
    do prefix += ~~(Math.random() * 1000000)
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
423
    while (document.getElementById(prefix))
424
    return prefix
425
  }
426
427
  Tooltip.prototype.tip = function () {
428
    if (!this.$tip) {
429
      this.$tip = $(this.options.template)
430
      if (this.$tip.length != 1) {
431
        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
432
      }
433
    }
434
    return this.$tip
435
  }
436
437
  Tooltip.prototype.arrow = function () {
438
    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
439
  }
440
441
  Tooltip.prototype.enable = function () {
442
    this.enabled = true
443
  }
444
445
  Tooltip.prototype.disable = function () {
446
    this.enabled = false
447
  }
448
449
  Tooltip.prototype.toggleEnabled = function () {
450
    this.enabled = !this.enabled
451
  }
452
453
  Tooltip.prototype.toggle = function (e) {
454
    var self = this
455
    if (e) {
456
      self = $(e.currentTarget).data('bs.' + this.type)
457
      if (!self) {
458
        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
459
        $(e.currentTarget).data('bs.' + this.type, self)
460
      }
461
    }
462
463
    if (e) {
464
      self.inState.click = !self.inState.click
465
      if (self.isInStateTrue()) self.enter(self)
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
466
      else self.leave(self)
467
    } else {
468
      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
469
    }
470
  }
471
472
  Tooltip.prototype.destroy = function () {
473
    var that = this
474
    clearTimeout(this.timeout)
475
    this.hide(function () {
476
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
477
      if (that.$tip) {
478
        that.$tip.detach()
479
      }
480
      that.$tip = null
481
      that.$arrow = null
482
      that.$viewport = null
483
      that.$element = null
484
    })
485
  }
486
487
488
  // TOOLTIP PLUGIN DEFINITION
489
  // =========================
490
491
  function Plugin(option) {
492
    return this.each(function () {
493
      var $this   = $(this)
494
      var data    = $this.data('bs.tooltip')
495
      var options = typeof option == 'object' && option
496
497
      if (!data && /destroy|hide/.test(option)) return
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
498
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
499
      if (typeof option == 'string') data[option]()
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
500
    })
501
  }
502
503
  var old = $.fn.tooltip
504
505
  $.fn.tooltip             = Plugin
506
  $.fn.tooltip.Constructor = Tooltip
507
508
509
  // TOOLTIP NO CONFLICT
510
  // ===================
511
512
  $.fn.tooltip.noConflict = function () {
513
    $.fn.tooltip = old
514
    return this
515
  }
516
517
}(jQuery);