Skip to content

Commit

Permalink
Merge pull request #38 from nickclaw/master
Browse files Browse the repository at this point in the history
Add direction specific functions
  • Loading branch information
trotzig committed Oct 31, 2015
2 parents 7bd8384 + a193c08 commit e877b63
Showing 5 changed files with 66 additions and 39 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## master (unreleased)

## 1.1.0

- Add second parameter to `onEnter` and `onLeave` callbacks to indicate
from which direction the waypoint entered _from_ and _to_ respectively.

## 1.0.6

- Prevent duplicate onError/onLeave callbacks
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -58,10 +58,30 @@ var Waypoint = require('react-waypoint');

```javascript
propTypes: {
onEnter: PropTypes.func, // function called when waypoint enters viewport
onLeave: PropTypes.func, // function called when waypoint leaves viewport
threshold: PropTypes.number, // threshold is percentage of the height of
// the visible part of the scrollable parent (e.g. 0.1)

/**
* Function called when waypoint enters viewport
* Both parameters will be null if the waypoint is in the
* viewport on initial mount.
*
* @param {Event|null} event
* @param {'above'|'below'|null} from
*/
onEnter: PropTypes.func,

/**
* Function called when waypoint leaves viewport
*
* @param {Event|null} event
* @param {'above'|'below'} to
*/
onLeave: PropTypes.func,

/**
* Threshold - a percentage of the height of the visible
* part of the scrollable parent (e.g. 0.1)
*/
threshold: PropTypes.number
},
```

32 changes: 17 additions & 15 deletions build/npm/waypoint.js
Original file line number Diff line number Diff line change
@@ -18,11 +18,11 @@ var Waypoint = React.createClass({
displayName: 'Waypoint',

propTypes: {
onEnter: PropTypes.func,
onLeave: PropTypes.func,
// threshold is percentage of the height of the visible part of the
// scrollable ancestor (e.g. 0.1)
threshold: PropTypes.number
threshold: PropTypes.number,
onEnter: PropTypes.func,
onLeave: PropTypes.func
},

/**
@@ -40,12 +40,12 @@ var Waypoint = React.createClass({
this.scrollableAncestor = this._findScrollableAncestor();
this.scrollableAncestor.addEventListener('scroll', this._handleScroll);
window.addEventListener('resize', this._handleScroll);
this._handleScroll();
this._handleScroll(null);
},

componentDidUpdate: function componentDidUpdate() {
// The element may have moved.
this._handleScroll();
this._handleScroll(null);
},

componentWillUnmount: function componentWillUnmount() {
@@ -103,28 +103,30 @@ var Waypoint = React.createClass({
*/
_handleScroll: function _handleScroll(event) {
var currentPosition = this._currentPosition();
var previousPosition = this._previousPosition || null;

// Save previous position as early as possible to prevent cycles
this._previousPosition = currentPosition;

if (this._previousPosition === currentPosition) {
if (previousPosition === currentPosition) {
// No change since last trigger
return;
}

if (currentPosition === POSITIONS.inside) {
this.props.onEnter.call(this, event);
} else if (this._previousPosition === POSITIONS.inside) {
this.props.onLeave.call(this, event);
this.props.onEnter.call(this, event, previousPosition);
} else if (previousPosition === POSITIONS.inside) {
this.props.onLeave.call(this, event, currentPosition);
}

var isRapidScrollDown = this._previousPosition === POSITIONS.below && currentPosition === POSITIONS.above;
var isRapidScrollUp = this._previousPosition === POSITIONS.above && currentPosition === POSITIONS.below;
var isRapidScrollDown = previousPosition === POSITIONS.below && currentPosition === POSITIONS.above;
var isRapidScrollUp = previousPosition === POSITIONS.above && currentPosition === POSITIONS.below;
if (isRapidScrollDown || isRapidScrollUp) {
// If the scroll event isn't fired often enough to occur while the
// waypoint was visible, we trigger both callbacks anyway.
this.props.onEnter.call(this, event);
this.props.onLeave.call(this, event);
this.props.onEnter.call(this, event, previousPosition);
this.props.onLeave.call(this, event, currentPosition);
}

this._previousPosition = currentPosition;
},

/**
22 changes: 11 additions & 11 deletions spec/waypoint_spec.js
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ describe('<Waypoint>', function() {
});

it('calls the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(null, null);
});

it('does not call the onLeave handler', () => {
@@ -94,7 +94,7 @@ describe('<Waypoint>', function() {
});

it('the onLeave handler is called', () => {
expect(this.props.onLeave).toHaveBeenCalled();
expect(this.props.onLeave).toHaveBeenCalledWith(jasmine.any(Event), 'above');
});

it('does not call the onEnter handler', () => {
@@ -143,7 +143,7 @@ describe('<Waypoint>', function() {
});

it('calls the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(jasmine.any(Event), 'below');
});

it('does not call the onLeave handler', () => {
@@ -161,11 +161,11 @@ describe('<Waypoint>', function() {
});

it('calls the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(jasmine.any(Event), 'below');
});

it('calls the onLeave handler', () => {
expect(this.props.onLeave).toHaveBeenCalled();
expect(this.props.onLeave).toHaveBeenCalledWith(jasmine.any(Event), 'above');
});
});

@@ -194,7 +194,7 @@ describe('<Waypoint>', function() {
});

it('calls the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(jasmine.any(Event), 'below');
});

it('does not call the onLeave handler', () => {
@@ -247,7 +247,7 @@ describe('<Waypoint>', function() {
});

it('calls the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(jasmine.any(Event), 'above');
});

it('does not call the onLeave handler', () => {
@@ -260,7 +260,7 @@ describe('<Waypoint>', function() {
});

it('calls the onLeave handler', () => {
expect(this.props.onLeave).toHaveBeenCalled();
expect(this.props.onLeave).toHaveBeenCalledWith(jasmine.any(Event), 'below');
});

it('does not call the onEnter handler again', () => {
@@ -279,11 +279,11 @@ describe('<Waypoint>', function() {
});

it('calls the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(jasmine.any(Event), 'above');
});

it('calls the onLeave handler', () => {
expect(this.props.onLeave).toHaveBeenCalled();
expect(this.props.onLeave).toHaveBeenCalledWith(jasmine.any(Event), 'below');
});
});
});
@@ -320,7 +320,7 @@ describe('<Waypoint>', function() {
});

it('fires the onEnter handler', () => {
expect(this.props.onEnter).toHaveBeenCalled();
expect(this.props.onEnter).toHaveBeenCalledWith(jasmine.any(Event), 'below');
});
});
});
18 changes: 9 additions & 9 deletions src/waypoint.jsx
Original file line number Diff line number Diff line change
@@ -14,11 +14,11 @@ const POSITIONS = {
*/
const Waypoint = React.createClass({
propTypes: {
onEnter: PropTypes.func,
onLeave: PropTypes.func,
// threshold is percentage of the height of the visible part of the
// scrollable ancestor (e.g. 0.1)
threshold: PropTypes.number,
onEnter: PropTypes.func,
onLeave: PropTypes.func
},

/**
@@ -36,12 +36,12 @@ const Waypoint = React.createClass({
this.scrollableAncestor = this._findScrollableAncestor();
this.scrollableAncestor.addEventListener('scroll', this._handleScroll);
window.addEventListener('resize', this._handleScroll);
this._handleScroll();
this._handleScroll(null);
},

componentDidUpdate() {
// The element may have moved.
this._handleScroll();
this._handleScroll(null);
},

componentWillUnmount() {
@@ -100,7 +100,7 @@ const Waypoint = React.createClass({
*/
_handleScroll(event) {
const currentPosition = this._currentPosition();
const previousPosition = this._previousPosition;
const previousPosition = this._previousPosition || null;

// Save previous position as early as possible to prevent cycles
this._previousPosition = currentPosition;
@@ -111,9 +111,9 @@ const Waypoint = React.createClass({
}

if (currentPosition === POSITIONS.inside) {
this.props.onEnter.call(this, event);
this.props.onEnter.call(this, event, previousPosition);
} else if (previousPosition === POSITIONS.inside) {
this.props.onLeave.call(this, event);
this.props.onLeave.call(this, event, currentPosition);
}

const isRapidScrollDown = previousPosition === POSITIONS.below &&
@@ -123,8 +123,8 @@ const Waypoint = React.createClass({
if (isRapidScrollDown || isRapidScrollUp) {
// If the scroll event isn't fired often enough to occur while the
// waypoint was visible, we trigger both callbacks anyway.
this.props.onEnter.call(this, event);
this.props.onLeave.call(this, event);
this.props.onEnter.call(this, event, previousPosition);
this.props.onLeave.call(this, event, currentPosition);
}
},

0 comments on commit e877b63

Please sign in to comment.