diff --git a/README.md b/README.md index a141ee7..4cb03c1 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ Swipe can take an optional second parameter– an object of key/value settings: - **autoRestart** Boolean *(default: `false`)*: auto restart slideshow after user's touch event or next/prev calls. - **disableScroll** Boolean *(default: `false`)*: prevent any touch events on this container from scrolling the page. - **stopPropagation** Boolean *(default: `false`)*: stop event propagation. -- **callback** Function *(default: `function() {}`)*: runs at slide change. -- **transitionEnd** Function *(default: `function() {}`)*: runs at the end of a slide transition. +- **callback** Function *(default: `function() {}`)*: runs at slide change. Three parameters are passed to the function: `index` (the current slide index), `elem` (the current slide element) and `dir` (direction: `1` for left or backward, `-1` for right or forward). +- **transitionEnd** Function *(default: `function() {}`)*: runs at the end of a slide transition. Two parameters are passed to the function: `index` (the current slide index) and `elem` (the current slide element). ### Example @@ -101,7 +101,7 @@ window.mySwipe = new Swipe(document.getElementById('slider'), { continuous: true, disableScroll: false, stopPropagation: false, - callback: function(index, elem) {}, + callback: function(index, elem, dir) {}, transitionEnd: function(index, elem) {} }); ``` diff --git a/build/swipe.min.js b/build/swipe.min.js index ce77b2e..41f7f60 100644 --- a/build/swipe.min.js +++ b/build/swipe.min.js @@ -1,8 +1,8 @@ /*! - * Swipe 2.1.5 + * Swipe 2.2.0 * * Brad Birdsall * Copyright 2013, MIT License * */ -!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Swipe=b(),a.Swipe}):"object"==typeof module&&module.exports?module.exports=b():a.Swipe=b()}(this,function(){function Swipe(c,d){"use strict";function e(){w.addEventListener?(B.removeEventListener("touchstart",H,!1),B.removeEventListener("mousedown",H,!1),B.removeEventListener("webkitTransitionEnd",H,!1),B.removeEventListener("msTransitionEnd",H,!1),B.removeEventListener("oTransitionEnd",H,!1),B.removeEventListener("otransitionend",H,!1),B.removeEventListener("transitionend",H,!1),a.removeEventListener("resize",H,!1)):a.onresize=null}function f(){w.addEventListener?(w.touch&&B.addEventListener("touchstart",H,!1),d.draggable&&B.addEventListener("mousedown",H,!1),w.transitions&&(B.addEventListener("webkitTransitionEnd",H,!1),B.addEventListener("msTransitionEnd",H,!1),B.addEventListener("oTransitionEnd",H,!1),B.addEventListener("otransitionend",H,!1),B.addEventListener("transitionend",H,!1)),a.addEventListener("resize",H,!1)):a.onresize=G}function g(){if(x=B.children,A=x.length,x.length<2&&(d.continuous=!1),w.transitions&&d.continuous&&x.length<3){var a=x[0].cloneNode(!0),b=B.children[1].cloneNode(!0);B.appendChild(a),B.appendChild(b),a.setAttribute("data-cloned",!0),b.setAttribute("data-cloned",!0),x=B.children}y=new Array(x.length),z=c.getBoundingClientRect().width||c.offsetWidth,B.style.width=x.length*z*2+"px";for(var g=x.length;g--;){var h=x[g];h.style.width=z+"px",h.setAttribute("data-index",g),w.transitions&&(h.style.left=g*-z+"px",m(g,C>g?-z:C=A&&(a-=A),a}function l(a,b){if(a="number"!=typeof a?parseInt(a,10):a,C!==a){if(w.transitions){var c=Math.abs(C-a)/(C-a);if(d.continuous){var e=c;c=-y[j(a)]/z,c!==e&&(a=-c*x.length+a)}for(var f=Math.abs(C-a)-1;f--;)m(j((a>C?a:C)-f-1),z*c,0);a=j(a),m(C,z*c,b||D),m(a,0,b||D),d.continuous&&m(j(a-c),-(z*c),0)}else a=j(a),o(C*-z,a*-z,b||D);C=a,u(function(){d.callback&&d.callback(k(),x[C])})}}function m(a,b,c){n(a,b,c),y[a]=b}function n(a,b,c){var d=x[a],e=d&&d.style;e&&(e.webkitTransitionDuration=e.MozTransitionDuration=e.msTransitionDuration=e.OTransitionDuration=e.transitionDuration=c+"ms",e.webkitTransform="translate("+b+"px,0)translateZ(0)",e.msTransform=e.MozTransform=e.OTransform="translateX("+b+"px)")}function o(a,b,c){if(!c)return void(B.style.left=b+"px");var e=+new Date,f=setInterval(function(){var g=+new Date-e;return g>c?(B.style.left=b+"px",I&&p(),d.transitionEnd&&d.transitionEnd.call(event,k(),x[C]),void clearInterval(f)):void(B.style.left=(b-a)*(Math.floor(g/c*100)/100)+a+"px")},4)}function p(){E=setTimeout(i,I)}function q(){I=0,clearTimeout(E)}function r(){q(),I=d.auto||0,p()}function s(a){return/^mouse/.test(a.type)}var t=function(){},u=function(a){setTimeout(a||t,0)},v=function(a,b){b=b||100;var c=null;return function(){var d=this,e=arguments;c&&clearTimeout(c),c=setTimeout(function(){c=null,a.apply(d,e)},b)}},w={addEventListener:!!a.addEventListener,touch:"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch,transitions:function(a){var b=["transitionProperty","WebkitTransition","MozTransition","OTransition","msTransition"];for(var c in b)if(void 0!==a.style[b[c]])return!0;return!1}(b.createElement("swipe"))};if(c){var x,y,z,A,B=c.children[0];d=d||{};var C=parseInt(d.startSlide,10)||0,D=d.speed||300;d.continuous=void 0===d.continuous||d.continuous,d.autoRestart=void 0!==d.autoRestart&&d.autoRestart;var E,F,G=v(g),H={handleEvent:function(a){switch(a.type){case"mousedown":case"touchstart":this.start(a);break;case"mousemove":case"touchmove":this.move(a);break;case"mouseup":case"mouseleave":case"touchend":this.end(a);break;case"webkitTransitionEnd":case"msTransitionEnd":case"oTransitionEnd":case"otransitionend":case"transitionend":this.transitionEnd(a);break;case"resize":G()}d.stopPropagation&&a.stopPropagation()},start:function(a){var b;s(a)?(b=a,a.preventDefault()):b=a.touches[0],J={x:b.pageX,y:b.pageY,time:+new Date},F=void 0,K={},s(a)?(B.addEventListener("mousemove",this,!1),B.addEventListener("mouseup",this,!1),B.addEventListener("mouseleave",this,!1)):(B.addEventListener("touchmove",this,!1),B.addEventListener("touchend",this,!1))},move:function(a){var b;if(s(a))b=a;else{if(a.touches.length>1||a.scale&&1!==a.scale)return;d.disableScroll&&a.preventDefault(),b=a.touches[0]}K={x:b.pageX-J.x,y:b.pageY-J.y},"undefined"==typeof F&&(F=!!(F||Math.abs(K.x)0||C===x.length-1&&K.x<0?Math.abs(K.x)/z+1:1),n(C-1,K.x+y[C-1],0),n(C,K.x+y[C],0),n(C+1,K.x+y[C+1],0)))},end:function(a){var b=+new Date-J.time,c=Number(b)<250&&Math.abs(K.x)>20||Math.abs(K.x)>z/2,e=!C&&K.x>0||C===x.length-1&&K.x<0;d.continuous&&(e=!1);var f=K.x<0;F||(c&&!e?(f?(d.continuous?(m(j(C-1),-z,0),m(j(C+2),z,0)):m(C-1,-z,0),m(C,y[C]-z,D),m(j(C+1),y[j(C+1)]-z,D),C=j(C+1)):(d.continuous?(m(j(C+1),z,0),m(j(C-2),-z,0)):m(C+1,z,0),m(C,y[C]+z,D),m(j(C-1),y[j(C-1)]+z,D),C=j(C-1)),d.callback&&d.callback(k(),x[C])):d.continuous?(m(j(C-1),-z,D),m(C,0,D),m(j(C+1),z,D)):(m(C-1,-z,D),m(C,0,D),m(C+1,z,D))),s(a)?(B.removeEventListener("mousemove",H,!1),B.removeEventListener("mouseup",H,!1),B.removeEventListener("mouseleave",H,!1)):(B.removeEventListener("touchmove",H,!1),B.removeEventListener("touchend",H,!1))},transitionEnd:function(a){var b=parseInt(a.target.getAttribute("data-index"),10);b===C&&((I||d.autoRestart)&&r(),d.transitionEnd&&d.transitionEnd.call(a,k(),x[C]))}},I=d.auto||0,J={},K={};return g(),I&&p(),{setup:function(){g()},slide:function(a,b){q(),l(a,b)},prev:function(){q(),h()},next:function(){q(),i()},restart:function(){r()},stop:function(){q()},getPos:function(){return k()},getNumSlides:function(){return A},kill:function(){q(),c.style.visibility="",B.style.width="",B.style.left="";for(var a=x.length;a--;){w.transitions&&n(a,0,0);var b=x[a];if(b.getAttribute("data-cloned")){var d=b.parentElement;d.removeChild(b)}b.style.width="",b.style.left="",b.style.webkitTransitionDuration=b.style.MozTransitionDuration=b.style.msTransitionDuration=b.style.OTransitionDuration=b.style.transitionDuration="",b.style.webkitTransform=b.style.msTransform=b.style.MozTransform=b.style.OTransform=""}e()}}}}var a="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this,b=a.document||this.document;return(a.jQuery||a.Zepto)&&!function(a){a.fn.Swipe=function(b){return this.each(function(){a(this).data("Swipe",new Swipe(a(this)[0],b))})}}(a.jQuery||a.Zepto),Swipe}); \ No newline at end of file +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.Swipe=b(),a.Swipe}):"object"==typeof module&&module.exports?module.exports=b():a.Swipe=b()}(this,function(){function Swipe(c,d){"use strict";function e(){E.addEventListener?(J.removeEventListener("touchstart",N,!1),J.removeEventListener("mousedown",N,!1),J.removeEventListener("webkitTransitionEnd",N,!1),J.removeEventListener("msTransitionEnd",N,!1),J.removeEventListener("oTransitionEnd",N,!1),J.removeEventListener("otransitionend",N,!1),J.removeEventListener("transitionend",N,!1),a.removeEventListener("resize",N,!1)):a.onresize=null}function f(){E.addEventListener?(E.touch&&J.addEventListener("touchstart",N,!1),d.draggable&&J.addEventListener("mousedown",N,!1),E.transitions&&(J.addEventListener("webkitTransitionEnd",N,!1),J.addEventListener("msTransitionEnd",N,!1),J.addEventListener("oTransitionEnd",N,!1),J.addEventListener("otransitionend",N,!1),J.addEventListener("transitionend",N,!1)),a.addEventListener("resize",N,!1)):a.onresize=M}function g(){if(F=J.children,I=F.length,F.length<2&&(d.continuous=!1),E.transitions&&d.continuous&&F.length<3){var a=F[0].cloneNode(!0),b=J.children[1].cloneNode(!0);J.appendChild(a),J.appendChild(b),a.setAttribute("data-cloned",!0),b.setAttribute("data-cloned",!0),F=J.children}G=new Array(F.length),H=c.getBoundingClientRect().width||c.offsetWidth,J.style.width=F.length*H*2+"px";for(var g=F.length;g--;){var h=F[g];h.style.width=H+"px",h.setAttribute("data-index",g),E.transitions&&(h.style.left=g*-H+"px",o(g,K>g?-H:K=I&&(a-=I),a}function n(a,b){if(a="number"!=typeof a?parseInt(a,10):a,K!==a){if(E.transitions){var c=Math.abs(K-a)/(K-a);if(d.continuous){var e=c;c=-G[l(a)]/H,c!==e&&(a=-c*F.length+a)}for(var f=Math.abs(K-a)-1;f--;)o(l((a>K?a:K)-f-1),H*c,0);a=l(a),o(K,H*c,b||L),o(a,0,b||L),d.continuous&&o(l(a-c),-(H*c),0)}else a=l(a),q(K*-H,a*-H,b||L);K=a,C(function(){j(m(),F[K],c)})}}function o(a,b,c){p(a,b,c),G[a]=b}function p(a,b,c){var d=F[a],e=d&&d.style;e&&(e.webkitTransitionDuration=e.MozTransitionDuration=e.msTransitionDuration=e.OTransitionDuration=e.transitionDuration=c+"ms",e.webkitTransform="translate("+b+"px,0)translateZ(0)",e.msTransform=e.MozTransform=e.OTransform="translateX("+b+"px)")}function q(a,b,c){if(!c)return void(J.style.left=b+"px");var e=+new Date,f=setInterval(function(){var g=+new Date-e;return g>c?(J.style.left=b+"px",A&&r(),d.transitionEnd&&d.transitionEnd.call(event,m(),F[K]),void clearInterval(f)):void(J.style.left=(b-a)*(Math.floor(g/c*100)/100)+a+"px")},4)}function r(){x=setTimeout(i,A)}function s(){A=0,clearTimeout(x)}function t(){s(),A=d.auto||0,r()}function u(a){return/^mouse/.test(a.type)}function v(){s(),c.style.visibility="",J.style.width="",J.style.left="";for(var a=F.length;a--;){E.transitions&&p(a,0,0);var b=F[a];if(b.getAttribute("data-cloned")){var d=b.parentElement;d.removeChild(b)}b.style.width="",b.style.left="",b.style.webkitTransitionDuration=b.style.MozTransitionDuration=b.style.msTransitionDuration=b.style.OTransitionDuration=b.style.transitionDuration="",b.style.webkitTransform=b.style.msTransform=b.style.MozTransform=b.style.OTransform=""}e()}var w,x,y={},z={},A=d.auto||0,B=function(){},C=function(a){setTimeout(a||B,0)},D=function(a,b){b=b||100;var c=null;return function(){var d=this,e=arguments;c&&clearTimeout(c),c=setTimeout(function(){c=null,a.apply(d,e)},b)}},E={addEventListener:!!a.addEventListener,touch:"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch,transitions:function(a){var b=["transitionProperty","WebkitTransition","MozTransition","OTransition","msTransition"];for(var c in b)if(void 0!==a.style[b[c]])return!0;return!1}(b.createElement("swipe"))};if(c){var F,G,H,I,J=c.children[0];d=d||{};var K=parseInt(d.startSlide,10)||0,L=d.speed||300;d.continuous=void 0===d.continuous||d.continuous,d.autoRestart=void 0!==d.autoRestart&&d.autoRestart;var M=D(g),N={handleEvent:function(a){switch(a.type){case"mousedown":case"touchstart":this.start(a);break;case"mousemove":case"touchmove":this.move(a);break;case"mouseup":case"mouseleave":case"touchend":this.end(a);break;case"webkitTransitionEnd":case"msTransitionEnd":case"oTransitionEnd":case"otransitionend":case"transitionend":this.transitionEnd(a);break;case"resize":M()}d.stopPropagation&&a.stopPropagation()},start:function(a){var b;u(a)?(b=a,a.preventDefault()):b=a.touches[0],y={x:b.pageX,y:b.pageY,time:+new Date},w=void 0,z={},u(a)?(J.addEventListener("mousemove",this,!1),J.addEventListener("mouseup",this,!1),J.addEventListener("mouseleave",this,!1)):(J.addEventListener("touchmove",this,!1),J.addEventListener("touchend",this,!1))},move:function(a){var b;if(u(a))b=a;else{if(a.touches.length>1||a.scale&&1!==a.scale)return;d.disableScroll&&a.preventDefault(),b=a.touches[0]}z={x:b.pageX-y.x,y:b.pageY-y.y},"undefined"==typeof w&&(w=!!(w||Math.abs(z.x)0||K===F.length-1&&z.x<0?Math.abs(z.x)/H+1:1),p(K-1,z.x+G[K-1],0),p(K,z.x+G[K],0),p(K+1,z.x+G[K+1],0)))},end:function(a){var b=+new Date-y.time,c=Number(b)<250&&Math.abs(z.x)>20||Math.abs(z.x)>H/2,e=!K&&z.x>0||K===F.length-1&&z.x<0;d.continuous&&(e=!1);var f=Math.abs(z.x)/z.x;w||(c&&!e?(f<0?(d.continuous?(o(l(K-1),-H,0),o(l(K+2),H,0)):o(K-1,-H,0),o(K,G[K]-H,L),o(l(K+1),G[l(K+1)]-H,L),K=l(K+1)):(d.continuous?(o(l(K+1),H,0),o(l(K-2),-H,0)):o(K+1,H,0),o(K,G[K]+H,L),o(l(K-1),G[l(K-1)]+H,L),K=l(K-1)),j(m(),F[K],f)):d.continuous?(o(l(K-1),-H,L),o(K,0,L),o(l(K+1),H,L)):(o(K-1,-H,L),o(K,0,L),o(K+1,H,L))),u(a)?(J.removeEventListener("mousemove",N,!1),J.removeEventListener("mouseup",N,!1),J.removeEventListener("mouseleave",N,!1)):(J.removeEventListener("touchmove",N,!1),J.removeEventListener("touchend",N,!1))},transitionEnd:function(a){var b=parseInt(a.target.getAttribute("data-index"),10);b===K&&((A||d.autoRestart)&&t(),k(m(),F[K]))}};return g(),A&&r(),{setup:g,slide:function(a,b){s(),n(a,b)},prev:function(){s(),h()},next:function(){s(),i()},restart:t,stop:s,getPos:m,getNumSlides:function(){return I},kill:v}}}var a="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this,b=a.document||this.document;return(a.jQuery||a.Zepto)&&!function(a){a.fn.Swipe=function(b){return this.each(function(){a(this).data("Swipe",new Swipe(a(this)[0],b))})}}(a.jQuery||a.Zepto),Swipe}); \ No newline at end of file diff --git a/package.json b/package.json index 5a6fd39..e76c019 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "swipejs", - "version": "2.1.5", + "version": "2.2.0", "main": "swipe.js", "description": "Swipe is the most accurate touch slider", "author": "Brad Birdsall", diff --git a/swipe.js b/swipe.js index d3ab020..45cb8a9 100644 --- a/swipe.js +++ b/swipe.js @@ -1,5 +1,5 @@ /*! - * Swipe 2.1.5 + * Swipe 2.2.0 * * Brad Birdsall * Copyright 2013, MIT License @@ -40,6 +40,15 @@ 'use strict'; + // setup initial vars + var start = {}; + var delta = {}; + var isScrolling; + + // setup auto slideshow + var delay = options.auto || 0; + var interval; + // utilities // simple no operation function var noop = function() {}; @@ -242,15 +251,17 @@ isPastBounds = false; } - // determine direction of swipe (true:right, false:left) - var direction = delta.x < 0; + // OLD determine direction of swipe (true:right, false:left) + // determine direction of swipe (1: backward, -1: forward) + var direction = Math.abs(delta.x) / delta.x; // if not scrolling vertically if (!isScrolling) { if (isValidSlide && !isPastBounds) { - if (direction) { + // if we're moving right + if (direction < 0) { if (options.continuous) { // we need to get the next in this direction in place @@ -278,12 +289,9 @@ move(index, slidePos[index]+width, speed); move(circle(index-1), slidePos[circle(index-1)]+width, speed); index = circle(index-1); - } - if (options.callback) { - options.callback(getPos(), slides[index]); - } + runCallback(getPos(), slides[index], direction); } else { @@ -319,13 +327,56 @@ if (currentIndex === index) { if (delay || options.autoRestart) restart(); - if (options.transitionEnd) { - options.transitionEnd.call(event, getPos(), slides[index]); - } + runTransitionEnd(getPos(), slides[index]); } } }; + // trigger setup + setup(); + + // start auto slideshow if applicable + if (delay) begin(); + + // Expose the Swipe API + return { + // initialize + setup: setup, + + // go to slide + slide: function(to, speed) { + stop(); + slide(to, speed); + }, + + // move to previous + prev: function() { + stop(); + prev(); + }, + + // move to next + next: function() { + stop(); + next(); + }, + + // Restart slideshow + restart: restart, + + // cancel slideshow + stop: stop, + + // return current index position + getPos: getPos, + + // return total number of slides + getNumSlides: function() { return length; }, + + // completely remove swipe + kill: kill + }; + // remove all event listeners function detachEvents() { if (browser.addEventListener) { @@ -452,14 +503,24 @@ else if (index < slides.length - 1) { slide(index+1); } + } + function runCallback(pos, index, dir) { + if (options.callback) { + options.callback(pos, index, dir); + } + } + + function runTransitionEnd(pos, index) { + if (options.transitionEnd) { + options.transitionEnd(pos, index); + } } function circle(index) { // a simple positive modulo using slides.length return (slides.length + (index % slides.length)) % slides.length; - } function getPos() { @@ -525,7 +586,7 @@ index = to; offloadFn(function() { - options.callback && options.callback(getPos(), slides[index]); + runCallback(getPos(), slides[index], direction); }); } @@ -586,10 +647,6 @@ } - // setup auto slideshow - var delay = options.auto || 0; - var interval; - function begin() { interval = setTimeout(next, delay); } @@ -609,103 +666,55 @@ return /^mouse/.test(e.type); } - // setup initial vars - var start = {}; - var delta = {}; - var isScrolling; - - // trigger setup - setup(); - - // start auto slideshow if applicable - if (delay) begin(); - - // Expose the Swipe API - return { - // initialize - setup: function() { setup(); }, - - // go to slide - slide: function(to, speed) { - stop(); - slide(to, speed); - }, - - // move to previous - prev: function() { - stop(); - prev(); - }, - - // move to next - next: function() { - stop(); - next(); - }, - - // Restart slideshow - restart: function() { restart(); }, - + function kill() { // cancel slideshow - stop: function() { stop(); }, - - // return current index position - getPos: function() { return getPos(); }, - - // return total number of slides - getNumSlides: function() { return length; }, - - // completely remove swipe - kill: function() { - // cancel slideshow - stop(); - - // remove inline styles - container.style.visibility = ''; + stop(); - // reset element - element.style.width = ''; - element.style.left = ''; + // remove inline styles + container.style.visibility = ''; - // reset slides - var pos = slides.length; - while (pos--) { + // reset element + element.style.width = ''; + element.style.left = ''; - if (browser.transitions) { - translate(pos, 0, 0); - } + // reset slides + var pos = slides.length; + while (pos--) { - var slide = slides[pos]; + if (browser.transitions) { + translate(pos, 0, 0); + } - // if the slide is tagged as clone, remove it - if (slide.getAttribute('data-cloned')) { - var _parent = slide.parentElement; - _parent.removeChild(slide); - } + var slide = slides[pos]; - // remove styles - slide.style.width = ''; - slide.style.left = ''; + // if the slide is tagged as clone, remove it + if (slide.getAttribute('data-cloned')) { + var _parent = slide.parentElement; + _parent.removeChild(slide); + } - slide.style.webkitTransitionDuration = - slide.style.MozTransitionDuration = - slide.style.msTransitionDuration = - slide.style.OTransitionDuration = - slide.style.transitionDuration = ''; + // remove styles + slide.style.width = ''; + slide.style.left = ''; - slide.style.webkitTransform = - slide.style.msTransform = - slide.style.MozTransform = - slide.style.OTransform = ''; + slide.style.webkitTransitionDuration = + slide.style.MozTransitionDuration = + slide.style.msTransitionDuration = + slide.style.OTransitionDuration = + slide.style.transitionDuration = ''; - // remove custom attributes (?) - // slide.removeAttribute('data-index'); - } + slide.style.webkitTransform = + slide.style.msTransform = + slide.style.MozTransform = + slide.style.OTransform = ''; - // remove all events - detachEvents(); + // remove custom attributes (?) + // slide.removeAttribute('data-index'); } - }; + + // remove all events + detachEvents(); + } } if ( root.jQuery || root.Zepto ) {