@@ -169,38 +169,9 @@ function $AnchorScrollProvider() {
169
169
this . $get = [ '$window' , '$location' , '$rootScope' , function ( $window , $location , $rootScope ) {
170
170
var document = $window . document ;
171
171
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.)
204
175
function getFirstAnchor ( list ) {
205
176
var result = null ;
206
177
Array . prototype . some . call ( list , function ( element ) {
@@ -216,31 +187,21 @@ function $AnchorScrollProvider() {
216
187
217
188
var offset = scroll . yOffset ;
218
189
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' ) {
242
196
offset = 0 ;
197
+ } else {
198
+ var rect = elem . getBoundingClientRect ( ) ;
199
+ var top = rect . top ;
200
+ var height = rect . height ;
201
+ offset = top + height ;
243
202
}
203
+ } else if ( ! isNumber ( offset ) ) {
204
+ offset = 0 ;
244
205
}
245
206
246
207
return offset ;
@@ -251,16 +212,23 @@ function $AnchorScrollProvider() {
251
212
elem . scrollIntoView ( ) ;
252
213
253
214
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
+ }
264
232
} else {
265
233
$window . scrollTo ( 0 , 0 ) ;
266
234
}
0 commit comments