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

Commit

Permalink
feat(tooltip): support more positioning options
Browse files Browse the repository at this point in the history
Closes #1676
  • Loading branch information
pkozlowski-opensource committed Jan 30, 2014
1 parent 1ba07c1 commit 3704db9
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 41 deletions.
72 changes: 72 additions & 0 deletions src/position/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,78 @@ angular.module('ui.bootstrap.position', [])
top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop),
left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
};
},

/**
* Provides coordinates for the targetEl in relation to hostEl
*/
positionElements: function (hostEl, targetEl, positionStr, appendToBody) {

var positionStrParts = positionStr.split('-');
var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center';

var hostElPos,
targetElWidth,
targetElHeight,
targetElPos;

hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl);

targetElWidth = targetEl.prop('offsetWidth');
targetElHeight = targetEl.prop('offsetHeight');

var shiftWidth = {
center: function () {
return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
},
left: function () {
return hostElPos.left;
},
right: function () {
return hostElPos.left + hostElPos.width;
}
};

var shiftHeight = {
center: function () {
return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
},
top: function () {
return hostElPos.top;
},
bottom: function () {
return hostElPos.top + hostElPos.height;
}
};

switch (pos0) {
case 'right':
targetElPos = {
top: shiftHeight[pos1](),
left: shiftWidth[pos0]()
};
break;
case 'left':
targetElPos = {
top: shiftHeight[pos1](),
left: hostElPos.left - targetElWidth
};
break;
case 'bottom':
targetElPos = {
top: shiftHeight[pos0](),
left: shiftWidth[pos1]()
};
break;
default:
targetElPos = {
top: hostElPos.top - targetElHeight,
left: shiftWidth[pos1]()
};
break;
}

return targetElPos;
}
};
}]);
99 changes: 99 additions & 0 deletions src/position/test/position.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
describe('position elements', function () {

var TargetElMock = function(width, height) {
this.width = width;
this.height = height;

this.prop = function(propName) {
return propName === 'offsetWidth' ? width : height;
};
};

var $position;

beforeEach(module('ui.bootstrap.position'));
beforeEach(inject(function (_$position_) {
$position = _$position_;
}));
beforeEach(function () {
this.addMatchers({
toBePositionedAt: function(top, left) {
this.message = function() {
return 'Expected "(' + this.actual.top + ', ' + this.actual.left + ')" to be positioned at (' + top + ', ' + left + ')';
};

return this.actual.top == top && this.actual.left == left;
}
});
});


describe('append-to-body: false', function () {

beforeEach(function () {
//mock position info normally queried from the DOM
$position.position = function() {
return {
width: 20,
height: 20,
top: 100,
left: 100
};
};
});

it('should position element on top-center by default', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'other')).toBePositionedAt(90, 105);
expect($position.positionElements({}, new TargetElMock(10, 10), 'top')).toBePositionedAt(90, 105);
expect($position.positionElements({}, new TargetElMock(10, 10), 'top-center')).toBePositionedAt(90, 105);
});

it('should position on top-left', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'top-left')).toBePositionedAt(90, 100);
});

it('should position on top-right', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'top-right')).toBePositionedAt(90, 120);
});

it('should position elements on bottom-center when "bottom" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'bottom')).toBePositionedAt(120, 105);
expect($position.positionElements({}, new TargetElMock(10, 10), 'bottom-center')).toBePositionedAt(120, 105);
});

it('should position elements on bottom-left', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'bottom-left')).toBePositionedAt(120, 100);
});

it('should position elements on bottom-right', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'bottom-right')).toBePositionedAt(120, 120);
});

it('should position elements on left-center when "left" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'left')).toBePositionedAt(105, 90);
expect($position.positionElements({}, new TargetElMock(10, 10), 'left-center')).toBePositionedAt(105, 90);
});

it('should position elements on left-top when "left-top" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'left-top')).toBePositionedAt(100, 90);
});

it('should position elements on left-bottom when "left-bottom" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'left-bottom')).toBePositionedAt(120, 90);
});

it('should position elements on right-center when "right" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'right')).toBePositionedAt(105, 120);
expect($position.positionElements({}, new TargetElMock(10, 10), 'right-center')).toBePositionedAt(105, 120);
});

it('should position elements on right-top when "right-top" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'right-top')).toBePositionedAt(100, 120);
});

it('should position elements on right-top when "right-top" specified', function () {
expect($position.positionElements({}, new TargetElMock(10, 10), 'right-bottom')).toBePositionedAt(120, 120);
});
});

});
43 changes: 2 additions & 41 deletions src/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,53 +119,14 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
var triggers = getTriggers( undefined );
var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']);

var positionTooltip = function (){
var position,
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' );
ttHeight = tooltip.prop( 'offsetHeight' );

// Calculate the tooltip's top and left coordinates to center it with
// this directive.
switch ( scope.tt_placement ) {
case 'right':
ttPosition = {
top: position.top + position.height / 2 - ttHeight / 2,
left: position.left + position.width
};
break;
case 'bottom':
ttPosition = {
top: position.top + position.height,
left: position.left + position.width / 2 - ttWidth / 2
};
break;
case 'left':
ttPosition = {
top: position.top + position.height / 2 - ttHeight / 2,
left: position.left - ttWidth
};
break;
default:
ttPosition = {
top: position.top - ttHeight,
left: position.left + position.width / 2 - ttWidth / 2
};
break;
}
var positionTooltip = function () {

var ttPosition = $position.positionElements(element, tooltip, scope.tt_placement, appendToBody);
ttPosition.top += 'px';
ttPosition.left += 'px';

// Now set the calculated positioning.
tooltip.css( ttPosition );

};

// By default, the tooltip is not open.
Expand Down

0 comments on commit 3704db9

Please sign in to comment.