From 85cc3ca4a95e04e1994f1d53a530464e4807cf33 Mon Sep 17 00:00:00 2001 From: Tasos Bekos Date: Mon, 16 Dec 2013 00:33:44 +0100 Subject: [PATCH] fix(tooltip): update placement on content change Since the recompute of position is a heavy calculation and given that this happens only when tooltip is visible, ie position is already calculated, we can reuse it to update the position when widht/height changes. Closes #96 --- src/tooltip/test/tooltip2.spec.js | 38 +++++++++++++++++++++++++++++-- src/tooltip/tooltip.js | 22 ++++++++++++------ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/tooltip/test/tooltip2.spec.js b/src/tooltip/test/tooltip2.spec.js index bb7e6ebba5..586f9060dd 100644 --- a/src/tooltip/test/tooltip2.spec.js +++ b/src/tooltip/test/tooltip2.spec.js @@ -1,14 +1,15 @@ describe('tooltip directive', function () { - var $rootScope, $compile, $document, $timeout; + var $rootScope, $compile, $document, $timeout, $position; beforeEach(module('ui.bootstrap.tooltip')); beforeEach(module('template/tooltip/tooltip-popup.html')); - beforeEach(inject(function (_$rootScope_, _$compile_, _$document_, _$timeout_) { + beforeEach(inject(function (_$rootScope_, _$compile_, _$document_, _$timeout_, _$position_) { $rootScope = _$rootScope_; $compile = _$compile_; $document = _$document_; $timeout = _$timeout_; + $position = _$position_; })); beforeEach(function(){ @@ -102,4 +103,37 @@ describe('tooltip directive', function () { }); }); + + describe('position', function() { + + beforeEach(function() { + spyOn($position, 'position').andCallThrough(); + }); + + it('is called once on mouse enter and leave', function () { + var fragment = compileTooltip('Trigger here'); + + expect($position.position).not.toHaveBeenCalled(); + + fragment.find('span').trigger( 'mouseenter' ); + expect($position.position.calls.length).toEqual(1); + + closeTooltip(fragment.find('span')); + expect($position.position.calls.length).toEqual(1); + }); + + it('is called once for content updates when is open', function () { + $rootScope.content = 'some text'; + var fragment = compileTooltip('Trigger here'); + + expect($position.position).not.toHaveBeenCalled(); + + fragment.find('span').trigger( 'mouseenter' ); + expect($position.position.calls.length).toEqual(1); + + $rootScope.content = 'some new text'; + $rootScope.$digest(); + expect($position.position.calls.length).toEqual(1); + }); + }); }); \ No newline at end of file diff --git a/src/tooltip/tooltip.js b/src/tooltip/tooltip.js index f6d116647f..5adb707a8a 100644 --- a/src/tooltip/tooltip.js +++ b/src/tooltip/tooltip.js @@ -64,7 +64,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap * Returns the actual instance of the $tooltip service. * TODO support multiple triggers */ - this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) { + this.$get = [ '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $compile, $timeout, $parse, $document, $position, $interpolate ) { return function $tooltip ( type, prefix, defaultTriggerShow ) { var options = angular.extend( {}, defaultOptions, globalOptions ); @@ -116,14 +116,12 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap var triggers = getTriggers( undefined ); var hasRegisteredTriggers = false; var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']); + var position; var positionTooltip = function (){ - var position, - ttWidth, + var ttWidth, ttHeight, ttPosition; - // Get the position of the directive element. - position = appendToBody ? $position.offset( element ) : $position.position( element ); // Get the height and width of the tooltip so we can center it. ttWidth = tooltip.prop( 'offsetWidth' ); @@ -222,7 +220,11 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap } else { element.after( tooltip ); } + + // Get the position of the directive element. + position = appendToBody ? $position.offset( element ) : $position.position( element ); + // Place tooltip positionTooltip(); // And show the tooltip. @@ -259,8 +261,14 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap attrs.$observe( type, function ( val ) { scope.tt_content = val; - if (!val && scope.tt_isOpen ) { - hide(); + if (scope.tt_isOpen) { + if (!val) { + hide(); + } else { + // Wait DOM to be updated and adjust position based on the new tooltip dimensions + // and the last known position of the directive element. + scope.$evalAsync(positionTooltip); + } } });