Permalink
Browse files

feat($anchorScroll): allow scrolling to a specified element

Add an optional argument to `$anchorScroll()` to enable scrolling to an
anchor element different than that related to the current value of
`$location.hash()`. If the argument is omitted or is not a string,
the value of `$location.hash()` will be used instead.

Closes #4568
Closes #9596
  • Loading branch information...
gkalpak committed Oct 13, 2014
1 parent 06a9f0a commit 731c8b5e2d01a44aa91f967f1a6acbadb8005a8b
Showing with 112 additions and 38 deletions.
  1. +10 −5 src/ng/anchorScroll.js
  2. +102 −33 test/ng/anchorScrollSpec.js
View
@@ -38,9 +38,10 @@ function $AnchorScrollProvider() {
* @requires $rootScope
*
* @description
* When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
* scrolls to the related element, according to the rules specified in the
* [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
* When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
* current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
* in the
* [HTML5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
*
* It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
* match any anchor whenever it changes. This can be disabled by calling
@@ -49,6 +50,9 @@ function $AnchorScrollProvider() {
* Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
* vertical scroll-offset (either fixed or dynamic).
*
* @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
* {@link ng.$location#hash $location.hash()} will be used.
*
* @property {(number|function|jqLite)} yOffset
* If set, specifies a vertical scroll-offset. This is often useful when there are fixed
* positioned elements at the top of the page, such as navbars, headers etc.
@@ -232,8 +236,9 @@ function $AnchorScrollProvider() {
}
}
function scroll() {
var hash = $location.hash(), elm;
function scroll(hash) {
hash = isString(hash) ? hash : $location.hash();
var elm;
// empty hash, scroll to the top of the page
if (!hash) scrollTo(null);
View
@@ -23,7 +23,6 @@ describe('$anchorScroll', function() {
};
}
function addElements() {
var elements = sliceArgs(arguments);
@@ -49,9 +48,9 @@ describe('$anchorScroll', function() {
};
}
function callAnchorScroll() {
function callAnchorScroll(hash) {
return function($anchorScroll) {
$anchorScroll();
$anchorScroll(hash);
};
}
@@ -141,50 +140,120 @@ describe('$anchorScroll', function() {
beforeEach(createMockWindow());
it('should scroll to top of the window if empty hash', inject(
changeHashAndScroll(''),
expectScrollingToTop));
describe('and implicitly using `$location.hash()`', function() {
it('should scroll to top of the window if empty hash', inject(
changeHashAndScroll(''),
expectScrollingToTop));
it('should not scroll if hash does not match any element', inject(
addElements('id=one', 'id=two'),
changeHashAndScroll('non-existing'),
expectNoScrolling()));
it('should scroll to anchor element with name', inject(
addElements('a name=abc'),
changeHashAndScroll('abc'),
expectScrollingTo('a name=abc')));
it('should not scroll to other than anchor element with name', inject(
addElements('input name=xxl', 'select name=xxl', 'form name=xxl'),
changeHashAndScroll('xxl'),
expectNoScrolling()));
it('should scroll to anchor even if other element with given name exist', inject(
addElements('input name=some', 'a name=some'),
changeHashAndScroll('some'),
expectScrollingTo('a name=some')));
it('should scroll to element with id with precedence over name', inject(
addElements('name=abc', 'id=abc'),
changeHashAndScroll('abc'),
expectScrollingTo('id=abc')));
it('should not scroll if hash does not match any element', inject(
addElements('id=one', 'id=two'),
changeHashAndScroll('non-existing'),
expectNoScrolling()));
it('should scroll to top if hash == "top" and no matching element', inject(
changeHashAndScroll('top'),
expectScrollingToTop));
it('should scroll to anchor element with name', inject(
addElements('a name=abc'),
changeHashAndScroll('abc'),
expectScrollingTo('a name=abc')));
it('should scroll to element with id "top" if present', inject(
addElements('id=top'),
changeHashAndScroll('top'),
expectScrollingTo('id=top')));
});
describe('and specifying a hash', function() {
it('should ignore the `hash` argument if not a string', inject(
spyOnJQLiteDocumentLoaded(),
addElements('id=one', 'id=two'),
changeHashTo('one'), // won't scroll since `jqLiteDocumentLoaded()` is spied upon
callAnchorScroll({}),
expectScrollingTo('id=one'),
unspyOnJQLiteDocumentLoaded()));
it('should ignore `$location.hash()` if `hash` is passed as argument', inject(
spyOnJQLiteDocumentLoaded(),
addElements('id=one', 'id=two'),
changeHashTo('one'), // won't scroll since `jqLiteDocumentLoaded()` is spied upon
callAnchorScroll('two'),
expectScrollingTo('id=two'),
unspyOnJQLiteDocumentLoaded()));
it('should scroll to top of the window if empty hash', inject(
callAnchorScroll(''),
expectScrollingToTop));
it('should not scroll to other than anchor element with name', inject(
addElements('input name=xxl', 'select name=xxl', 'form name=xxl'),
changeHashAndScroll('xxl'),
expectNoScrolling()));
it('should not scroll if hash does not match any element', inject(
addElements('id=one', 'id=two'),
callAnchorScroll('non-existing'),
expectNoScrolling()));
it('should scroll to anchor even if other element with given name exist', inject(
addElements('input name=some', 'a name=some'),
changeHashAndScroll('some'),
expectScrollingTo('a name=some')));
it('should scroll to anchor element with name', inject(
addElements('a name=abc'),
callAnchorScroll('abc'),
expectScrollingTo('a name=abc')));
it('should scroll to element with id with precedence over name', inject(
addElements('name=abc', 'id=abc'),
changeHashAndScroll('abc'),
expectScrollingTo('id=abc')));
it('should not scroll to other than anchor element with name', inject(
addElements('input name=xxl', 'select name=xxl', 'form name=xxl'),
callAnchorScroll('xxl'),
expectNoScrolling()));
it('should scroll to top if hash == "top" and no matching element', inject(
changeHashAndScroll('top'),
expectScrollingToTop));
it('should scroll to anchor even if other element with given name exist', inject(
addElements('input name=some', 'a name=some'),
callAnchorScroll('some'),
expectScrollingTo('a name=some')));
it('should scroll to element with id "top" if present', inject(
addElements('id=top'),
changeHashAndScroll('top'),
expectScrollingTo('id=top')));
it('should scroll to element with id with precedence over name', inject(
addElements('name=abc', 'id=abc'),
callAnchorScroll('abc'),
expectScrollingTo('id=abc')));
it('should scroll to top if hash == "top" and no matching element', inject(
callAnchorScroll('top'),
expectScrollingToTop));
it('should scroll to element with id "top" if present', inject(
addElements('id=top'),
callAnchorScroll('top'),
expectScrollingTo('id=top')));
});
});

0 comments on commit 731c8b5

Please sign in to comment.