wpfw_ewei_shopv2/plugin/exchange/static/js/swipe.js
2023-02-14 19:57:32 +08:00

525 lines
17 KiB
JavaScript

/*
* Swipe 2.0
*
* Brad Birdsall
* Copyright 2012, Licensed GPL & MIT
*
*/
window.Swipe = function(element, options) {
var _this = this;
// return immediately if element doesn't exist
if (!element) return;
// reference dom elements
this.container = element;
this.element = this.container.children[0];
// simple feature detection
this.browser = {
touch: (function() {
return ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch;
})(),
transitions: (function() {
var temp = document.createElement('swipe'),
props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
for ( var i in props ) {
if (temp.style[ props[i] ] !== undefined) return true;
}
return false;
})()
};
// retreive options
options = options || {};
this.index = options.startSlide || 0;
this.speed = options.speed || 200;
this.callback = options.callback || function() {};
this.transitionEnd = options.transitionEnd || function() {};
this.delay = options.auto || 0;
this.cont = (options.continuous != undefined) ? !!options.continuous : true;
this.disableScroll = !!options.disableScroll;
// verify index is a number not string
this.index = parseInt(this.index,10);
// trigger slider initialization
this.setup();
// begin auto slideshow
this.begin();
// add event listeners
if (this.element.addEventListener) {
if (!!this.browser.touch) {
this.element.addEventListener('touchstart', this, false);
this.element.addEventListener('touchmove', this, false);
this.element.addEventListener('touchend', this, false);
}
if (!!this.browser.transitions) {
this.element.addEventListener('webkitTransitionEnd', this, false);
this.element.addEventListener('msTransitionEnd', this, false);
this.element.addEventListener('oTransitionEnd', this, false);
this.element.addEventListener('transitionend', this, false);
}
window.addEventListener('resize', this, false);
}
// to play nice with old IE
else {
window.onresize = function () {
_this.setup();
};
}
};
Swipe.prototype = {
createElem:function(){
this.length = this.slides.length;
if (this.length < 2) return;
var last=$(this.slides[this.length-1]).clone();
var first=$(this.slides[0]).clone();
$(this.element).append(first);
$(this.element).prepend(last);
this.length = this.slides.length;
$(this.slides[0]).attr('id','')
$(this.slides[this.length-1]).attr('id','')
},
setup: function() {
// get and measure amt of slides
this.slides = this.element.children;
this.length = this.slides.length;
this.cache = new Array(this.length);
// return immediately if their are less than two slides
// determine width of each slide
this.width = this.container.getBoundingClientRect().width || this.container.offsetWidth;
// return immediately if measurement fails
if (!this.width) return;
// store array of slides before, current, and after
var refArray = [[],[],[]];
this.element.style.width = (this.slides.length * this.width) + 'px';
// stack elements
for (var index = this.length - 1; index > -1; index--) {
var elem = this.slides[index];
elem.style.width = this.width + 'px';
elem.setAttribute('data-index', index);
if (this.browser.transitions) {
elem.style.left = (index * -this.width) + 'px';
}
// add this index to the reference array 0:before 1:equal 2:after
refArray[this.index > index ? 0 : (this.index < index ? 2 : 1)].push(index);
}
//console.log(refArray)
if (this.browser.transitions) {
// stack left, current, and right slides
this._stack(refArray[0],-1);
this._stack(refArray[1],0);
this._stack(refArray[2],1);
} else {
// move "viewport" to put current slide into view
this.element.style.left = (this.index * -this.width)+"px";
}
this.container.style.visibility = 'visible';
},
kill: function() {
// cancel slideshow
this.delay = 0;
clearTimeout(this.interval);
// clear all translations
var slideArray = [];
for (var i = this.slides.length - 1; i >= 0; i--) {
this.slides[i].style.width = '';
slideArray.push(i);
}
this._stack(slideArray,0);
var elem = this.element;
elem.className = elem.className.replace('swipe-active','');
// remove event listeners
if (this.element.removeEventListener) {
if (!!this.browser.touch) {
this.element.removeEventListener('touchstart', this, false);
this.element.removeEventListener('touchmove', this, false);
this.element.removeEventListener('touchend', this, false);
}
if (!!this.browser.transitions) {
this.element.removeEventListener('webkitTransitionEnd', this, false);
this.element.removeEventListener('msTransitionEnd', this, false);
this.element.removeEventListener('oTransitionEnd', this, false);
this.element.removeEventListener('transitionend', this, false);
}
window.removeEventListener('resize', this, false);
}
// kill old IE! you can quote me on that ;)
else {
window.onresize = null;
}
},
getPos: function() {
// return current index position
return this.index;
},
prev: function(delay) {
// cancel slideshow
this.delay = delay || 0;
clearTimeout(this.interval);
// if not at first slide
if (this.index) this.slide(this.index-1, this.speed);
else if (this.cont) this.slide(this.length-1, this.speed);
},
next: function(delay) {
// cancel slideshow
this.delay = delay || 0;
clearTimeout(this.interval);
if (this.index < this.length - 1) this.slide(this.index+1, this.speed); // if not last slide
else if (this.cont) this.slide(0, this.speed); //if last slide return to start
},
showelem: function(index) {
clearTimeout(this.interval);
this.slide(index, this.speed);
},
begin: function() {
var _this = this;
this.interval = (this.delay)
? setTimeout(function() {
_this.next(_this.delay);
}, this.delay)
: 0;
},
handleEvent: function(e) {
switch (e.type) {
case 'touchstart':
this.onTouchStart(e);
break;
case 'touchmove':
this.onTouchMove(e);
break;
case 'touchend':
this.onTouchEnd(e);
break;
case 'webkitTransitionEnd':
case 'msTransitionEnd':
case 'oTransitionEnd': // opera 11 and below
case 'otransitionend': // opera 12 (and above?)
case 'transitionend':
this.onTransitionEnd(e);
break;
case 'resize':
this.setup();
break;
}
e.stopPropagation();
},
onTouchStart: function(e) {
var _this = this;
_this.start = {
// get touch coordinates for delta calculations in onTouchMove
pageX: e.touches[0].pageX,
pageY: e.touches[0].pageY,
// set initial timestamp of touch sequence
time: Number( new Date() )
};
// used for testing first onTouchMove event
_this.isScrolling = undefined;
// reset deltaX
_this.deltaX = 0;
},
onTouchMove: function(e) {
var _this = this;
// ensure swiping with one touch and not pinching
if(e.touches.length > 1 || e.scale && e.scale !== 1) return;
_this.deltaX = e.touches[0].pageX - _this.start.pageX;
// determine if scrolling test has run - one time test
if ( typeof _this.isScrolling == 'undefined') {
_this.isScrolling = !!( _this.isScrolling || Math.abs(_this.deltaX) < Math.abs(e.touches[0].pageY - _this.start.pageY) );
}
// if user is not trying to scroll vertically
if (!_this.isScrolling) {
// prevent native scrolling
e.preventDefault();
// cancel slideshow
_this.delay = 0;
clearTimeout(_this.interval);
// increase resistance if first or last slide
_this.deltaX =
_this.deltaX /
( (!_this.index && _this.deltaX > 0 // if first slide and sliding left
|| _this.index == _this.length - 1 // or if last slide and sliding right
&& _this.deltaX < 0 // and if sliding at all
) ?
( Math.abs(_this.deltaX) / _this.width + 1 ) // determine resistance level
: 1 ); // no resistance if false
// translate immediately 1:1
_this._move([_this.index-1,_this.index,_this.index+1],_this.deltaX);
} else if (_this.disableScroll) {
// prevent native scrolling
e.preventDefault();
}
},
onTouchEnd: function(e) {
var _this = this;
// determine if slide attempt triggers next/prev slide
var isValidSlide =
Number(new Date()) - _this.start.time < 250 // if slide duration is less than 250ms
&& Math.abs(_this.deltaX) > 20 // and if slide amt is greater than 20px
|| Math.abs(_this.deltaX) > _this.width/6, // or if slide amt is greater than half the width
// determine if slide attempt is past start and end
isPastBounds =
!_this.index && _this.deltaX > 0 // if first slide and slide amt is greater than 0
|| _this.index == _this.length - 1 && _this.deltaX < 0, // or if last slide and slide amt is less than 0
direction = _this.deltaX < 0; // true:right false:left
// if not scrolling vertically
if (!_this.isScrolling) {
if (isValidSlide && !isPastBounds) {
if (direction) {
_this._stack([_this.index-1],-1);
_this._slide([_this.index,_this.index+1],-_this.width,_this.speed);
_this.index += 1;
} else {
_this._stack([_this.index+1],1);
_this._slide([_this.index-1,_this.index],_this.width,_this.speed);
_this.index += -1;
}
_this.callback(_this.index, _this.slides[_this.index]);
} else {
_this._slide([_this.index-1,_this.index,_this.index+1],0,_this.speed);
}
}
},
onTransitionEnd: function(e) {
if (this._getElemIndex(e.target) == this.index) { // only call transition end on the main slide item
if (this.delay) this.begin();
this.transitionEnd(this.index, this.slides[this.index]);
}
},
slide: function(to, speed) {
var from = this.index;
if (from == to) return; // do nothing if already on requested slide
var speed = (typeof speed === "Undefined") ? this.speed : speed;
if (this.browser.transitions) {
var toStack = Math.abs(from-to) - 1,
direction = Math.abs(from-to) / (from-to), // 1:right -1:left
inBetween = [];
while (toStack--) inBetween.push( (to > from ? to : from) - toStack - 1 );
// stack em
this._stack(inBetween,direction);
// now slide from and to in the proper direction
this._slide([from,to],this.width * direction,speed);
}
else {
this._animate(from*-this.width, to * -this.width, speed)
}
this.index = to;
this.callback(this.index, this.slides[this.index]);
},
_slide: function(nums, dist, speed) {
var _slides = this.slides,
l = nums.length;
while(l--) {
this._translate(_slides[nums[l]], dist + this.cache[nums[l]], speed ? speed : 0);
this.cache[nums[l]] += dist;
}
},
_stack: function(nums, pos) { // pos: -1:left 0:center 1:right
var _slides = this.slides,
l = nums.length,
dist = this.width * pos;
while(l--) {
this._translate(_slides[nums[l]], dist, 0);
this.cache[nums[l]] = dist;
}
},
_move: function(nums, dist) { // 1:1 scrolling
var _slides = this.slides,
l = nums.length;
while(l--) this._translate(_slides[nums[l]], dist + this.cache[nums[l]], 0);
},
_translate: function(elem, xval, speed) {
if (!elem) return;
var style = elem.style;
// set duration speed to 0
style.webkitTransitionDuration =
style.MozTransitionDuration =
style.msTransitionDuration =
style.OTransitionDuration =
style.transitionDuration = speed + 'ms';
// translate to given position
style.webkitTransform = 'translate(' + xval + 'px,0)' + 'translateZ(0)';
style.msTransform =
style.MozTransform =
style.OTransform = 'translateX(' + xval + 'px)';
},
_animate: function(from, to, speed) {
var elem = this.element;
if (!speed) { // if not an animation, just reposition
elem.style.left = to + 'px';
return;
}
var _this = this,
start = new Date(),
timer = setInterval(function() {
var timeElap = new Date() - start;
if (timeElap > speed) {
elem.style.left = to + 'px'; // callback after this line
if (_this.delay) _this.begin();
_this.transitionEnd(_this.index, _this.slides[_this.index]);
clearInterval(timer);
return;
}
elem.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';
}, 4);
},
_getElemIndex: function(elem) {
return parseInt(elem.getAttribute('data-index'),10);
}
};
if ( window.jQuery || window.Zepto ) {
(function($) {
$.fn.Swipe = function(params) {
return this.each(function() {
var _this = $(this);
_this.data('Swipe', new Swipe(_this[0], params));
});
}
})( window.jQuery || window.Zepto )
}