Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
});

});

});