Skip to content

Commit 5bf6a63

Browse files
author
Joel Steres
committed
Compensate for positioned HTML element
1 parent 66baec7 commit 5bf6a63

File tree

3 files changed

+118
-26
lines changed

3 files changed

+118
-26
lines changed

src/core.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// useful private variables
1111
var $document = $(document),
1212
$window = $(window),
13+
$html = $(document.documentElement),
1314
$body = $('body');
1415

1516
// constants

src/utility.js

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -207,38 +207,51 @@ function countFlags(value) {
207207
}
208208

209209
/**
210-
* Compute compensating position offsets if body element has non-standard position attribute.
210+
* Compute compensating position offsets if body or html element has non-static position attribute.
211211
* @private
212212
* @param {number} windowWidth Window width in pixels.
213213
* @param {number} windowHeight Window height in pixels.
214214
* @return {Offsets} The top, left, right, bottom offset in pixels
215215
*/
216216
function computePositionCompensation(windowWidth, windowHeight) {
217-
var bodyWidthWithMargin,
218-
bodyHeightWithMargin,
219-
offsets,
220-
bodyPositionPx;
221-
222-
switch ($body.css('position')) {
223-
case 'absolute':
224-
case 'fixed':
225-
case 'relative':
226-
// jquery offset and position functions return top and left
227-
// offset function computes position + margin
228-
offsets = $body.offset();
229-
bodyPositionPx = $body.position();
230-
// because element might be positioned compute right margin using the different between
231-
// outerWidth computations and add position offset
232-
bodyWidthWithMargin = $body.outerWidth(true);
233-
bodyHeightWithMargin = $body.outerHeight(true);
234-
// right offset = right margin + body right position
235-
offsets.right = (bodyWidthWithMargin - $body.outerWidth() - (offsets.left - bodyPositionPx.left)) + (windowWidth - bodyWidthWithMargin - bodyPositionPx.left);
236-
// bottom offset = bottom margin + body bottom position
237-
offsets.bottom = (bodyHeightWithMargin - $body.outerHeight() - offsets.top) + (windowHeight - bodyHeightWithMargin - bodyPositionPx.top);
238-
break;
239-
default:
240-
// even though body may have offset, no compensation is required
241-
offsets = { top: 0, bottom: 0, left: 0, right: 0 };
217+
// Check if the element is "positioned". A "positioned" element has a CSS
218+
// position value other than static. Whether the element is positioned is
219+
// relevant because absolutely positioned elements are positioned relative
220+
// to the first positioned ancestor rather than relative to the doc origin.
221+
var isPositioned = function(el) {
222+
return el.css('position') !== 'static';
223+
};
224+
225+
var getElementOffsets = function(el) {
226+
var elWidthWithMargin,
227+
elHeightWithMargin,
228+
elPositionPx,
229+
offsets;
230+
// jquery offset and position functions return top and left
231+
// offset function computes position + margin
232+
offsets = el.offset();
233+
elPositionPx = el.position();
234+
235+
// Compute the far margins based off the outerWidth values.
236+
elWidthWithMargin = el.outerWidth(true);
237+
elHeightWithMargin = el.outerHeight(true);
238+
239+
// right offset = right margin + body right position
240+
offsets.right = (elWidthWithMargin - el.outerWidth() - (offsets.left - elPositionPx.left)) + (windowWidth - elWidthWithMargin - elPositionPx.left);
241+
// bottom offset = bottom margin + body bottom position
242+
offsets.bottom = (elHeightWithMargin - el.outerHeight() - offsets.top) + (windowHeight - elHeightWithMargin - elPositionPx.top);
243+
return offsets;
244+
};
245+
246+
var offsets;
247+
248+
if (isPositioned($body)) {
249+
offsets = getElementOffsets($body);
250+
} else if (isPositioned($html)) {
251+
offsets = getElementOffsets($html);
252+
} else {
253+
// even though body may have offset, no compensation is required
254+
offsets = { top: 0, bottom: 0, left: 0, right: 0 };
242255
}
243256

244257
return offsets;

test/htmloffset-rel.html

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!DOCTYPE html>
2+
<html lang="en-US" style="position:relative">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>PowerTip Test Suite</title>
6+
7+
<!-- Library Resources -->
8+
<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
9+
10+
<!-- PowerTip Core Resources -->
11+
<script type="text/javascript" src="../src/core.js"></script>
12+
<script type="text/javascript" src="../src/csscoordinates.js"></script>
13+
<script type="text/javascript" src="../src/displaycontroller.js"></script>
14+
<script type="text/javascript" src="../src/placementcalculator.js"></script>
15+
<script type="text/javascript" src="../src/tooltipcontroller.js"></script>
16+
<script type="text/javascript" src="../src/utility.js"></script>
17+
<link rel="stylesheet" type="text/css" href="../css/jquery.powertip.css" />
18+
19+
<!-- Unit Test Scripts -->
20+
<script type="text/javascript" src="tests-bodyoffset.js"></script>
21+
22+
<!-- Custom Styles For Test Cases -->
23+
<style type="text/css">
24+
header, section { margin-bottom: 20px; }
25+
section { border: 1px solid #CCC; margin: 20px; padding: 20px; }
26+
#powerTip { white-space: normal; }
27+
#huge-text div, #huge-text-smart div { text-align: center; }
28+
#huge-text input, #huge-text-smart input { margin: 10px; padding: 10px; }
29+
#huge-text .east, #huge-text-smart .east { margin-left: 450px; }
30+
#session { position: fixed; right: 10px; top: 10px; font-size: 10px; width: 160px; background-color: #fff; border: 1px solid #ccc; padding: 10px; overflow: hidden; }
31+
#session pre { margin: 0; }
32+
</style>
33+
</head>
34+
<body>
35+
<section id="huge-text">
36+
<h2>Huge Text</h2>
37+
<p>The tooltips for the buttons below have a lot of text. The tooltip div is completely elastic for this demo. The tooltips should be properly placed when they render.</p>
38+
<div>
39+
<input type="button" class="north-west-alt" value="North West Alt" />
40+
<input type="button" class="north-west" value="North West" />
41+
<input type="button" class="north" value="North" />
42+
<input type="button" class="north-east" value="North East" />
43+
<input type="button" class="north-east-alt" value="North East Alt" /><br />
44+
<input type="button" class="west" value="West" />
45+
<input type="button" class="east" value="East" /><br />
46+
<input type="button" class="south-west-alt" value="South West Alt" />
47+
<input type="button" class="south-west" value="South West" />
48+
<input type="button" class="south" value="South" />
49+
<input type="button" class="south-east" value="South East" />
50+
<input type="button" class="south-east-alt" value="South East Alt" />
51+
</div>
52+
</section>
53+
<section id="huge-text-smart">
54+
<h2>Huge Text with Smart Placement</h2>
55+
<p>The tooltips for the buttons below have a lot of text. The tooltip div is completely elastic for this demo. The tooltips should be properly placed when they render.</p>
56+
<div>
57+
<input type="button" class="north-west-alt" value="North West Alt" />
58+
<input type="button" class="north-west" value="North West" />
59+
<input type="button" class="north" value="North" />
60+
<input type="button" class="north-east" value="North East" />
61+
<input type="button" class="north-east-alt" value="North East Alt" /><br />
62+
<input type="button" class="west" value="West" />
63+
<input type="button" class="east" value="East" /><br />
64+
<input type="button" class="south-west-alt" value="South West Alt" />
65+
<input type="button" class="south-west" value="South West" />
66+
<input type="button" class="south" value="South" />
67+
<input type="button" class="south-east" value="South East" />
68+
<input type="button" class="south-east-alt" value="South East Alt" />
69+
</div>
70+
</section>
71+
<section id="trapped-mousefollow" data-powertip="This is the tooltip text.&lt;br /&gt;It is tall so you can test the padding.">
72+
<h2>Trapped mouse following tooltip</h2>
73+
<p>This box has a mouse following tooltip.</p>
74+
<p>Trap it in the bottom right corner of the viewport. It should flip out of the way. It should not flip if it only hits one edge.</p>
75+
</section>
76+
<div id="session"><pre /></div>
77+
</body>
78+
</html>

0 commit comments

Comments
 (0)