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

Commit

Permalink
feat($anchorScroll): allow scrolling to a specified element
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gkalpak committed Apr 2, 2015
1 parent 06a9f0a commit 55f44b7
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 38 deletions.
15 changes: 10 additions & 5 deletions src/ng/anchorScroll.js
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand Down
135 changes: 102 additions & 33 deletions test/ng/anchorScrollSpec.js
Expand Up @@ -23,7 +23,6 @@ describe('$anchorScroll', function() {
};
}


function addElements() {
var elements = sliceArgs(arguments);

Expand All @@ -49,9 +48,9 @@ describe('$anchorScroll', function() {
};
}

function callAnchorScroll() {
function callAnchorScroll(hash) {
return function($anchorScroll) {
$anchorScroll();
$anchorScroll(hash);
};
}

Expand Down Expand Up @@ -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')));
});
});


Expand Down

0 comments on commit 55f44b7

Please sign in to comment.