diff --git a/js/bootstrap-tooltip.js b/js/bootstrap-tooltip.js index c23d8267a8e7..718f9643ee1a 100644 --- a/js/bootstrap-tooltip.js +++ b/js/bootstrap-tooltip.js @@ -152,14 +152,67 @@ break } - $tip - .offset(tp) + this.applyPlacement(tp, placement) + + this.$element.trigger('shown') + } + } + + , applyPlacement: function(offset, placement){ + var $tip + , width + , height + , actualWidth + , actualHeight + , delta + , replace = false + + $tip = this.tip() + + width = $tip[0].offsetWidth + height = $tip[0].offsetHeight + + $tip + .offset(offset) .addClass(placement) .addClass('in') - this.$element.trigger('shown') + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight + + if (placement == "top" && actualHeight != height){ + offset.top = offset.top + height - actualHeight + replace = true + } + + if (placement == "bottom" || placement == "top"){ + delta = 0 + + if (offset.left < 0){ + delta = -offset.left * 2 + offset.left = 0 + $tip.offset(offset) + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight } + + this.replaceArrow(delta - width + actualWidth, actualWidth, "left") + }else{ + this.replaceArrow(actualHeight - height, actualHeight, "top") + } + + if (replace) $tip.offset(offset) + } + + , replaceArrow: function(delta, dimension, position){ + var $arrow = this.arrow() + + if (delta !== 0){ + $arrow.css(position, 50 * (1 - delta / dimension) + "%") + }else{ + $arrow.css(position, "") } + } , setContent: function () { var $tip = this.tip() @@ -233,6 +286,10 @@ return this.$tip = this.$tip || $(this.options.template) } + , arrow: function(){ + return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow") + } + , validate: function () { if (!this.$element[0].parentNode) { this.hide() diff --git a/js/tests/index.html b/js/tests/index.html index 976ca16872b6..e9ad01d67a69 100644 --- a/js/tests/index.html +++ b/js/tests/index.html @@ -29,6 +29,9 @@ + + + diff --git a/js/tests/unit/bootstrap-tooltip.css b/js/tests/unit/bootstrap-tooltip.css new file mode 100644 index 000000000000..8614e60d7d01 --- /dev/null +++ b/js/tests/unit/bootstrap-tooltip.css @@ -0,0 +1,13 @@ + + +.tooltip{ + position: absolute; +} + +.tooltip-inner{ + max-width: 200px; +} + +.tooltip.top .tooltip-arrow{ + position: absolute; +} \ No newline at end of file diff --git a/js/tests/unit/bootstrap-tooltip.js b/js/tests/unit/bootstrap-tooltip.js index ef21bd96b477..dc4c19bcfd08 100644 --- a/js/tests/unit/bootstrap-tooltip.js +++ b/js/tests/unit/bootstrap-tooltip.js @@ -251,4 +251,65 @@ $(function () { ok(!$("#qunit-fixture > .tooltip").length, 'not found in parent') tooltip.tooltip('hide') }) + + test("should place tooltip inside window", function(){ + var container = $("
").appendTo("body") + .css({position: "absolute", width: 200, height: 200, bottom: 0, left: 0}) + , tooltip = $("Hover me") + .css({position: "absolute", top:0, left: 0}) + .appendTo(container) + .tooltip({placement: "top", animate: false}) + .tooltip("show") + + stop() + + setTimeout(function(){ + ok($(".tooltip").offset().left >= 0) + + start() + container.remove() + }, 100) + }) + + test("should place tooltip on top of element", function(){ + var container = $("
").appendTo("body") + .css({position: "absolute", bottom: 0, left: 0, textAlign: "right", width: 300, height: 300}) + , p = $("

").appendTo(container) + , tooltiped = $("Hover me") + .css({marginTop: 200}) + .appendTo(p) + .tooltip({placement: "top", animate: false}) + .tooltip("show") + + stop() + + setTimeout(function(){ + var tooltip = container.find(".tooltip") + + start() + ok(tooltip.offset().top + tooltip.outerHeight() <= tooltiped.offset().top) + container.remove() + }, 100) + }) + + test("arrow should point to element", function(){ + var container = $("

").appendTo("body") + .css({position: "absolute", bottom: 0, left: 0, textAlign: "right", width: 300, height: 300}) + , p = $("

").appendTo(container) + , tooltiped = $("Hover me") + .css({marginTop: 200}) + .appendTo(p) + .tooltip({placement: "top", animate: false}) + .tooltip("show") + + stop() + + setTimeout(function(){ + var arrow = container.find(".tooltip-arrow") + + start() + ok(Math.abs(arrow.offset().left - tooltiped.offset().left - tooltiped.outerWidth()/2) <= 1) + container.remove() + }, 100) + }) }) diff --git a/less/tooltip.less b/less/tooltip.less index 59b02cd4314c..d5a2bfaba642 100644 --- a/less/tooltip.less +++ b/less/tooltip.less @@ -9,15 +9,14 @@ z-index: @zindexTooltip; display: block; visibility: visible; - padding: 5px; font-size: 11px; line-height: 1.4; .opacity(0); &.in { .opacity(80); } - &.top { margin-top: -3px; } - &.right { margin-left: 3px; } - &.bottom { margin-top: 3px; } - &.left { margin-left: -3px; } + &.top { margin-top: -3px; padding: 5px 0;} + &.right { margin-left: 3px; padding: 0 5px;} + &.bottom { margin-top: 3px; padding: 5px 0;} + &.left { margin-left: -3px; padding: 0 5px;} } // Wrapper for the tooltip content