Skip to content

Commit

Permalink
[added] <Route ignoreScrollBehavior /> to opt out of scroll behavior …
Browse files Browse the repository at this point in the history
…for itself and descendants
  • Loading branch information
gaearon committed Oct 13, 2014
1 parent b9416bc commit 6192285
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 5 deletions.
3 changes: 2 additions & 1 deletion modules/components/Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ var Route = React.createClass({
handler: React.PropTypes.any.isRequired,
getAsyncProps: React.PropTypes.func,
path: React.PropTypes.string,
name: React.PropTypes.string
name: React.PropTypes.string,
ignoreScrollBehavior: React.PropTypes.bool
},

render: function () {
Expand Down
21 changes: 17 additions & 4 deletions modules/components/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,16 @@ function updateMatchComponents(matches, refs) {
}
}

function shouldUpdateScroll(currentMatches, previousMatches) {
var commonMatches = currentMatches.filter(function (match) {
return previousMatches.indexOf(match) !== -1;
});

return !commonMatches.some(function (match) {
return match.route.props.ignoreScrollBehavior;
});
}

function returnNull() {
return null;
}
Expand Down Expand Up @@ -285,16 +295,19 @@ var Routes = React.createClass({
} else if (abortReason) {
this.goBack();
} else {
this._handleStateChange = this.handleStateChange.bind(this, path, actionType);
this._handleStateChange = this.handleStateChange.bind(this, path, actionType, this.state.matches);
this.setState(nextState);
}
});
},

handleStateChange: function (path, actionType) {
updateMatchComponents(this.state.matches, this.refs);
handleStateChange: function (path, actionType, previousMatches) {
var currentMatches = this.state.matches;
updateMatchComponents(currentMatches, this.refs);

this.updateScroll(path, actionType);
if (shouldUpdateScroll(currentMatches, previousMatches)) {
this.updateScroll(path, actionType);
}

if (this.props.onChange)
this.props.onChange.call(this);
Expand Down
89 changes: 89 additions & 0 deletions modules/components/__tests__/Routes-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,93 @@ describe('A Routes', function () {
});
});

describe('that considers ignoreScrollBehavior when calling updateScroll', function () {
var component;
beforeEach(function () {
component = ReactTestUtils.renderIntoDocument(
Routes({ location: 'none' },
Route({ handler: NullHandler, ignoreScrollBehavior: true },
Route({ path: '/feed', handler: NullHandler }),
Route({ path: '/discover', handler: NullHandler })
),
Route({ path: '/search', handler: NullHandler, ignoreScrollBehavior: true }),
Route({ path: '/about', handler: NullHandler })
)
);
});

function spyOnUpdateScroll(action) {
var didCall = false;

var realUpdateScroll = component.updateScroll;
component.updateScroll = function mockUpdateScroll() {
didCall = true;
realUpdateScroll.apply(component, arguments);
};

try {
action();
} finally {
component.updateScroll = realUpdateScroll;
}

return didCall;
}

afterEach(function () {
React.unmountComponentAtNode(component.getDOMNode());
});

it('calls updateScroll when no ancestors ignore scroll', function () {
component.updateLocation('/feed');

var calledUpdateScroll = spyOnUpdateScroll(function () {
component.updateLocation('/about');
});

expect(calledUpdateScroll).toEqual(true);
});

it('calls updateScroll when no ancestors ignore scroll even though source and target do', function () {
component.updateLocation('/feed');

var calledUpdateScroll = spyOnUpdateScroll(function () {
component.updateLocation('/search');
});

expect(calledUpdateScroll).toEqual(true);
});

it('calls updateScroll when source is same as target and does not ignore scroll', function () {
component.updateLocation('/about');

var calledUpdateScroll = spyOnUpdateScroll(function () {
component.updateLocation('/about?page=2');
});

expect(calledUpdateScroll).toEqual(true);
});

it('does not call updateScroll when common ancestor ignores scroll', function () {
component.updateLocation('/feed');

var calledUpdateScroll = spyOnUpdateScroll(function () {
component.updateLocation('/discover');
});

expect(calledUpdateScroll).toEqual(false);
});

it('does not call updateScroll when source is same as target and ignores scroll', function () {
component.updateLocation('/search');

var calledUpdateScroll = spyOnUpdateScroll(function () {
component.updateLocation('/search?q=test');
});

expect(calledUpdateScroll).toEqual(false);
});

});

});

0 comments on commit 6192285

Please sign in to comment.