Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
refactor(tooltip): optimize positioning routine
Browse files Browse the repository at this point in the history
Wrapped position logic in a timeout to ensure the
digest cycle always completes before positioning
the popup.  Also optimized when the calls to
position the popup occur.

Closes #4328
  • Loading branch information
unknown authored and wesleycho committed Sep 2, 2015
1 parent 7556bed commit c7d669f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 37 deletions.
1 change: 0 additions & 1 deletion src/tooltip/test/tooltip.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ describe('tooltip', function() {
elmScope.disabled = true;
elmScope.$digest();

$timeout.flush();
expect(tooltipScope.isOpen).toBe(false);
});

Expand Down
72 changes: 36 additions & 36 deletions src/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b
var tooltipLinkedScope;
var transitionTimeout;
var popupTimeout;
var positionTimeout;
var appendToBody = angular.isDefined(options.appendToBody) ? options.appendToBody : false;
var triggers = getTriggers(undefined);
var hasEnableExp = angular.isDefined(attrs[prefix + 'Enable']);
Expand All @@ -132,24 +133,27 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b

var positionTooltip = function() {
if (!tooltip) { return; }

// Reset the positioning and box size for correct width and height values.
tooltip.css({ top: 0, left: 0, width: 'auto', height: 'auto' });

var ttBox = $position.position(tooltip);
var ttCss = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
ttCss.top += 'px';
ttCss.left += 'px';

ttCss.width = ttBox.width + 'px';
ttCss.height = ttBox.height + 'px';

// Now set the calculated positioning and size.
tooltip.css(ttCss);
};

var positionTooltipAsync = function() {
$timeout(positionTooltip, 0, false);
if (!positionTimeout) {
positionTimeout = $timeout(function() {
// Reset the positioning and box size for correct width and height values.
tooltip.css({ top: 0, left: 0, width: 'auto', height: 'auto' });

var ttBox = $position.position(tooltip);
var ttCss = $position.positionElements(element, tooltip, ttScope.placement, appendToBody);
ttCss.top += 'px';
ttCss.left += 'px';

ttCss.width = ttBox.width + 'px';
ttCss.height = ttBox.height + 'px';

// Now set the calculated positioning and size.
tooltip.css(ttCss);

positionTimeout = null;

}, 0, false);
}
};

// Set up the correct scope to allow transclusion later
Expand Down Expand Up @@ -180,10 +184,9 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b
// This happens if show is triggered multiple times before any hide is triggered.
if (!popupTimeout) {
popupTimeout = $timeout(show, ttScope.popupDelay, false);
popupTimeout.then(function(reposition) { reposition(); });
}
} else {
show()();
show();
}
}

Expand Down Expand Up @@ -212,11 +215,6 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b

createTooltip();

// Set the initial positioning.
tooltip.css({ top: 0, left: 0, display: 'block' });

positionTooltip();

// And show the tooltip.
ttScope.isOpen = true;
if (isOpenExp) {
Expand All @@ -227,9 +225,9 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b
ttScope.$apply(); // digest required as $apply is not called
}

// Return positioning function as promise callback for correct
// positioning after draw.
return positionTooltip;
tooltip.css({ display: 'block' });

positionTooltip();
}

// Hide the tooltip popup element.
Expand All @@ -244,6 +242,9 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b
$timeout.cancel(popupTimeout);
popupTimeout = null;

$timeout.cancel(positionTimeout);
positionTimeout = null;

// And now we remove it from the DOM. However, if we have animation, we
// need to wait for it to expire beforehand.
// FIXME: this is a placeholder for a port of the transitions library.
Expand Down Expand Up @@ -283,7 +284,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b
tooltipLinkedScope.$$postDigest(function() {
repositionScheduled = false;
if (ttScope.isOpen) {
positionTooltipAsync();
positionTooltip();
}
});
}
Expand Down Expand Up @@ -324,7 +325,7 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b
if (!val && ttScope.isOpen) {
hide();
} else {
positionTooltipAsync();
positionTooltip();
}
});
}
Expand All @@ -342,15 +343,13 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b

attrs.$observe(prefix + 'Title', function(val) {
ttScope.title = val;
positionTooltipAsync();
positionTooltip();
});

attrs.$observe(prefix + 'Placement', function() {
if (ttScope.isOpen) {
$timeout(function() {
prepPlacement();
show()();
}, 0, false);
prepPlacement();
positionTooltip();
}
});

Expand Down Expand Up @@ -425,8 +424,9 @@ angular.module('ui.bootstrap.tooltip', ['ui.bootstrap.position', 'ui.bootstrap.b

// Make sure tooltip is destroyed and removed.
scope.$on('$destroy', function onDestroyTooltip() {
$timeout.cancel( transitionTimeout );
$timeout.cancel( popupTimeout );
$timeout.cancel(transitionTimeout);
$timeout.cancel(popupTimeout);
$timeout.cancel(positionTimeout);
unregisterTriggers();
removeTooltip();
ttScope = null;
Expand Down

0 comments on commit c7d669f

Please sign in to comment.