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 () { ...@@ -719,6 +719,43 @@ $(function () {
$styles.remove() $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) { 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) assert.expect(1)
var passed = true var passed = true
......
...@@ -344,7 +344,7 @@ ...@@ -344,7 +344,7 @@
} }
var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } 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) return $.extend({}, elRect, scroll, outerDims, elOffset)
} }
...@@ -357,16 +357,34 @@ ...@@ -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) { Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
var delta = { top: 0, left: 0 } var delta = { top: 0, left: 0 }
if (!this.$viewport) return delta if (!this.$viewport) return delta
var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 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)) { if (/right|left/.test(placement)) {
var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll var topEdgeOffset = pos.top - viewportPadding
var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight var bottomEdgeOffset = pos.top + viewportPadding + actualHeight
if (topEdgeOffset < viewportDimensions.top) { // top overflow if (topEdgeOffset < viewportDimensions.top) { // top overflow
delta.top = viewportDimensions.top - topEdgeOffset delta.top = viewportDimensions.top - topEdgeOffset
} else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow } 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