diff --git a/docs/_includes/js/popovers.html b/docs/_includes/js/popovers.html index dadddafc34da61caec24c5f5085afb8cf4443d88..a782a12047521bd3fddee562617990c7c6f0f0e6 100644 --- a/docs/_includes/js/popovers.html +++ b/docs/_includes/js/popovers.html @@ -233,10 +233,11 @@ sagittis lacus vel augue laoreet rutrum faucibus."> </tr> <tr> <td>viewport</td> - <td>string | object</td> + <td>string | object | function</td> <td>{ selector: 'body', padding: 0 }</td> <td> <p>Keeps the popover within the bounds of this element. Example: <code>viewport: '#viewport'</code> or <code>{ "selector": "#viewport", "padding": 0 }</code></p> + <p>If a function is given, it is called with the triggering element DOM node as its only argument. The <code>this</code> context is set to the popover instance.</p> </td> </tr> </tbody> diff --git a/docs/_includes/js/tooltips.html b/docs/_includes/js/tooltips.html index a8914b180eb79b133b18051095ce1acc1044275a..5b399a5f38d23391dca6a4f71b91497af8a30a7a 100644 --- a/docs/_includes/js/tooltips.html +++ b/docs/_includes/js/tooltips.html @@ -199,10 +199,11 @@ $('#example').tooltip(options) </tr> <tr> <td>viewport</td> - <td>string | object</td> + <td>string | object | function</td> <td>{ selector: 'body', padding: 0 }</td> <td> <p>Keeps the tooltip within the bounds of this element. Example: <code>viewport: '#viewport'</code> or <code>{ "selector": "#viewport", "padding": 0 }</code></p> + <p>If a function is given, it is called with the triggering element DOM node as its only argument. The <code>this</code> context is set to the tooltip instance.</p> </td> </tr> </tbody> diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js index 8086631c896fe7991a9d950a00b5fd484ca7e4bd..0cb964e9b6fffef97ce3e850393dcd1e2d499b2e 100644 --- a/js/tests/unit/tooltip.js +++ b/js/tests/unit/tooltip.js @@ -733,6 +733,37 @@ $(function () { $styles.remove() }) + QUnit.test('should get viewport element from function', function (assert) { + assert.expect(3) + var styles = '<style>' + + '.tooltip, .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + '.container-viewport { position: absolute; top: 50px; left: 60px; width: 300px; height: 300px; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div class="container-viewport"/>').appendTo(document.body) + var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 50px; left: 350px;"/>').appendTo($container) + $target + .bootstrapTooltip({ + placement: 'bottom', + viewport: function ($element) { + assert.strictEqual($element[0], $target[0], 'viewport function was passed target as argument') + return ($element.closest('.container-viewport')) + } + }) + + $target.bootstrapTooltip('show') + var $tooltip = $container.find('.tooltip') + assert.strictEqual(Math.round($tooltip.offset().left), Math.round(60 + $container.width() - $tooltip[0].offsetWidth)) + + $target.bootstrapTooltip('hide') + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + + $container.remove() + $styles.remove() + }) + 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 diff --git a/js/tooltip.js b/js/tooltip.js index bbff2cdec8fce67073f5aac7069d2f5315c5ac5d..b2d775938afa7e339ecb9ca02f3e605c133e5eec 100644 --- a/js/tooltip.js +++ b/js/tooltip.js @@ -50,7 +50,7 @@ this.type = type this.$element = $(element) this.options = this.getOptions(options) - this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) + this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) 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!')