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

Commit f45b82e

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 c3d6215 commit f45b82e

File tree

2 files changed

+272
-86
lines changed

2 files changed

+272
-86
lines changed

src/ng/anchorScroll.js

Lines changed: 38 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -169,46 +169,16 @@ 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-
204-
// helper function to get first anchor from a NodeList
205-
// can't use filter.filter, as it accepts only instances of Array
206-
// and IE can't convert NodeList to an array using [].slice
207-
// TODO(vojta): use filter if we change it to accept lists as well
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.)
208175
function getFirstAnchor(list) {
209176
var result = null;
210-
forEach(list, function(element) {
211-
if (!result && nodeName_(element) === 'a') result = element;
177+
Array.prototype.some.call(list, function(element) {
178+
if (nodeName_(element) === 'a') {
179+
result = element;
180+
return true;
181+
}
212182
});
213183
return result;
214184
}
@@ -217,31 +187,21 @@ function $AnchorScrollProvider() {
217187

218188
var offset = scroll.yOffset;
219189

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

247207
return offset;
@@ -252,16 +212,23 @@ function $AnchorScrollProvider() {
252212
elem.scrollIntoView();
253213

254214
var offset = getYOffset();
255-
// `offset` is the number of pixels we should scroll up in order to align `elem` properly.
256-
// This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
257-
// top of the viewport. IF the number of pixels from the top of `elem` to the end of page's
258-
// content is less than the height of the viewport, then `elem.scrollIntoView()` will NOT
259-
// align the top of `elem` at the top of the viewport (but further down). This is often the
260-
// case for elements near the bottom of the page.
261-
// In such cases we do not need to scroll the whole `offset` up, just the fraction of the
262-
// offset that is necessary to align the top of `elem` at the desired position.
263-
var necessaryOffset = offset && (offset - (offsetTopGetter(elem) - document.body.scrollTop));
264-
$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+
}
265232
} else {
266233
$window.scrollTo(0, 0);
267234
}

0 commit comments

Comments
 (0)