Skip to content

Commit

Permalink
Multiple tooltip triggers don't play well together
Browse files Browse the repository at this point in the history
Fixes issue twbs#16008
  • Loading branch information
redbmk committed Mar 7, 2015
1 parent e7efd81 commit b310093
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 6 deletions.
37 changes: 37 additions & 0 deletions js/tests/unit/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -1180,4 +1180,41 @@ $(function () {
assert.strictEqual($tooltip.data('bs.tooltip'), undefined, 'should not initialize the tooltip')
})

QUnit.test('should not remove tooltip if multiple triggers are set and one is still active', function (assert) {
assert.expect(41)
var $el = $('<button>Trigger</button>')
.appendTo('#qunit-fixture')
.bootstrapTooltip({ trigger: 'click hover focus', animation: false })
var tooltip = $el.data('bs.tooltip')
var $tooltip = tooltip.tip()

function showingTooltip() { return $tooltip.hasClass('in') || tooltip.hoverState == 'in' }

var tests = [
['mouseenter', 'mouseleave'],

['focusin', 'focusout'],

['click', 'click'],

['mouseenter', 'focusin', 'focusout', 'mouseleave'],
['mouseenter', 'focusin', 'mouseleave', 'focusout'],

['focusin', 'mouseenter', 'mouseleave', 'focusout'],
['focusin', 'mouseenter', 'focusout', 'mouseleave'],

['click', 'focusin', 'mouseenter', 'focusout', 'mouseleave', 'click'],
['mouseenter', 'click', 'focusin', 'focusout', 'mouseleave', 'click'],
['mouseenter', 'focusin', 'click', 'click', 'mouseleave', 'focusout']
]

assert.ok(!showingTooltip())

$.each(tests, function (idx, triggers) {
for (var i = 0, len = triggers.length; i < len; i++) {
$el.trigger(triggers[i]);
assert.equal(i < (len - 1), showingTooltip())
}
})
})
})
29 changes: 23 additions & 6 deletions js/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
this.$element = $(element)
this.options = this.getOptions(options)
this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
this.inState = { click: false, hover: false, focus: false }

if (this.$element[0] instanceof document.constructor && !this.options.selector) {
throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
Expand Down Expand Up @@ -109,16 +110,20 @@
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type)

if (self && self.$tip && self.$tip.is(':visible')) {
self.hoverState = 'in'
return
}

if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self)
}

if (obj instanceof $.Event) {
self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
}

if (self.tip().hasClass('in') || (self.hoverState == 'in')) {
self.hoverState = 'in'
return
}

clearTimeout(self.timeout)

self.hoverState = 'in'
Expand All @@ -139,6 +144,12 @@
$(obj.currentTarget).data('bs.' + this.type, self)
}

if (obj instanceof $.Event) {
self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
}

if (self.inState.click || self.inState.focus || self.inState.hover) return

clearTimeout(self.timeout)

self.hoverState = 'out'
Expand Down Expand Up @@ -432,7 +443,13 @@
}
}

self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
if (e) {
self.inState.click = !self.inState.click
if (self.inState.click || self.inState.focus || self.inState.hover) self.enter(self)
else self.leave(self)
} else {
self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
}
}

Tooltip.prototype.destroy = function () {
Expand Down

0 comments on commit b310093

Please sign in to comment.