diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3cd5e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +/led-test.html +/touchexample3.html +/touchexample/js/libs/jquery.animate-enhanced.min.js +/touchexample \ No newline at end of file diff --git a/README.md b/README.md index 13f83a3..b91b51b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,27 @@ +Note: Currently in a bit of state of disrepair. Use at your own risk. + + +Cycle + Touch +=================== + +Fork homepage: [http://keeganbrown.github.com/cycle/] (http://keeganbrown.github.com/cycle/) + +* [Simple Example] (http://keeganbrown.github.com/cycle/touchexample1.html) +* [Custom Transition Example] (http://keeganbrown.github.com/cycle/touchexample2.html) +* [Super Fancy 3D Custom Transition] (http://keeganbrown.github.com/cycle/touchexample3.html) +* [Example with only 2 Slides] (http://keeganbrown.github.com/cycle/touchexample4.html) + +Integrating touch-compatibility requires a number of user-settable new options, and some modification/addition to core functionality in cycle. + +A sizable amount of code used in integrating Touch events exists within individual transitions, therefore some work has to be done to enable non-touch enabled transitions to be touch-friendly. Touch-enabled transitions are more complicated than non-touch enabled transitions, because touch interactions are inherently more complicated than click interactions. + +There is an option to allow the developer to emulate touch events by clicking-and-dragging, making integrating touch support into new transitions easier. + +Touch-capability tested on Android 2.3 and iOS 4+. + +Feedback is greatly appreciated. + + jQuery Cycle Plugin =================== @@ -9,4 +33,3 @@ Links * [Options Reference](http://jquery.malsup.com/cycle/options.html) * [Effects Browser](http://jquery.malsup.com/cycle/browser.html) * [Download](http://jquery.malsup.com/cycle/download.html) - \ No newline at end of file diff --git a/jquery.cycle.all.js b/jquery.cycle.all.js index caef8ea..795b025 100644 --- a/jquery.cycle.all.js +++ b/jquery.cycle.all.js @@ -2,15 +2,20 @@ * jQuery Cycle Plugin (with Transition Definitions) * Examples and documentation at: http://jquery.malsup.com/cycle/ * Copyright (c) 2007-2010 M. Alsup - * Version: 2.9999.4 (29-MAR-2012) + * Version: 2.9999.5 (10-APR-2012) * Dual licensed under the MIT and GPL licenses. * http://jquery.malsup.com/license.html * Requires: jQuery v1.3.2 or later + * + * Touch Support integration features ( "TOUCHMOD" ) + * TOUCHMOD Requires: jQuery v1.4.3 or later + * Modified By: Keegan Brown -- TOUCHMOD Version: 0.9.8 (08-NOV-2012) + * */ ;(function($, undefined) { "use strict"; -var ver = '2.9999.4'; +var ver = '2.9999.5' + " + TOUCHMOD"; // if $.support is not defined (pre jQuery 1.3) add what I need if ($.support === undefined) { @@ -22,7 +27,7 @@ if ($.support === undefined) { function debug(s) { if ($.fn.cycle.debug) log(s); -} +} function log() { if (window.console && console.log) console.log('[cycle] ' + Array.prototype.join.call(arguments,' ')); @@ -66,11 +71,12 @@ $.fn.cycle = function(options, arg2) { return; opts.updateActivePagerLink = opts.updateActivePagerLink || $.fn.cycle.updateActivePagerLink; - + // stop existing slideshow for this container (if there is one) if (this.cycleTimeout) clearTimeout(this.cycleTimeout); this.cycleTimeout = this.cyclePause = 0; + this.cycleStop = 0; // issue #108 var $cont = $(this); var $slides = opts.slideExpr ? $(opts.slideExpr, this) : $cont.children(); @@ -181,7 +187,7 @@ function handleArguments(cont, options, arg2) { return false; } return options; - + function checkInstantResume(isPaused, arg2, cont) { if (!isPaused && arg2 === true) { // resume now! var options = $(cont).data('cycle.opts'); @@ -195,6 +201,7 @@ function handleArguments(cont, options, arg2) { } go(options.elements, options, 1, !options.backwards); } + return true; } } @@ -211,19 +218,370 @@ function destroy(cont, opts) { $(opts.next).unbind(opts.prevNextEvent); if (opts.prev) $(opts.prev).unbind(opts.prevNextEvent); - + if (opts.pager || opts.pagerAnchorBuilder) $.each(opts.pagerAnchors || [], function() { this.unbind().remove(); }); + + //destory touchmod + if ( opts.touchFx ) { + destroyTouch(cont, opts); + } opts.pagerAnchors = null; $(cont).unbind('mouseenter.cycle mouseleave.cycle'); if (opts.destroy) // callback opts.destroy(opts); } +// +// BEGIN TOUCHMOD SUPPORT HANDLING +var supportsTouch = false; +var detectTouchSupport = function (bypass) { + try { + if ( 'ontouchstart' in window && + typeof TouchEvent != "undefined" && + "ontouchend" in document ) + { + supportsTouch = true; + } + } catch (e) { supportsTouch = false; } + + // Add jQuery support for CSS3 + vendor prefixes + if ( supportsTouch ) { $.fn.cycle.addCSS3Support(); } + + return supportsTouch; +} +$.fn.cycle.haveCheckedCSS3Support = false; +$.fn.cycle.checkStyleSupport = function checkStyleSupport ( index, prop ) { + var vendorProp, supportedProp, + // capitalize first character of the prop to test vendor prefix + capProp = prop.charAt(0).toUpperCase() + prop.slice(1), + prefixes = [ "Moz", "Webkit", "O", "ms" ], + div = document.createElement( "div" ); + + if ( prop in div.style ) { + // browser supports standard CSS property name + supportedProp = prop; + } else { + // otherwise test support for vendor-prefixed property names + for ( var i = 0; i < prefixes.length; i++ ) { + vendorProp = prefixes[i] + capProp; + if ( vendorProp in div.style ) { + supportedProp = vendorProp; + break; + } + } + } + + // avoid memory leak in IE + div = null; + // add property to $.support so it can be accessed elsewhere + $.support[ prop ] = supportedProp; + + if ( !!supportedProp && supportedProp !== prop ) { + $.cssHooks[prop] = { + get: function( elem, computed, extra ) { + return $.css( elem, supportedProp ); + }, + set: function( elem, value) { + elem.style[ supportedProp ] = value; + } + } + } + return supportedProp; +} +$.fn.cycle.addCSS3Support = function () { + $.fn.cycle.haveCheckedCSS3Support = true; + var addSupportFor = [ 'userSelect', 'userModify', 'userDrag', 'tapHighlightColor' ]; + var extraSupport = [ 'transitionDuration', 'transitionDelay', 'transform', 'transformOrigin', 'transformStyle','transitionProperty', 'transition', 'perspective', 'backfaceVisibility' ]; + + var checkSupportForCSS3d = !!navigator.userAgent.match(/ipod|ipad|iphone/gi); + if ( checkSupportForCSS3d ) { + var totalsup = addSupportFor.join('|') + '|' + extraSupport.join('|'); + addSupportFor = totalsup.split('|'); + } + $( addSupportFor ).each( $.fn.cycle.checkStyleSupport ); +} + +function destroyTouch (cont, opts) { + //TOUCHMOD -- DESTROY TOUCHMOD RELATED EVENT LISTENERS. + var $cont = $(cont); + $cont.unbind('touchstart touchmove touchend touchcancel'); + + if (opts.touchClickDrag) { + $cont.unbind( 'mousedown mousemove mouseup' ); + } +} + +// Request Animation Frame Pollyfill +function polyfillRequestAnimFrame (window) { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; + window.cancelAnimationFrame = + window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function() { callback(currTime + timeToCall); }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; +} + +function integrateTouch (opts, cont) { + polyfillRequestAnimFrame(window); + + if ( !!supportsTouch && ( !!opts.touchFx || $.fn.cycle.transitions[opts.fx].activeDir ) ) { + var getTouchPos = function (event) { + if ( !!event && !!event.originalEvent && !!event.originalEvent.touches ) { + return ({ pageX: event.originalEvent.touches[0].pageX, pageY: event.originalEvent.touches[0].pageY }); + } else if ( !!event && ( !!event.pageX || !!event.pageY ) ) { + return ({ pageX: event.pageX, pageY: event.pageY }); + } + return ({ pageX: 0, pageY: 0 }); + } + + var SCROLLING_DRAGSTATE = "locked_for_page_scroll", + DRAGGING_DRAGSTATE = "dragging_cycle_elements", + INIT_DRAGSTATE = "init_dragging"; + + var $cont = opts.$cont; + + opts.touch = { + initPos: getTouchPos(), diffPos: getTouchPos(), + prevElem: null, currElem: null, nextElem: null, + mainContSize: { width: $cont.width(), height: $cont.height() }, + touchFx: null, + dir: { x: 0, y: 0 }, + currStart: { x: 0, y: 0 }, + changeCycle: 0, dragstate: null, + revdir: ( ( !!opts.rev ) ? -1 : 1 ) + } + + //window.opts = opts; + var bindTouchPause = function ($cont, touchPause, touchUnpause) { + $(window).bind({ + touchstart: touchPause, + touchend: touchUnpause + }); + } + var bindPauseOnClickAndDrag = function ($cont, touchPause, touchUnpause) { + $(window).bind({ + mouseover: touchPause, + mouseout: touchUnpause + }); + } + var onTouchPause = function () { + $cont.data( 'touchPauseFlag', true ); + $cont[0].cyclePause++; + triggerPause( $cont[0], true ); + } + var onTouchUnPause = function () { + var pauseFlag = !!$cont.data( 'touchPauseFlag' ); + if ( pauseFlag ) + $cont[0].cyclePause--; + triggerPause( $cont[0], true ); + $cont.data( 'touchPauseFlag', false ); + } + + bindTouchPause( $(cont), onTouchPause, onTouchUnPause ); + if ( !!opts.touchClickDrag ) { + bindPauseOnClickAndDrag( $(cont), onTouchPause, onTouchUnPause ); + } + + //TOUCHMOD -- HANDLING FOR SCROLLING RESULTING JAVASCRIPT PROBLEMS + var abortDrag = function () { + opts.touch.initPos = getTouchPos(); + opts.touch.diffPos = getTouchPos(); + opts.touch.dragstate = null; + } + + //TOUCHMOD -- ADD CSS RULES TO PREVENT ODD BEHAVIOR, EG SELECTING TEXT WHILE TOUCHMOVE + $(opts.elements).css( { + userSelect: 'none', userModify: 'read-only', + userDrag: 'none', tapHighlightColor: 'transparent' + } ); + + //TOUCHMOD -- TOUCH BEHAVIOR INITIALIZATION + var initSlidePos, snapSlideBack, dragSlideTick; + + //TOUCHMOD -- TOUCH TRANSITION & ASSOCIATED OPTIONS + if ( !!opts.touchFx && !!$.fn.cycle.transitions[opts.touchFx] ) { + opts.touch.touchFx = opts.touchFx; + opts.touch.dir = ( !!$.fn.cycle.transitions[opts.touchFx].activeDir ) ? $.fn.cycle.transitions[opts.touchFx].activeDir : { x: 1, y: 0 }; + if ( !!opts.touch.dir.x ) { + opts.touch.changeCycle = (opts.touch.mainContSize.width/4); + } else if ( !!opts.touch.dir.y ) { + opts.touch.changeCycle = (opts.touch.mainContSize.height/4); + } + + //ALLOW USER OPTION TO OVERRIDE DEFAULT TOUCH BEHAVIOR INITIALIZATION + if ( !!$.fn.cycle.transitions[opts.touchFx].initSlidePos ) { + initSlidePos = $.fn.cycle.transitions[opts.touchFx].initSlidePos; + } + if ( !!$.fn.cycle.transitions[opts.touchFx].snapSlideBack ) { + snapSlideBack = $.fn.cycle.transitions[opts.touchFx].snapSlideBack; + } + if ( !!$.fn.cycle.transitions[opts.touchFx].dragSlideTick ) { + dragSlideTick = $.fn.cycle.transitions[opts.touchFx].dragSlideTick; + } + } else { + return false; + } + + opts.touch.changeCycle = ( !!opts.touchCycleLimit ) ? opts.touchCycleLimit : opts.touch.changeCycle; + + //TOUCHMOD -- TOUCH CORE FUNCTIONALITY -- GETTING POSITION OF TOUCH EVENTS, PREPARING ELEMENTS FOR DRAGGING + var resetTransition = function () { + $.fn.cycle.resetState(opts); + } + var dragStart = function (event) { + if( !!opts.busy || !!( navigator.userAgent.match(/android/gi) || location.href.match('testandroid') ) ) { event.preventDefault(); } + if( !!opts.busy ) { resetTransition(); } + + if ( !opts.touch.dragstate && !opts.busy ) { + window.cycle_touchMoveCurrentPos = getTouchPos(event); + var currPos = window.cycle_touchMoveCurrentPos; + + opts.touch.initPos.pageX = currPos.pageX - opts.touch.initPos.pageX; + opts.touch.initPos.pageY = currPos.pageY - opts.touch.initPos.pageY; + + var prevNum = (opts.elements.length + opts.currSlide - 1) % opts.elements.length; + var nextNum = (opts.elements.length + opts.currSlide + 1) % opts.elements.length; + + opts.touch.prevElem = $( opts.elements[prevNum] ); + opts.touch.currElem = $( opts.elements[opts.currSlide] ); + opts.touch.nextElem = $( opts.elements[nextNum] ); + + opts.touch.currStart.x = opts.touch.currElem.position().left; + opts.touch.currStart.y = opts.touch.currElem.position().top; + + initSlidePos( opts, opts.touch.prevElem, opts.touch.currElem, opts.touch.nextElem, opts.touch.initPos, opts.touch.mainContSize, opts.touch.dir, opts.touch.revdir, opts.touch.currStart ); + + opts.touch.dragstate = INIT_DRAGSTATE; + } + } + + var dragFrameTick = function () { + var currPos = window.cycle_touchMoveCurrentPos; + + opts.touch.diffPos.pageX = currPos.pageX - opts.touch.initPos.pageX; + opts.touch.diffPos.pageY = currPos.pageY - opts.touch.initPos.pageY; + + if ( opts.touch.dragstate === DRAGGING_DRAGSTATE ) { + if ( Math.abs( opts.touch.diffPos.pageX ) * opts.touch.dir.x > opts.touchMinDrag || Math.abs( opts.touch.diffPos.pageY ) * opts.touch.dir.y > opts.touchMinDrag ) { + dragSlideTick( opts, opts.touch.prevElem, opts.touch.currElem, opts.touch.nextElem, opts.touch.diffPos, opts.touch.mainContSize, opts.touch.dir, opts.touch.revdir, opts.touch.currStart ); + } else { + snapSlideBack( opts, opts.touch.prevElem, opts.touch.currElem, opts.touch.nextElem, opts.touch.diffPos, opts.touch.mainContSize, opts.touch.dir, opts.touch.revdir, opts.touch.currStart ); + } + } + window.requestAnimationFrame( dragFrameTick ); + } + + var dragMove = function (event) { + if ( !!opts.touch.dragstate && !opts.busy ) { + window.cycle_touchMoveCurrentPos = getTouchPos(event); + if ( opts.touch.dragstate === INIT_DRAGSTATE && ( Math.abs( opts.touch.diffPos.pageX ) * opts.touch.dir.x > opts.touchMinDrag || Math.abs( opts.touch.diffPos.pageY ) * opts.touch.dir.y > opts.touchMinDrag ) ) { + opts.touch.dragstate = DRAGGING_DRAGSTATE; + } + if ( opts.touch.dragstate === INIT_DRAGSTATE && ( Math.abs( opts.touch.diffPos.pageX ) * opts.touch.dir.y > opts.touchMinDrag || Math.abs( opts.touch.diffPos.pageY ) * opts.touch.dir.x > opts.touchMinDrag ) ) { + opts.touch.dragstate = SCROLLING_DRAGSTATE; + } + } + if ( opts.touch.dragstate === DRAGGING_DRAGSTATE || !!opts.busy ) { + event.preventDefault(); + } + } + + window.cycle_touchMoveCurrentPos = getTouchPos(); + + var dragEnd = function (event) { + if ( opts.touch.dragstate === DRAGGING_DRAGSTATE ) { + var cacheOpts = { speed: opts.speed, fx: opts.fx, ease: opts.easing } + var newspeed = 0; + + opts.fx = opts.touch.touchFx; + opts.easing = 'linear'; + + if ( !!opts.touch.dir.x && Math.abs(opts.touch.diffPos.pageX) > opts.touch.changeCycle ) { + newspeed = Math.round( opts.speed * ( ( opts.touch.mainContSize.width - (opts.touch.mainContSize.width/4) - Math.abs( opts.touch.diffPos.pageX ) ) / opts.touch.mainContSize.width ) ) + 50; + opts.speed = newspeed; + opts.speedIn = newspeed; + opts.speedOut = newspeed; + + if ( opts.touch.diffPos.pageX <= 0) advance(opts,1); + if ( opts.touch.diffPos.pageX > 0) advance(opts,0); + } else if ( !!opts.touch.dir.y && Math.abs(opts.touch.diffPos.pageY) > opts.touch.changeCycle ) { + newspeed = Math.round( opts.speed * ( ( opts.touch.mainContSize.height - (opts.touch.mainContSize.height/4) - Math.abs( opts.touch.diffPos.pageY ) ) / opts.touch.mainContSize.height ) ) + 50; + opts.speed = newspeed; + opts.speedIn = newspeed; + opts.speedOut = newspeed; + + if ( opts.touch.diffPos.pageY <= 0) advance(opts,1); + if ( opts.touch.diffPos.pageY > 0) advance(opts,0); + } else { + snapSlideBack( opts, opts.touch.prevElem, opts.touch.currElem, opts.touch.nextElem, opts.touch.diffPos, opts.touch.mainContSize, opts.touch.dir, opts.touch.revdir, opts.touch.currStart ); + } + opts.touch.dragstate = null; + opts.speed = cacheOpts.speed; + opts.speedIn = cacheOpts.speed; + opts.speedOut = cacheOpts.speed; + opts.fx = cacheOpts.fx; + opts.easing = cacheOpts.ease; + + opts.touch.initPos = getTouchPos(); + opts.touch.diffPos = getTouchPos(); + } else { + abortDrag(); + } + } + var dragCancel = function (e) { + abortDrag(); + } + + $cont.bind({ + touchstart: dragStart, + touchmove: dragMove, + touchend: dragEnd, + touchcancel: dragCancel + }); + + if (opts.touchClickDrag) { + $cont.bind({ + mousedown: dragStart, + mousemove: dragMove, + mouseup: dragEnd + }); + } + + dragFrameTick(); + } +} +// END TOUCHMOD SUPPORT HANDLING +// + + // one-time initialization function buildOptions($cont, $slides, els, options, o) { + + //TOUCHMOD -- DETECT TOUCH SUPPORT ON DEVICE + supportsTouch = detectTouchSupport(); + if ( !!supportsTouch ) { + $.fn.cycle.defaults.pauseOnTouch = 1; + } + var startingSlideSpecified; // support metadata plugin (v1.0 and v2.0) var opts = $.extend({}, $.fn.cycle.defaults, options || {}, $.metadata ? $cont.metadata() : $.meta ? $cont.data() : {}); @@ -241,6 +599,15 @@ function buildOptions($cont, $slides, els, options, o) { opts.before = opts.before ? [opts.before] : []; opts.after = opts.after ? [opts.after] : []; + //TOUCHMOD -- INTEGRATE TOUCH SUPPORT IF TRANSITION SPECIFIED + if ( !!opts.touchFx ) { + if ( !!options.touchClickDrag && !supportsTouch ) { + opts.touchPagerEvent = opts.pagerEvent; + supportsTouch = true; + } + integrateTouch(opts, cont); + } + // push some after callbacks if (!$.support.opacity && opts.cleartype) opts.after.push(function() { removeFilter(this, opts); }); @@ -265,7 +632,7 @@ function buildOptions($cont, $slides, els, options, o) { opts.startingSlide = parseInt(opts.startingSlide,10); if (opts.startingSlide >= els.length || opts.startSlide < 0) opts.startingSlide = 0; // catch bogus input - else + else startingSlideSpecified = true; } else if (opts.backwards) @@ -358,7 +725,7 @@ function buildOptions($cont, $slides, els, options, o) { }); }); } - + // stretch container var reshape = opts.containerResize && !$cont.innerHeight(); if (reshape) { // do this only if container has no size http://tinyurl.com/da2oa9 @@ -375,7 +742,7 @@ function buildOptions($cont, $slides, els, options, o) { } var pauseFlag = false; // https://github.com/malsup/cycle/issues/44 - if (opts.pause) + if (opts.pause) { $cont.bind('mouseenter.cycle', function(){ pauseFlag = true; this.cyclePause++; @@ -385,6 +752,8 @@ function buildOptions($cont, $slides, els, options, o) { this.cyclePause--; triggerPause(cont, true); }); + } + if (supportMultiTransitions(opts) === false) return false; @@ -442,7 +811,7 @@ function buildOptions($cont, $slides, els, options, o) { opts.speed = $.fx.speeds[opts.speed] || parseInt(opts.speed,10); if (!opts.sync) opts.speed = opts.speed / 2; - + var buffer = opts.fx == 'none' ? 0 : opts.fx == 'shuffle' ? 500 : 250; while((opts.timeout - opts.speed) < buffer) // sanitize timeout opts.timeout += opts.speed; @@ -700,7 +1069,7 @@ function go(els, opts, manual, fwd) { }; debug('tx firing('+fx+'); currSlide: ' + opts.currSlide + '; nextSlide: ' + opts.nextSlide); - + // get ready to perform the transition opts.busy = 1; if (opts.fxFn) // fx function provided? @@ -755,7 +1124,7 @@ function go(els, opts, manual, fwd) { } if (changed && opts.pager) opts.updateActivePagerLink(opts.pager, opts.currSlide, opts.activePagerClass); - + function queueNext() { // stage the next transition var ms = 0, timeout = opts.timeout; @@ -852,7 +1221,7 @@ $.fn.cycle.createPagerAnchor = function(i, el, $p, els, opts) { } else a = ''+(i+1)+''; - + if (!a) return; var $a = $(a); @@ -874,7 +1243,7 @@ $.fn.cycle.createPagerAnchor = function(i, el, $p, els, opts) { opts.pagerAnchors = opts.pagerAnchors || []; opts.pagerAnchors.push($a); - + var pagerFn = function(e) { e.preventDefault(); opts.nextSlide = i; @@ -889,30 +1258,30 @@ $.fn.cycle.createPagerAnchor = function(i, el, $p, els, opts) { go(els,opts,1,opts.currSlide < i); // trigger the trans // return false; // <== allow bubble }; - + if ( /mouseenter|mouseover/i.test(opts.pagerEvent) ) { $a.hover(pagerFn, function(){/* no-op */} ); } else { $a.bind(opts.pagerEvent, pagerFn); } - + if ( ! /^click/.test(opts.pagerEvent) && !opts.allowPagerClickBubble) $a.bind('click.cycle', function(){return false;}); // suppress click - + var cont = opts.$cont[0]; var pauseFlag = false; // https://github.com/malsup/cycle/issues/44 if (opts.pauseOnPagerHover) { $a.hover( - function() { + function() { pauseFlag = true; - cont.cyclePause++; + cont.cyclePause++; triggerPause(cont,true,true); - }, function() { + }, function() { if (pauseFlag) - cont.cyclePause--; + cont.cyclePause--; triggerPause(cont,true,true); - } + } ); } }; @@ -985,7 +1354,7 @@ $.fn.cycle.custom = function(curr, next, opts, cb, fwd, speedOverride) { }; $l.animate(opts.animOut, speedOut, easeOut, function() { $l.css(opts.cssAfter); - if (!opts.sync) + if (!opts.sync) fn(); }); if (opts.sync) fn(); @@ -1018,7 +1387,7 @@ $.fn.cycle.defaults = { autostop: 0, // true to end slideshow after X transitions (where X == slide count) autostopCount: 0, // number of transitions (optionally used with autostop to define X) backwards: false, // true to start slideshow at last slide and move backwards through the stack - before: null, // transition callback (scope set to element to be shown): function(currSlideElement, nextSlideElement, options, forwardFlag) + before: null, // transition callback (scope set to element to be shown): function(currSlideElement, nextSlideElement, options, forwardFlag) center: null, // set to true to have cycle add top/left margin to each slide (use with width and height options) cleartype: !$.support.opacity, // true if clearType corrections should be applied (for IE) cleartypeNoBg: false, // set to true to disable extra cleartype fixing (leave false to force background color setting on slides) @@ -1065,6 +1434,10 @@ $.fn.cycle.defaults = { sync: 1, // true if in/out transitions should occur simultaneously timeout: 4000, // milliseconds between slide transitions (0 to disable auto advance) timeoutFn: null, // callback for determining per-slide timeout value: function(currSlideElement, nextSlideElement, options, forwardFlag) + touchFx: null, // name of touch transition effect. Touch Functionality will not be enabled if left "null" or "false" + touchCycleLimit: 0, // Number (in px) for touch gesture before a touchend event will force a cycle. + touchClickDrag: 0, // true to enable mouse slide-dragging. + touchMinDrag: 0, // Minimum (in px) before touch handling will effect positioning of the cycle updateActivePagerLink: null,// callback fn invoked to update the active pager link (adds/removes activePagerClass style) width: null // container width (if the 'fit' option is true, the slides will be set to this width as well) }; @@ -1541,4 +1914,114 @@ $.fn.cycle.transitions.wipe = function($cont, $slides, opts) { opts.animOut = { left: 0 }; }; + +//TOUCHMOD -- TRANSITIONS WITH TOUCH-ENHANCEMENTS +$.fn.cycle.transitions.touchScrollHorz = function($cont, $slides, opts) { + $cont.css( { overflow: 'hidden', transform: 'translate3d(0,0,0)' }); + if ( !!this && !this.isSetup ) { + $slides.css( { position: 'absolute', display: 'block', top: 0, left: 0, zIndex: 5, opacity: 1 } ); + this.isSetup = true; + } + opts.before.push(function(curr, next, opts, fwd) { + var dirrev = -1; + if (opts.rev) { + fwd = !fwd; + dirrev = 1; + } + $.fn.cycle.commonReset(curr,next,opts); + opts.animOut.left = fwd ? curr.cycleW * dirrev : -curr.cycleW * dirrev; + }); + opts.cssFirst.left = 0; + opts.cssBefore.top = 0; + opts.animIn.left = 0; + opts.animOut.top = 0; +} +$.fn.cycle.transitions.touchScrollHorz.activeDir = { x: 1, y: 0 } +$.fn.cycle.transitions.touchScrollHorz.initSlidePos = function ( opts, prevElem, currElem, nextElem, initPos, mainContSize, dir, revdir, currStart ) { + var move = { x: (mainContSize.width * dir.x * revdir), y: (mainContSize.height * dir.y * revdir) } + prevElem.stop(true,false).css( { left: -move.x + currStart.x, top: -move.y + currStart.y, display: 'block', opacity: 1 } ); + currElem.stop(true,false).css( { left: 0, top: 0, display: 'block', opacity: 1 } ); + nextElem.stop(true,false).css( { left: move.x + currStart.x, top: move.y + currStart.y, display: 'block', opacity: 1 } ); +} +$.fn.cycle.transitions.touchScrollHorz.snapSlideBack = function ( opts, prevElem, currElem, nextElem, diffPos, mainContSize, dir, revdir, currStart ) { + var move = { x: (mainContSize.width * dir.x * revdir), y: (mainContSize.height * dir.y * revdir) } + prevElem.stop(true,false).animate( { left: -move.x, top: -move.y }, opts.speed/4 ); + currElem.stop(true,false).animate( { left: 0, top: 0 }, opts.speed/4 ); + nextElem.stop(true,false).animate( { left: move.x, top: move.y }, opts.speed/4 ); +} +$.fn.cycle.transitions.touchScrollHorz.dragSlideTick = function ( opts, prevElem, currElem, nextElem, diffPos, mainContSize, dir, revdir, currStart ) { + if ( diffPos.pageX * dir.x > 0 || diffPos.pageY * dir.y > 0 ) { + prevElem.stop(true,false).css( { + left: ( ( -mainContSize.width + diffPos.pageX ) * dir.x ) + currStart.x, + top: ( ( -mainContSize.height + diffPos.pageY ) * dir.y ) + currStart.y, + display: 'block', opacity: 1, zIndex: 9 + } ); + } + currElem.stop(true,false).css( { + left: ( ( 0 + diffPos.pageX ) * dir.x ) + currStart.x, + top: ( ( 0 + diffPos.pageY ) * dir.y ) + currStart.y, + display: 'block', opacity: 1, zIndex: 10 + } ); + if ( diffPos.pageX * dir.x < 0 || diffPos.pageY * dir.y < 0 ) { + nextElem.stop(true,false).css( { + left: ( ( mainContSize.width + diffPos.pageX ) * dir.x ) + currStart.x, + top: ( ( mainContSize.height + diffPos.pageY ) * dir.y ) + currStart.y, + display: 'block', opacity: 1, zIndex: 9 + }); + } +} + +$.fn.cycle.transitions.touchScrollVert = function($cont, $slides, opts) { + $cont.css( { overflow: 'hidden', transform: 'translate3d(0,0,0)' }); + opts.before.push(function(curr, next, opts, fwd) { + var dirrev = -1; + if (opts.rev) { + fwd = !fwd; + dirrev = 1; + } + $.fn.cycle.commonReset(curr,next,opts); + //opts.cssBefore.top = fwd ? (1-next.cycleH) : (next.cycleH-1); + opts.animOut.top = fwd ? curr.cycleH*dirrev : -curr.cycleH*dirrev; + }); + opts.cssFirst.top = 0; + opts.cssBefore.left = 0; + opts.animIn.top = 0; + opts.animOut.left = 0; +} +$.fn.cycle.transitions.touchScrollVert.activeDir = { x: 0, y: 1 } +$.fn.cycle.transitions.touchScrollVert.initSlidePos = function ( opts, prevElem, currElem, nextElem, initPos, mainContSize, dir, revdir, currStart ) { + var move = { x: (mainContSize.width * dir.x * revdir), y: (mainContSize.height * dir.y * revdir) } + prevElem.css( { left: -move.x + currStart.x, top: -move.y + currStart.y, display: 'block', opacity: 1 } ); + currElem.stop(true,false).css( { left: 0, top: 0, display: 'block', opacity: 1 } ); + nextElem.css( { left: move.x + currStart.x, top: move.y + currStart.y, display: 'block', opacity: 1 } ); +} +$.fn.cycle.transitions.touchScrollVert.snapSlideBack = function ( opts, prevElem, currElem, nextElem, diffPos, mainContSize, dir, revdir, currStart ) { + var move = { x: (mainContSize.width * dir.x * revdir), y: (mainContSize.height * dir.y * revdir) } + prevElem.stop(true,false).animate( { left: -move.x, top: -move.y }, opts.speed/4 ); + currElem.stop(true,false).animate( { left: 0, top: 0 }, opts.speed/4 ); + nextElem.stop(true,false).animate( { left: move.x, top: move.y }, opts.speed/4 ); +} +$.fn.cycle.transitions.touchScrollVert.dragSlideTick = function ( opts, prevElem, currElem, nextElem, diffPos, mainContSize, dir, revdir, currStart ) { + if ( diffPos.pageX * dir.x > 0 || diffPos.pageY * dir.y > 0 ) { + prevElem.stop(true,false).css( { + left: ( ( -mainContSize.width + diffPos.pageX ) * dir.x ) + currStart.x, + top: ( ( -mainContSize.height + diffPos.pageY ) * dir.y ) + currStart.y, + display: 'block', opacity: 1 + }); + } + currElem.stop(true,false).css( { + left: ( ( 0 + diffPos.pageX ) * dir.x ) + currStart.x, + top: ( ( 0 + diffPos.pageY ) * dir.y ) + currStart.y, + display: 'block', opacity: 1 + }); + if ( diffPos.pageX * dir.x < 0 || diffPos.pageY * dir.y < 0 ) { + nextElem.stop(true,false).css( { + left: ( ( mainContSize.width + diffPos.pageX ) * dir.x ) + currStart.x, + top: ( ( mainContSize.height + diffPos.pageY ) * dir.y ) + currStart.y, + display: 'block', opacity: 1 + }); + } +} + + })(jQuery);