Skip to content

Commit 01e9009

Browse files
lskramarovmgcrea
authored andcommitted
feat(tooltip): Added exotic positions left-top, left-bottom, right-top, right-bottom
1 parent c902f7e commit 01e9009

File tree

2 files changed

+70
-34
lines changed

2 files changed

+70
-34
lines changed

src/tooltip/test/tooltip.spec.js

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ describe('tooltip', function() {
9696
'options-placement-exotic-bottom-right': {
9797
element: '<a data-placement="bottom-right" bs-tooltip="tooltip" data-viewport="null">hover me</a>'
9898
},
99+
'options-placement-exotic-right-top': {
100+
element: '<a data-placement="right-top" bs-tooltip="tooltip" data-viewport="null">hover me</a>'
101+
},
102+
'options-placement-exotic-right-bottom': {
103+
element: '<a data-placement="right-bottom" bs-tooltip="tooltip" data-viewport="null">hover me</a>'
104+
},
105+
'options-placement-exotic-left-top': {
106+
element: '<a data-placement="left-top" bs-tooltip="tooltip" data-viewport="null">hover me</a>'
107+
},
108+
'options-placement-exotic-left-bottom': {
109+
element: '<a data-placement="left-bottom" bs-tooltip="tooltip" data-viewport="null">hover me</a>'
110+
},
99111
'options-placement-auto': {
100112
element: '<a data-placement="auto" bs-tooltip="tooltip" data-viewport="null">hover me</a>'
101113
},
@@ -768,7 +780,7 @@ describe('tooltip', function() {
768780

769781
$$rAF.flush();
770782
expect(sandboxEl.children('.tooltip').hasClass('top')).toBeTruthy();
771-
})
783+
});
772784

773785
it('should remove `auto` from exotic placements when auto positioning', function () {
774786
var elm = compileDirective('options-placement-auto-exotic-top-left');
@@ -780,7 +792,7 @@ describe('tooltip', function() {
780792

781793
$$rAF.flush();
782794
expect(sandboxEl.children('.tooltip').hasClass('bottom-right')).toBeTruthy();
783-
})
795+
});
784796

785797
it('should default to `top` when `auto` placement is set without a preference', function () {
786798
var elm = compileDirective('options-placement-auto');
@@ -978,7 +990,7 @@ describe('tooltip', function() {
978990
placements[placement] = {
979991
top: tipElement.style.top,
980992
left: tipElement.style.left,
981-
}
993+
};
982994

983995
// Clear the sandbox after we've rendered
984996
// each tooltip
@@ -989,7 +1001,7 @@ describe('tooltip', function() {
9891001
}
9901002

9911003
return placements;
992-
};
1004+
}
9931005

9941006
var standardPlacements,
9951007
autoPlacements,
@@ -1012,6 +1024,10 @@ describe('tooltip', function() {
10121024
'options-placement-exotic-top-right': {},
10131025
'options-placement-exotic-bottom-left': {},
10141026
'options-placement-exotic-bottom-right': {},
1027+
'options-placement-exotic-right-top': {},
1028+
'options-placement-exotic-right-bottom': {},
1029+
'options-placement-exotic-left-top': {},
1030+
'options-placement-exotic-left-bottom': {}
10151031
}, styleEl);
10161032

10171033
autoPlacements = calculatePlacements({
@@ -1022,7 +1038,7 @@ describe('tooltip', function() {
10221038
'options-placement-auto-exotic-top-left': {},
10231039
'options-placement-auto-exotic-top-right': {},
10241040
'options-placement-auto-exotic-bottom-left': {},
1025-
'options-placement-auto-exotic-bottom-right': {},
1041+
'options-placement-auto-exotic-bottom-right': {}
10261042
}, styleEl);
10271043

10281044
// Change the style for viewport testing
@@ -1043,7 +1059,7 @@ describe('tooltip', function() {
10431059
'options-placement-viewport-bottom': {},
10441060
'options-placement-viewport-left': {},
10451061
'options-placement-viewport-padding': {},
1046-
'options-placement-viewport-exotic': {},
1062+
'options-placement-viewport-exotic': {}
10471063
}, styleEl);
10481064
});
10491065

@@ -1130,6 +1146,34 @@ describe('tooltip', function() {
11301146
expect(placement.top).toBe('20px');
11311147
expect(placement.left).toBe('-180px');
11321148
});
1149+
1150+
it('should position the tooltip to the left-top of the target when placement is `left-top`', function () {
1151+
var placement = standardPlacements['options-placement-exotic-left-top'];
1152+
1153+
expect(placement.top).toBe('-80px');
1154+
expect(placement.left).toBe('-200px');
1155+
});
1156+
1157+
it('should position the tooltip to the left-bottom of the target when placement is `left-bottom`', function () {
1158+
var placement = standardPlacements['options-placement-exotic-left-bottom'];
1159+
1160+
expect(placement.top).toBe('0px');
1161+
expect(placement.left).toBe('-200px');
1162+
});
1163+
1164+
it('should position the tooltip to the right-top of the target when placement is `right-top`', function () {
1165+
var placement = standardPlacements['options-placement-exotic-right-top'];
1166+
1167+
expect(placement.top).toBe('-80px');
1168+
expect(placement.left).toBe('20px');
1169+
});
1170+
1171+
it('should position the tooltip to the right-bottom of the target when placement is `right-bottom`', function () {
1172+
var placement = standardPlacements['options-placement-exotic-right-bottom'];
1173+
1174+
expect(placement.top).toBe('0px');
1175+
expect(placement.left).toBe('20px');
1176+
});
11331177
});
11341178

11351179
describe('auto placements', function () {
@@ -1138,7 +1182,7 @@ describe('tooltip', function() {
11381182
var bottom = standardPlacements['options-placement-bottom'];
11391183

11401184
// top is offscreen, so it should swap to bottom and match the standard bottom
1141-
expect(autoTop.top).toBe(bottom.top)
1185+
expect(autoTop.top).toBe(bottom.top);
11421186
expect(autoTop.left).toBe(bottom.left)
11431187
});
11441188

@@ -1147,7 +1191,7 @@ describe('tooltip', function() {
11471191
var left = standardPlacements['options-placement-left'];
11481192

11491193
// right is offscreen, so it should swap to left and match the standard left
1150-
expect(autoRight.top).toBe(left.top)
1194+
expect(autoRight.top).toBe(left.top);
11511195
expect(autoRight.left).toBe(left.left)
11521196
});
11531197

@@ -1156,7 +1200,7 @@ describe('tooltip', function() {
11561200
var top = standardPlacements['options-placement-top'];
11571201

11581202
// bottom is offscreen, so it should swap to top and match the standard top
1159-
expect(autoBottom.top).toBe(top.top)
1203+
expect(autoBottom.top).toBe(top.top);
11601204
expect(autoBottom.left).toBe(top.left)
11611205
});
11621206

@@ -1165,7 +1209,7 @@ describe('tooltip', function() {
11651209
var right = standardPlacements['options-placement-right'];
11661210

11671211
// left is offscreen, so it should swap to right and match the standard right
1168-
expect(autoLeft.top).toBe(right.top)
1212+
expect(autoLeft.top).toBe(right.top);
11691213
expect(autoLeft.left).toBe(right.left)
11701214
});
11711215

@@ -1174,7 +1218,7 @@ describe('tooltip', function() {
11741218
var bottomLeft = standardPlacements['options-placement-exotic-bottom-left'];
11751219

11761220
// should swap to bottom-left and match the standard bottom-left
1177-
expect(autoTopRight.top).toBe(bottomLeft.top)
1221+
expect(autoTopRight.top).toBe(bottomLeft.top);
11781222
expect(autoTopRight.left).toBe(bottomLeft.left)
11791223
});
11801224

@@ -1183,7 +1227,7 @@ describe('tooltip', function() {
11831227
var bottomRight = standardPlacements['options-placement-exotic-bottom-right'];
11841228

11851229
// should swap to bottom-right and match the standard bottom-right
1186-
expect(autoTopLeft.top).toBe(bottomRight.top)
1230+
expect(autoTopLeft.top).toBe(bottomRight.top);
11871231
expect(autoTopLeft.left).toBe(bottomRight.left)
11881232
});
11891233

@@ -1192,7 +1236,7 @@ describe('tooltip', function() {
11921236
var topLeft = standardPlacements['options-placement-exotic-top-left'];
11931237

11941238
// should swap to top-left and match the standard top-left
1195-
expect(autoBottomRight.top).toBe(topLeft.top)
1239+
expect(autoBottomRight.top).toBe(topLeft.top);
11961240
expect(autoBottomRight.left).toBe(topLeft.left)
11971241
});
11981242

@@ -1201,7 +1245,7 @@ describe('tooltip', function() {
12011245
var topRight = standardPlacements['options-placement-exotic-top-right'];
12021246

12031247
// should swap to top-right and match the standard top-right
1204-
expect(autoBottomLeft.top).toBe(topRight.top)
1248+
expect(autoBottomLeft.top).toBe(topRight.top);
12051249
expect(autoBottomLeft.left).toBe(topRight.left)
12061250
});
12071251
});

src/tooltip/tooltip.js

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -357,24 +357,16 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap
357357
var originalPlacement = placement;
358358
var viewportPosition = getPosition($tooltip.$viewport);
359359

360-
// Determine if the vertical placement
361-
if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > viewportPosition.bottom) {
362-
placement = originalPlacement.replace('bottom', 'top');
363-
} else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < viewportPosition.top) {
360+
if (/top/.test(originalPlacement) && elementPosition.bottom + tipHeight > viewportPosition.bottom) {
364361
placement = originalPlacement.replace('top', 'bottom');
362+
} else if (/bottom/.test(originalPlacement) && elementPosition.top - tipHeight < viewportPosition.top) {
363+
placement = originalPlacement.replace('bottom', 'top');
365364
}
366365

367-
// Determine the horizontal placement
368-
// The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right
369-
// and flow in the opposite direction of their placement.
370-
if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&
371-
elementPosition.right + tipWidth > viewportPosition.width) {
372-
373-
placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');
374-
} else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&
375-
elementPosition.left - tipWidth < viewportPosition.left) {
376-
377-
placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');
366+
if (/left/.test(originalPlacement) && elementPosition.left - tipWidth < viewportPosition.left) {
367+
placement = placement.replace('left', 'right');
368+
} else if (/right/.test(originalPlacement) && elementPosition.right + tipWidth > viewportPosition.width) {
369+
placement = placement.replace('right', 'left');
378370
}
379371

380372
tipElement.removeClass(originalPlacement).addClass(placement);
@@ -552,11 +544,11 @@ angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.core', 'mgcrea.ngStrap
552544
}
553545
} else if(split[0] === 'left' || split[0] === 'right') {
554546
switch (split[1]) {
555-
case 'top':
556-
offset.top = position.top - actualHeight;
557-
break;
558-
case 'bottom':
559-
offset.top = position.top + position.height;
547+
case 'top':
548+
offset.top = position.top - actualHeight + position.height;
549+
break;
550+
case 'bottom':
551+
offset.top = position.top;
560552
}
561553
}
562554

0 commit comments

Comments
 (0)