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

Commit d03bd9f

Browse files
author
Ken Sheedlo
committed
fix(position): improve placing around corners
1 parent e432059 commit d03bd9f

File tree

2 files changed

+87
-59
lines changed

2 files changed

+87
-59
lines changed

src/position/position.js

Lines changed: 82 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,74 @@ angular.module('ui.bootstrap.position', [])
2525
return (getStyle(element, 'position') || 'static' ) === 'static';
2626
}
2727

28+
/**
29+
* Computes the `left` position property of a target element to be
30+
* positioned.
31+
* @param place the placement of the target element relative to the
32+
* host. For instance, place `'bottom'` means the target element
33+
* will be placed below the host.
34+
* @param align the alignment of the element relative to the host.
35+
* For instance, align `'left'` means align the element with the host's
36+
* left edge. `'center'` may be passed to center the element.
37+
* @param hostElPos the host element position, having at least a `width`
38+
* and `left` property.
39+
* @param targetElWidth the width of the target element as a number of
40+
* pixels.
41+
*/
42+
function computeLeftProperty(place, align, hostElPos, targetElWidth) {
43+
if (place === 'left') {
44+
return hostElPos.left - targetElWidth;
45+
}
46+
47+
if (place === 'top' || place === 'bottom') {
48+
if (align === 'left') {
49+
return hostElPos.left;
50+
}
51+
if (align === 'center') {
52+
return (hostElPos.left + hostElPos.width / 2) - (targetElWidth / 2);
53+
}
54+
// align === 'right'
55+
return (hostElPos.left + hostElPos.width) - targetElWidth;
56+
}
57+
58+
// place === 'right'
59+
return hostElPos.left + hostElPos.width;
60+
}
61+
62+
/**
63+
* Computes the `top` position property of a target element to be
64+
* positioned.
65+
* @param place the placement of the target element relative to the
66+
* host. For instance, place `'bottom'` means the target element
67+
* will be placed below the host.
68+
* @param align the alignment of the element relative to the host.
69+
* For instance, align `'left'` means align the element with the host's
70+
* left edge. `'center'` may be passed to center the element.
71+
* @param hostElPos the host element position, having at least a `height`
72+
* and `top` property.
73+
* @param targetElHeight the height of the target element as a number of
74+
* pixels.
75+
*/
76+
function computeTopProperty(place, align, hostElPos, targetElHeight) {
77+
if (place === 'top') {
78+
return hostElPos.top - targetElHeight;
79+
}
80+
81+
if (place === 'right' || place === 'left') {
82+
if (align === 'top') {
83+
return hostElPos.top;
84+
}
85+
if (align === 'center') {
86+
return (hostElPos.top + hostElPos.height / 2) - (targetElHeight / 2);
87+
}
88+
// align === 'bottom'
89+
return (hostElPos.top + hostElPos.height) - targetElHeight;
90+
}
91+
92+
// place === 'bottom'
93+
return hostElPos.top + hostElPos.height;
94+
}
95+
2896
/**
2997
* returns the closest, non-statically positioned parentOffset of a given element
3098
* @param element
@@ -81,70 +149,30 @@ angular.module('ui.bootstrap.position', [])
81149
*/
82150
positionElements: function(hostEl, targetEl, positionStr, appendToBody) {
83151
var positionStrParts = positionStr.split('-');
84-
var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center';
152+
var place = positionStrParts[0],
153+
align = positionStrParts[1] || 'center',
154+
targetElPos = {};
85155

86156
var hostElPos,
87157
targetElWidth,
88-
targetElHeight,
89-
targetElPos;
158+
targetElHeight;
159+
160+
if (place !== 'top' && place !== 'right' && place !== 'bottom' && place !== 'left') {
161+
place = 'top';
162+
}
163+
if (align !== 'top' && align !== 'right' && align !== 'bottom' && align !== 'left' && align !== 'center') {
164+
align = 'center';
165+
}
90166

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

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

96-
var shiftWidth = {
97-
center: function() {
98-
return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
99-
},
100-
left: function() {
101-
return hostElPos.left;
102-
},
103-
right: function() {
104-
return hostElPos.left + hostElPos.width;
105-
}
106-
};
107-
108-
var shiftHeight = {
109-
center: function() {
110-
return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
111-
},
112-
top: function() {
113-
return hostElPos.top;
114-
},
115-
bottom: function() {
116-
return hostElPos.top + hostElPos.height;
117-
}
172+
return {
173+
top: computeTopProperty(place, align, hostElPos, targetElHeight),
174+
left: computeLeftProperty(place, align, hostElPos, targetElWidth)
118175
};
119-
120-
switch (pos0) {
121-
case 'right':
122-
targetElPos = {
123-
top: shiftHeight[pos1](),
124-
left: shiftWidth[pos0]()
125-
};
126-
break;
127-
case 'left':
128-
targetElPos = {
129-
top: shiftHeight[pos1](),
130-
left: hostElPos.left - targetElWidth
131-
};
132-
break;
133-
case 'bottom':
134-
targetElPos = {
135-
top: shiftHeight[pos0](),
136-
left: shiftWidth[pos1]()
137-
};
138-
break;
139-
default:
140-
targetElPos = {
141-
top: hostElPos.top - targetElHeight,
142-
left: shiftWidth[pos1]()
143-
};
144-
break;
145-
}
146-
147-
return targetElPos;
148176
}
149177
};
150178
}]);

src/position/test/position.spec.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('position elements', function () {
6363
});
6464

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

6969
it('should position elements on bottom-center when "bottom" specified', function() {
@@ -76,7 +76,7 @@ describe('position elements', function () {
7676
});
7777

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

8282
it('should position elements on left-center when "left" specified', function() {
@@ -89,7 +89,7 @@ describe('position elements', function () {
8989
});
9090

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

9595
it('should position elements on right-center when "right" specified', function() {
@@ -101,8 +101,8 @@ describe('position elements', function () {
101101
expect($position.positionElements({}, new TargetElMock(10, 10), 'right-top')).toBePositionedAt(100, 120);
102102
});
103103

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

0 commit comments

Comments
 (0)