Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit ea8aba8

Browse files
committed
test($anchorScroll.yOffset): add tests for $anchorScroll.yOffset
Add tests for `$anchorScroll.yOffset` and make some necessary modifications to the existing test helper functions. (Also, refactor the $anchorScroll code to get rid of IE8-specific stuff and simplify.)
1 parent 09086a3 commit ea8aba8

File tree

2 files changed

+267
-80
lines changed

2 files changed

+267
-80
lines changed

src/ng/anchorScroll.js

Lines changed: 33 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -169,38 +169,9 @@ function $AnchorScrollProvider() {
169169
this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
170170
var document = $window.document;
171171

172-
// Helper function to increase code readability and DRYness
173-
function asInt(val) {
174-
return parseInt(val, 10) || 0;
175-
}
176-
177-
// IE8 does not support `window.getComputedStyle()`, but it's proprietary `elem.currentStyle`
178-
// seems to work the same. If neither exists, fall back to `elem.style`.
179-
function computedStyleGetter(elem) {
180-
return $window.getComputedStyle ?
181-
$window.getComputedStyle(elem) :
182-
elem.currentStyle || elem.style || {};
183-
}
184-
185-
// `offsetTop` works consistently across browsers, but returns the offset from the element's
186-
// "offsetParent", which is (either <body> or the first ancestor with `position !== 'static'` or
187-
// (if elem has `position: static`) a <table>, <th>, <td>).
188-
// This function will recursively add the offsetTop of each offsetParent along with the width of
189-
// its top-border.
190-
function offsetTopGetter(elem) {
191-
var totalOffsetTop = asInt(elem.offsetTop);
192-
193-
while (elem = elem.offsetParent) {
194-
var computedStyle = computedStyleGetter(elem);
195-
var borderTop = asInt(computedStyle.borderTopWidth);
196-
var offsetTop = asInt(elem.offsetTop);
197-
totalOffsetTop += offsetTop + borderTop;
198-
}
199-
200-
return totalOffsetTop;
201-
}
202-
203-
172+
// Helper function to get first anchor from a NodeList
173+
// (using `Array#some()` instead of `angular#forEach()` since it's more performant
174+
// and working in all supported browsers.)
204175
function getFirstAnchor(list) {
205176
var result = null;
206177
Array.prototype.some.call(list, function(element) {
@@ -216,31 +187,21 @@ function $AnchorScrollProvider() {
216187

217188
var offset = scroll.yOffset;
218189

219-
if (!offset) {
220-
offset = 0;
221-
} else if (!isNumber(offset)) {
222-
if (isFunction(offset)) {
223-
offset = asInt(offset());
224-
} else if (isElement(offset)) {
225-
var elem = offset[0];
226-
227-
var style = computedStyleGetter(elem);
228-
if (style.position !== 'fixed') {
229-
offset = 0;
230-
} else {
231-
// TODO: Make sure this works well on all supported browsers.
232-
// Tested on Chrome 37, Firefox 32 and IE8-IE11 and works as expected.
233-
// I.e. `elem.offsetHeight` consistently accounts for the height of the content,
234-
// the padding, the scrollbars (if any) and the border of the element
235-
// (for both `content-box` and `border-box` boxSizings).
236-
// (See also this fiddle: http://jsfiddle.net/ExpertSystem/5dx7fg2r/)
237-
var top = offsetTopGetter(elem.offsetTop);
238-
var height = asInt(elem.offsetHeight);
239-
offset = top + height;
240-
}
241-
} else {
190+
if (isFunction(offset)) {
191+
offset = offset();
192+
} else if (isElement(offset)) {
193+
var elem = offset[0];
194+
var style = $window.getComputedStyle(elem);
195+
if (style.position !== 'fixed') {
242196
offset = 0;
197+
} else {
198+
var rect = elem.getBoundingClientRect();
199+
var top = rect.top;
200+
var height = rect.height;
201+
offset = top + height;
243202
}
203+
} else if (!isNumber(offset)) {
204+
offset = 0;
244205
}
245206

246207
return offset;
@@ -251,16 +212,23 @@ function $AnchorScrollProvider() {
251212
elem.scrollIntoView();
252213

253214
var offset = getYOffset();
254-
// `offset` is the number of pixels we should scroll up in order to align `elem` properly.
255-
// This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
256-
// top of the viewport. IF the number of pixels from the top of `elem` to the end of page's
257-
// content is less than the height of the viewport, then `elem.scrollIntoView()` will NOT
258-
// align the top of `elem` at the top of the viewport (but further down). This is often the
259-
// case for elements near the bottom of the page.
260-
// In such cases we do not need to scroll the whole `offset` up, just the fraction of the
261-
// offset that is necessary to align the top of `elem` at the desired position.
262-
var necessaryOffset = offset && (offset - (offsetTopGetter(elem) - document.body.scrollTop));
263-
$window.scrollBy(0, -1 * necessaryOffset);
215+
216+
if (offset) {
217+
// `offset` is the number of pixels we should scroll up in order to align `elem` properly.
218+
// This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
219+
// top of the viewport. IF the number of pixels from the top of `elem` to the end of page's
220+
// content is less than the height of the viewport, then `elem.scrollIntoView()` will NOT
221+
// align the top of `elem` at the top of the viewport (but further down). This is often the
222+
// case for elements near the bottom of the page.
223+
// In such cases we do not need to scroll the whole `offset` up, just the fraction of the
224+
// offset that is necessary to align the top of `elem` at the desired position.
225+
var body = document.body;
226+
var bodyRect = body.getBoundingClientRect();
227+
var elemRect = elem.getBoundingClientRect();
228+
var necessaryOffset = offset - (elemRect.top - (bodyRect.top + body.scrollTop));
229+
230+
$window.scrollBy(0, -1 * necessaryOffset);
231+
}
264232
} else {
265233
$window.scrollTo(0, 0);
266234
}

0 commit comments

Comments
 (0)