From 4d9890ea2e7e868221d0c2254c9dc86152304815 Mon Sep 17 00:00:00 2001
From: Chris Rebert <code@rebertia.com>
Date: Mon, 15 Sep 2014 12:36:40 -0700
Subject: [PATCH] Use container instead of parent for tooltip/popover
 auto-placement calcs

Fixes #14561. Big thanks to @wickstargazer.

[skip validator]
---
 js/tests/unit/tooltip.js | 42 ++++++++++++++++++++++++++++++++++++++++
 js/tooltip.js            | 12 ++++++------
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js
index fd02a5e7f2..78ea7a81b5 100644
--- a/js/tests/unit/tooltip.js
+++ b/js/tests/unit/tooltip.js
@@ -827,6 +827,47 @@ $(function () {
     $circle.bootstrapTooltip('show')
   })
 
+  test('should correctly determine auto placement based on container rather than parent', function () {
+    stop()
+
+    var styles = '<style>'
+        + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }'
+        + '.tooltip { position: absolute; display: block; font-size: 12px; line-height: 1.4; }'
+        + '.tooltip .tooltip-inner { max-width: 200px; padding: 3px 8px; font-family: Helvetica; text-align: center; }'
+        + '#trigger-parent {'
+        + '  position: fixed;'
+        + '  top: 100px;'
+        + '  right: 17px;'
+        + '}'
+        + '</style>'
+    var $styles = $(styles).appendTo('head')
+
+    $('#qunit-fixture').append('<span id="trigger-parent"><a id="tt-trigger" title="If a_larger_text is written here, it won\'t fit using older broken version of BS">HOVER OVER ME</a></span>')
+    var $trigger = $('#tt-trigger')
+
+    $trigger
+      .on('shown.bs.tooltip', function () {
+        var $tip = $('.tooltip-inner')
+        var tipXrightEdge = $tip.offset().left + $tip.width()
+        var triggerXleftEdge = $trigger.offset().left
+        ok(tipXrightEdge < triggerXleftEdge, 'tooltip with auto left placement, when near the right edge of the viewport, gets left placement')
+        $trigger.bootstrapTooltip('hide')
+      })
+      .on('hidden.bs.tooltip', function () {
+        $styles.remove()
+        $(this).remove()
+        equal($('.tooltip').length, 0, 'tooltip removed from dom')
+        start()
+      })
+      .bootstrapTooltip({
+        container: 'body',
+        placement: 'auto left',
+        trigger: 'manual'
+      })
+
+    $trigger.bootstrapTooltip('show')
+  })
+
   test('should not reload the tooltip on subsequent mouseenter events', function () {
     var titleHtml = function () {
       var uid = $.fn.bootstrapTooltip.Constructor.prototype.getUID('tooltip')
@@ -909,6 +950,7 @@ $(function () {
       .on('hidden.bs.tooltip', function () {
         $styles.remove()
         $(this).remove()
+        equal($('.tooltip').length, 0, 'tooltip removed from dom')
         start()
       })
       .bootstrapTooltip({
diff --git a/js/tooltip.js b/js/tooltip.js
index d0da83a5a9..55dedcef41 100644
--- a/js/tooltip.js
+++ b/js/tooltip.js
@@ -188,13 +188,13 @@
 
       if (autoPlace) {
         var orgPlacement = placement
-        var $parent      = this.$element.parent()
-        var parentDim    = this.getPosition($parent)
+        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()
+        var containerDim = this.getPosition($container)
 
-        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
-                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < parentDim.top                       ? 'bottom' :
-                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
-                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
+        placement = placement == 'bottom' && pos.top   + pos.height          + actualHeight - containerDim.scroll > containerDim.height ? 'top'    :
+                    placement == 'top'    && pos.top   - containerDim.scroll - actualHeight < containerDim.top                                         ? 'bottom' :
+                    placement == 'right'  && pos.right + actualWidth         > containerDim.width                                       ? 'left'   :
+                    placement == 'left'   && pos.left  - actualWidth         < containerDim.left                                        ? 'right'  :
                     placement
 
         $tip
-- 
GitLab