react-slick
Version:
React port of slick carousel
401 lines (345 loc) • 13.1 kB
JavaScript
'use strict';
exports.__esModule = true;
var _trackHelper = require('./trackHelper');
var _helpers = require('./helpers');
var _helpers2 = _interopRequireDefault(_helpers);
var _objectAssign = require('object-assign');
var _objectAssign2 = _interopRequireDefault(_objectAssign);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
var _trackUtils = require('../utils/trackUtils');
var _innerSliderUtils = require('../utils/innerSliderUtils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var EventHandlers = {
// Event handler for previous and next
// gets called if slide is changed via arrows or dots but not swiping/dragging
changeSlide: function changeSlide(options) {
var indexOffset, previousInt, slideOffset, unevenOffset, targetSlide;
var _props = this.props,
slidesToScroll = _props.slidesToScroll,
slidesToShow = _props.slidesToShow,
centerMode = _props.centerMode,
rtl = _props.rtl;
var _state = this.state,
slideCount = _state.slideCount,
currentSlide = _state.currentSlide;
unevenOffset = slideCount % slidesToScroll !== 0;
indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll;
if (options.message === 'previous') {
slideOffset = indexOffset === 0 ? slidesToScroll : slidesToShow - indexOffset;
targetSlide = currentSlide - slideOffset;
if (this.props.lazyLoad && !this.props.infinite) {
previousInt = currentSlide - slideOffset;
targetSlide = previousInt === -1 ? slideCount - 1 : previousInt;
}
} else if (options.message === 'next') {
slideOffset = indexOffset === 0 ? slidesToScroll : indexOffset;
targetSlide = currentSlide + slideOffset;
if (this.props.lazyLoad && !this.props.infinite) {
targetSlide = (currentSlide + slidesToScroll) % slideCount + indexOffset;
}
} else if (options.message === 'dots') {
// Click on dots
targetSlide = options.index * options.slidesToScroll;
if (targetSlide === options.currentSlide) {
return;
}
} else if (options.message === 'children') {
// Click on the slides
targetSlide = options.index;
if (targetSlide === options.currentSlide) {
return;
}
if (this.props.infinite) {
var direction = (0, _trackUtils.siblingDirection)({ currentSlide: currentSlide, targetSlide: targetSlide, slidesToShow: slidesToShow, centerMode: centerMode, slideCount: slideCount, rtl: rtl });
if (targetSlide > options.currentSlide && direction === 'left') {
targetSlide = targetSlide - slideCount;
} else if (targetSlide < options.currentSlide && direction === 'right') {
targetSlide = targetSlide + slideCount;
}
}
} else if (options.message === 'index') {
targetSlide = Number(options.index);
if (targetSlide === options.currentSlide) {
return;
}
}
this.slideHandler(targetSlide);
},
// Accessiblity handler for previous and next
keyHandler: function keyHandler(e) {
//Dont slide if the cursor is inside the form fields and arrow keys are pressed
if (!e.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
if (e.keyCode === 37 && this.props.accessibility === true) {
this.changeSlide({
message: this.props.rtl === true ? 'next' : 'previous'
});
} else if (e.keyCode === 39 && this.props.accessibility === true) {
this.changeSlide({
message: this.props.rtl === true ? 'previous' : 'next'
});
}
}
},
// Focus on selecting a slide (click handler on track)
selectHandler: function selectHandler(options) {
this.changeSlide(options);
},
// invoked when swiping/dragging starts (just once)
swipeStart: function swipeStart(e) {
if (e.target.tagName === 'IMG') {
e.preventDefault();
}
var touches, posX, posY;
// the condition after or looked redundant
if (this.props.swipe === false) {
// || ('ontouchend' in document && this.props.swipe === false)) {
return;
} else if (this.props.draggable === false && e.type.indexOf('mouse') !== -1) {
return;
}
posX = e.touches !== undefined ? e.touches[0].pageX : e.clientX;
posY = e.touches !== undefined ? e.touches[0].pageY : e.clientY;
this.setState({
dragging: true,
touchObject: {
startX: posX,
startY: posY,
curX: posX,
curY: posY
}
});
},
// continuous invokation while swiping/dragging is going on
swipeMove: function swipeMove(e) {
if (!this.state.dragging) {
e.preventDefault();
return;
}
if (this.state.scrolling) {
return;
}
if (this.state.animating) {
e.preventDefault();
return;
}
if (this.props.vertical && this.props.swipeToSlide && this.props.verticalSwiping) {
e.preventDefault();
}
var swipeLeft;
var curLeft, positionOffset;
var touchObject = this.state.touchObject;
curLeft = (0, _trackHelper.getTrackLeft)((0, _objectAssign2.default)({
slideIndex: this.state.currentSlide,
trackRef: this.track
}, this.props, this.state));
touchObject.curX = e.touches ? e.touches[0].pageX : e.clientX;
touchObject.curY = e.touches ? e.touches[0].pageY : e.clientY;
touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curX - touchObject.startX, 2)));
var verticalSwipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curY - touchObject.startY, 2)));
if (!this.props.verticalSwiping && !this.state.swiping && verticalSwipeLength > 10) {
this.setState({
scrolling: true
});
return;
}
if (this.props.verticalSwiping) {
touchObject.swipeLength = verticalSwipeLength;
}
positionOffset = (this.props.rtl === false ? 1 : -1) * (touchObject.curX > touchObject.startX ? 1 : -1);
if (this.props.verticalSwiping) {
positionOffset = touchObject.curY > touchObject.startY ? 1 : -1;
}
var currentSlide = this.state.currentSlide;
var dotCount = Math.ceil(this.state.slideCount / this.props.slidesToScroll); // this might not be correct, using getDotCount may be more accurate
var swipeDirection = (0, _innerSliderUtils.getSwipeDirection)(this.state.touchObject, this.props.verticalSwiping);
var touchSwipeLength = touchObject.swipeLength;
if (this.props.infinite === false) {
if (currentSlide === 0 && swipeDirection === 'right' || currentSlide + 1 >= dotCount && swipeDirection === 'left') {
touchSwipeLength = touchObject.swipeLength * this.props.edgeFriction;
if (this.state.edgeDragged === false && this.props.edgeEvent) {
this.props.edgeEvent(swipeDirection);
this.setState({ edgeDragged: true });
}
}
}
if (this.state.swiped === false && this.props.swipeEvent) {
this.props.swipeEvent(swipeDirection);
this.setState({ swiped: true });
}
if (!this.props.vertical) {
if (!this.props.rtl) {
swipeLeft = curLeft + touchSwipeLength * positionOffset;
} else {
swipeLeft = curLeft - touchSwipeLength * positionOffset;
}
} else {
swipeLeft = curLeft + touchSwipeLength * (this.state.listHeight / this.state.listWidth) * positionOffset;
}
if (this.props.verticalSwiping) {
swipeLeft = curLeft + touchSwipeLength * positionOffset;
}
this.setState({
touchObject: touchObject,
swipeLeft: swipeLeft,
trackStyle: (0, _trackHelper.getTrackCSS)((0, _objectAssign2.default)({ left: swipeLeft }, this.props, this.state))
});
if (Math.abs(touchObject.curX - touchObject.startX) < Math.abs(touchObject.curY - touchObject.startY) * 0.8) {
return;
}
if (touchObject.swipeLength > 10) {
this.setState({
swiping: true
});
e.preventDefault();
}
},
getNavigableIndexes: function getNavigableIndexes() {
var max = void 0;
var breakPoint = 0;
var counter = 0;
var indexes = [];
if (!this.props.infinite) {
max = this.state.slideCount;
} else {
breakPoint = this.props.slidesToShow * -1;
counter = this.props.slidesToShow * -1;
max = this.state.slideCount * 2;
}
while (breakPoint < max) {
indexes.push(breakPoint);
breakPoint = counter + this.props.slidesToScroll;
counter += this.props.slidesToScroll <= this.props.slidesToShow ? this.props.slidesToScroll : this.props.slidesToShow;
}
return indexes;
},
checkNavigable: function checkNavigable(index) {
var navigables = this.getNavigableIndexes();
var prevNavigable = 0;
if (index > navigables[navigables.length - 1]) {
index = navigables[navigables.length - 1];
} else {
for (var n in navigables) {
if (index < navigables[n]) {
index = prevNavigable;
break;
}
prevNavigable = navigables[n];
}
}
return index;
},
getSlideCount: function getSlideCount() {
var _this = this;
var centerOffset = this.props.centerMode ? this.state.slideWidth * Math.floor(this.props.slidesToShow / 2) : 0;
if (this.props.swipeToSlide) {
var swipedSlide = void 0;
var slickList = _reactDom2.default.findDOMNode(this.list);
var slides = slickList.querySelectorAll('.slick-slide');
Array.from(slides).every(function (slide) {
if (!_this.props.vertical) {
if (slide.offsetLeft - centerOffset + (0, _innerSliderUtils.getWidth)(slide) / 2 > _this.state.swipeLeft * -1) {
swipedSlide = slide;
return false;
}
} else {
if (slide.offsetTop + (0, _innerSliderUtils.getHeight)(slide) / 2 > _this.state.swipeLeft * -1) {
swipedSlide = slide;
return false;
}
}
return true;
});
if (!swipedSlide) {
return 0;
}
var currentIndex = this.props.rtl === true ? this.state.slideCount - this.state.currentSlide : this.state.currentSlide;
var slidesTraversed = Math.abs(swipedSlide.dataset.index - currentIndex) || 1;
return slidesTraversed;
} else {
return this.props.slidesToScroll;
}
},
swipeEnd: function swipeEnd(e) {
if (!this.state.dragging) {
if (this.props.swipe) {
e.preventDefault();
}
return;
}
var touchObject = this.state.touchObject;
var minSwipe = this.state.listWidth / this.props.touchThreshold;
var swipeDirection = (0, _innerSliderUtils.getSwipeDirection)(touchObject, this.props.verticalSwiping);
if (this.props.verticalSwiping) {
minSwipe = this.state.listHeight / this.props.touchThreshold;
}
var wasScrolling = this.state.scrolling;
// reset the state of touch related state variables.
this.setState({
dragging: false,
edgeDragged: false,
scrolling: false,
swiping: false,
swiped: false,
swipeLeft: null,
touchObject: {}
});
if (wasScrolling) {
return;
}
// Fix for #13
if (!touchObject.swipeLength) {
return;
}
if (touchObject.swipeLength > minSwipe) {
e.preventDefault();
if (this.props.onSwipe) {
this.props.onSwipe(swipeDirection);
}
var slideCount = void 0,
newSlide = void 0;
switch (swipeDirection) {
case 'left':
case 'up':
newSlide = this.state.currentSlide + this.getSlideCount();
slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
this.setState({ currentDirection: 0 });
break;
case 'right':
case 'down':
newSlide = this.state.currentSlide - this.getSlideCount();
slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
this.setState({ currentDirection: 1 });
break;
default:
slideCount = this.state.currentSlide;
}
this.slideHandler(slideCount);
} else {
// Adjust the track back to it's original position.
var currentLeft = (0, _trackHelper.getTrackLeft)((0, _objectAssign2.default)({
slideIndex: this.state.currentSlide,
trackRef: this.track
}, this.props, this.state));
this.setState({
trackStyle: (0, _trackHelper.getTrackAnimateCSS)((0, _objectAssign2.default)({ left: currentLeft }, this.props, this.state))
});
}
},
onInnerSliderEnter: function onInnerSliderEnter(e) {
if (this.props.autoplay && this.props.pauseOnHover) {
this.pause();
}
},
onInnerSliderOver: function onInnerSliderOver(e) {
if (this.props.autoplay && this.props.pauseOnHover) {
this.pause();
}
},
onInnerSliderLeave: function onInnerSliderLeave(e) {
if (this.props.autoplay && this.props.pauseOnHover) {
this.autoPlay();
}
}
};
exports.default = EventHandlers;