Commit 88697c03 authored by Eric Martel's avatar Eric Martel Committed by Chris Rebert

Fix tooltip positioning with regard to viewports

The getPosition function was simplified with a new function,
getViewportBounds, was added to specifically
tackle the cases where we’re looking for the viewport bounds.

'absolute' and 'fixed' tooltips are now matched against the screen
where other ones are made to fit inside the viewport element.

Fixes #14195
Closes #14226
parent e22a73fd
......@@ -719,6 +719,43 @@ $(function () {
$styles.remove()
})
QUnit.test('should not adjust position when scrolling the window', function (assert) {
assert.expect(2)
var styles = '<style>'
+ '.large-spacer { height: 3000px; }'
+ '</style>'
var $styles = $(styles).appendTo('head')
var $container = $('<div class="container-viewport"/>').appendTo(document.body)
var $target = $('<a href="#" rel="tooltip" title="tip"/>')
.appendTo($container)
.bootstrapTooltip({
placement: 'right',
viewport: 'body'
})
$('<div class="large-spacer"/>').appendTo($container)
$target.bootstrapTooltip('show')
var $tooltip = $container.find('.tooltip')
var $initialTop = Math.round($tooltip.offset().top)
$target.bootstrapTooltip('hide')
window.scrollTo(0, 2000)
$target.bootstrapTooltip('show')
$tooltip = $container.find('.tooltip')
assert.strictEqual(Math.round($tooltip.offset().top), $initialTop, 'position is the same after scrolling')
assert.strictEqual($(document).scrollTop(), 2000, 'document scrolled')
$target.bootstrapTooltip('hide')
$container.remove()
$styles.remove()
window.scrollTo(0, 0)
})
QUnit.test('should not error when trying to show an auto-placed tooltip that has been removed from the dom', function (assert) {
assert.expect(1)
var passed = true
......
......@@ -344,7 +344,7 @@
}
var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
var outerDims = isBody ? { width: $element.outerWidth(), height: $element.outerHeight() } : null
return $.extend({}, elRect, scroll, outerDims, elOffset)
}
......@@ -357,16 +357,34 @@
}
Tooltip.prototype.getViewportBounds = function ($viewport) {
if ($viewport.is('body') && (/fixed|absolute/).test(this.$element.css('position'))) {
// fixed and absolute elements should be tested against the window
return this.getScreenSpaceBounds($viewport)
}
return $.extend({}, $viewport.offset(), { width: $viewport.outerWidth(), height: $viewport.outerHeight() })
}
Tooltip.prototype.getScreenSpaceBounds = function ($viewport) {
return {
top: $viewport.scrollTop(),
left: $viewport.scrollLeft(),
width: $(window).width(),
height: $(window).height()
}
}
Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
var delta = { top: 0, left: 0 }
if (!this.$viewport) return delta
var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
var viewportDimensions = this.getPosition(this.$viewport)
var viewportDimensions = this.getViewportBounds(this.$viewport)
if (/right|left/.test(placement)) {
var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
var topEdgeOffset = pos.top - viewportPadding
var bottomEdgeOffset = pos.top + viewportPadding + actualHeight
if (topEdgeOffset < viewportDimensions.top) { // top overflow
delta.top = viewportDimensions.top - topEdgeOffset
} else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment