(function($) { $.fn.reverse = [].reverse; $.fn.touchSlider = function(options){ var options = $.extend({ item: 'li.item', holder: 'ul.holder', box: 'li.list', debug: false, mode: 'shift', shift: '80%', delta: 40, single: false, center: false, animation: 'auto', touch: true, duration: 500, prevLink: null, nextLink: null, onChange: null, onStart: null, onCheckItems: null, lockScroll: false, hideClass: 'mt-hidden', activeClass: 'active' }, options); this.each(function() { var $this = jQuery(this); if(options.debug) $('body').append('
'); var events = [{start: 'mousedown', end: 'mouseup', move: 'mousemove', leave: 'mouseout'}, {start: 'touchstart', end: 'touchend', move: 'touchmove', leave: 'touchend'}]; var eventIndex = "ontouchend" in document ? 1 : 0; var items = $(options.item, this); if (!items.length) return; var holder = $(options.holder, this).first(); if (!holder.length) return; var box = $(options.box, this).first(); if (!box.length) return; var cssTransitionsSupported = false; if (options.animation && options.animation != 'js') { var body = document.body || document.documentElement; var bodyStyle = body.style; var transitionEndEvent = (bodyStyle.WebkitTransition !== undefined) ? "webkitTransitionEnd" : "transitionend"; cssTransitionsSupported = bodyStyle.WebkitTransition !== undefined || bodyStyle.MozTransition !== undefined || bodyStyle.transition !== undefined; if (cssTransitionsSupported && options.animation == 'auto') { debug('Detected Transitions Support', ''); box.css({ '-webkit-transition-property': '-webkit-transform', '-webkit-transition-timing-function': 'ease', '-moz-transition-property': '-moz-transform', '-moz-transition-timing-function': 'ease', 'transition-property': 'transform', 'transition-timing-function': 'ease' }); box.unbind(transitionEndEvent); box.bind(transitionEndEvent, endAnimation); } var has3D = ('WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix()); if (has3D) { debug('Detected 3D Support', ''); } } var currentIndex = null; var currentOffset = null; var graphRealIndex = 0; var graphItems = []; var currentSubOffset = 0; var previousIndex = null; var previousOffset = null; var touchOffset = 0; var hasChanges = false; setCurrentIndex(0); setCurrentOffset(0); if(options.touch) { var b = box.get(0); b.addEventListener(events[eventIndex]['start'], touchEvent, false); b.addEventListener(events[eventIndex]['end'], touchEvent, false); b.addEventListener(events[eventIndex]['leave'], touchEvent, false); b.addEventListener(events[eventIndex]['move'], touchEvent, false); } if(options.prevLink) { $(options.prevLink, $this).bind('click', function(){ $this.get(0).movePrev(); return false; }); } if(options.nextLink) { $(options.nextLink, $this).bind('click', function(){ $this.get(0).moveNext(); return false; }); } window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", resizeEvent, false); window.addEventListener("load", resizeEvent, false); function resizeEvent() { setTimeout(initPosition, 200); } var isTouching = false; var startX = 0; var width = holder.width(); debug('Current width:', width); this.getCount = function() { return options.mode == 'auto' ? graphItems.length : $(items).length; }; this.moveNext = function() { switch(options.mode) { case 'index': moveNextIndex(); break; case 'shift': moveNextOffset(); break; case 'auto': moveNextAuto(); break; } }; this.movePrev = function() { switch(options.mode) { case 'index': movePrevIndex(); break; case 'shift': movePrevOffset(); break; case 'auto': movePrevAuto(); break; } } this.moveTo = function(i) { switch(options.mode) { case 'index': moveToIndex(i); break; //case 'auto': moveToAuto(i); //break; } } this.refresh = function() { initPosition(); } initPosition(true); function initPosition(init) { width = holder.width(); touchOffset = 0; var init = typeof(init) == 'undefined' ? false: init; if (init && $.isFunction(options.onStart)) { options.onStart(); } switch(options.mode) { case 'index': if (options.single) { var itemsWidth = 0; if (init) { resizeItems(); } else { $(items[currentIndex]).css('width', width); setTimeout(delayResizeItems, 100); } moveIndex(); } else if(options.center) { moveIndex(); } break; case 'shift': moveShift(); break; case 'auto': graphItems = []; if (options.single) resetGraphItems(); showLink('both'); items.each(function(i, el) { var w = this.offsetWidth; var l = graphItems.length; if (i == 0) { if (w > width){ graphItems.push([w, new Array(new Array(i, w)), 0]); } else { graphItems.push([w, new Array(new Array(i, w))]); } detectGraphIndex(i); } else { if (graphItems[l-1][0] + w <= width) { graphItems[l-1][0] += w; graphItems[l-1][1].push(new Array(i, w)); detectGraphIndex(i); } else { if (w > width){ graphItems.push([w, new Array(new Array(i, w)), 0]); } else { graphItems.push([w, new Array(new Array(i, w))]); } detectGraphIndex(i); } } }); if (currentIndex >= graphItems.length) setCurrentIndex(graphItems.length-1); if (options.single) resizeGraphItems(); if ($.isFunction(options.onCheckItems)) options.onCheckItems(); moveAuto(); break; } }; function resetGraphItems() { $(items).css('width', 'auto'); } function detectGraphIndex(i) { if (i == graphRealIndex) { setCurrentIndex(graphItems.length-1); } } function resizeItems() { $.each(items, function() { $(this).css('width', 'auto'); var _w = $(this).width(); if (_w < width) { $(this).css('width', width); } }); } function resizeGraphItems() { $.each(graphItems, function(i, el) { if (el[0] < width) { var orig = el[0]; el[0] = width; $(el[1]).each(function(k, item){ item[1] = parseInt(width*item[1]/orig); $(items[item[0]]).css('width', item[1]); }) } }); } function delayResizeItems() { resizeItems(); moveIndex(true); } function touchEvent(e) { var touch = (eventIndex) ? e.touches[0] : e; switch(e.type) { case events[eventIndex]['move']: touchMove(e, touch); break; case events[eventIndex]['start']: touchStart(e, touch); break; case events[eventIndex]['end']: case events[eventIndex]['leave']: touchEnd(e); break; } }; function touchMove(e, touch) { if (isTouching) { if (options.lockScroll && e.type != 'click') e.preventDefault(); touchOffset = startX - touch.pageX; if (touchOffset != 0) { moveTo(currentOffset - touchOffset, true); } } }; function touchStart(e, touch) { if (!isTouching) { hasChanges = false; //if (options.lockScroll && e.type != 'click') e.preventDefault(); debug('Touch Start'); isTouching = true; touchOffset = 0; startX = (eventIndex) ? touch.pageX : e.clientX; } }; function touchEnd(e, touch) { if (isTouching) { debug('Touch End'); isTouching = false; startX = 0; if (touchOffset != 0) { if (touchOffset > options.delta || touchOffset < (0 - options.delta)) { detectMove(); } else { moveTo(currentOffset); } } } touchOffset = 0; }; function detectMove() { switch(options.mode) { case 'shift': moveShift(); break; case 'index': moveIndex(); break; case 'auto': moveAuto(); break; } }; function moveIndex(now) { var itemsWidth = 0; var itemsBeforeWidth = 0; $.each(items, function(i){ if (i < currentIndex) { itemsBeforeWidth += this.offsetWidth; } itemsWidth += this.offsetWidth; }); if(itemsWidth <= width) {hideLink('both');return;}else{showLink('both');} var possibleOffset = 0; if (touchOffset > 0) { if (options.center) { possibleOffset = 0 - (itemsBeforeWidth + $(items[currentIndex]).width() + $(items[currentIndex+1]).width()/2) + width/2; if(currentIndex < items.length-1) { setCurrentIndex(currentIndex+1); setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { moveTo(currentOffset); } } else { possibleOffset = 0 - (itemsBeforeWidth + $(items[currentIndex]).width()); if(itemsWidth + possibleOffset > width) { setCurrentIndex(currentIndex+1); setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { setCurrentIndex(items.length - 1); setCurrentOffset(0 - (itemsWidth - width)); moveTo(currentOffset); } } } else if (touchOffset < 0) { if (options.center) { possibleOffset = 0 - (itemsBeforeWidth - $(items[currentIndex-1]).width()/2) + width/2; if(currentIndex > 0) { setCurrentIndex(currentIndex-1); setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { moveTo(currentOffset); } } else { possibleOffset = 0 - (itemsBeforeWidth - $(items[currentIndex]).width()); if(possibleOffset < 0) { setCurrentIndex(currentIndex-1); setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { setCurrentIndex(0); setCurrentOffset(0); moveTo(currentOffset); } } } else { if (options.center) { possibleOffset = 0 - (itemsBeforeWidth + $(items[currentIndex]).width()/2) + width/2; setCurrentOffset(possibleOffset); if (typeof(now) == 'undefined') { moveTo(currentOffset); }else { moveTo(currentOffset, true); } } else { possibleOffset = 0 - itemsBeforeWidth; setCurrentOffset(possibleOffset); if (typeof(now) == 'undefined') { moveTo(currentOffset); }else { moveTo(currentOffset, true); } } } }; function moveAuto() { var itemsWidth = 0; var itemsBeforeWidth = 0; $.each(graphItems, function(i){ if (i < currentIndex) { itemsBeforeWidth += this[0]; } itemsWidth += this[0]; }); var long = graphItems[currentIndex].length > 2 ? true : false; if(itemsWidth <= width) {hideLink('both');}else{showLink('both');} if (options.center && itemsWidth < width) { possibleOffset = width/2 - itemsWidth/2; setCurrentOffset(possibleOffset); moveTo(currentOffset); return; } var possibleOffset = 0; if (touchOffset > 0) { if(currentIndex < graphItems.length-1 || (currentIndex >= graphItems.length-1 && long)) { if (long && graphItems[currentIndex][0] - width > graphItems[currentIndex][2]) { graphItems[currentIndex][2] += width; if (graphItems[currentIndex][0] - graphItems[currentIndex][2] > width) { setCurrentOffset(currentOffset - width); moveTo(currentOffset); } else { setCurrentOffset(currentOffset - (graphItems[currentIndex][0] - graphItems[currentIndex][2])); graphItems[currentIndex][2] += graphItems[currentIndex][0] - graphItems[currentIndex][2]; graphItems[currentIndex][2] -= width; moveTo(currentOffset); } } else { if(typeof(graphItems[currentIndex+1]) != 'undefined') { if( graphItems[currentIndex+1].length > 2) { possibleOffset = 0 - (itemsBeforeWidth + graphItems[currentIndex][0]); } else { possibleOffset = 0 - (itemsBeforeWidth + graphItems[currentIndex][0] + graphItems[currentIndex+1][0]/2) + width/2; } if(itemsWidth + possibleOffset > width) { setCurrentIndex(currentIndex+1); setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { setCurrentIndex(graphItems.length - 1); setCurrentOffset(0 - (itemsWidth - width)); moveTo(currentOffset); } } else { moveTo(currentOffset); } } } else { moveTo(currentOffset); } } else if (touchOffset < 0) { if(currentIndex > 0 || (currentIndex <= 0 && long)) { if (long && graphItems[currentIndex][2] > 0) { graphItems[currentIndex][2] -= width; if (graphItems[currentIndex][2] >= 0) { setCurrentOffset(currentOffset + width); moveTo(currentOffset); } else { setCurrentOffset(currentOffset + (graphItems[currentIndex][2] + width)); graphItems[currentIndex][2] = 0; moveTo(currentOffset); } } else { if(typeof(graphItems[currentIndex-1]) != 'undefined' ) { if (graphItems[currentIndex-1].length > 2) { possibleOffset = 0 - (itemsBeforeWidth - width); graphItems[currentIndex-1][2] = graphItems[currentIndex-1][0] - width; } else { possibleOffset = 0 - (itemsBeforeWidth - graphItems[currentIndex-1][0]/2) + width/2; } if(possibleOffset < 0) { setCurrentIndex(currentIndex-1); setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { setCurrentIndex(0); setCurrentOffset(0); moveTo(currentOffset); } } else { moveTo(currentOffset); } } } else { moveTo(currentOffset); } } else { if (long) { possibleOffset = 0 - itemsBeforeWidth; } else { possibleOffset = 0 - (itemsBeforeWidth + graphItems[currentIndex][0]/2) + width/2; } if (possibleOffset >= 0) { setCurrentOffset(0); moveTo(currentOffset); } else if (itemsWidth + possibleOffset <= width) { setCurrentOffset(0 - (itemsWidth - width)); moveTo(currentOffset); } else { setCurrentOffset(possibleOffset); moveTo(currentOffset); } } }; function hideLink(name) { switch(name) { case "both": if(options.prevLink) $(options.prevLink, $this).addClass(options.hideClass); if(options.nextLink) $(options.nextLink, $this).addClass(options.hideClass); break; case "prev": if(options.prevLink) $(options.prevLink, $this).addClass(options.hideClass); break; case "next": if(options.nextLink) $(options.nextLink, $this).addClass(options.hideClass); break; } width = holder.width(); } function showLink(name) { switch(name) { case "both": if(options.prevLink) $(options.prevLink, $this).removeClass(options.hideClass); if(options.nextLink) $(options.nextLink, $this).removeClass(options.hideClass); break; case "prev": if(options.prevLink) $(options.prevLink, $this).removeClass(options.hideClass); break; case "next": if(options.nextLink) $(options.nextLink, $this).removeClass(options.hideClass); break; } width = holder.width(); } function moveShift() { var itemsWidth = 0; $.each(items, function(){ itemsWidth += this.offsetWidth; }); if (itemsWidth < width && !options.center) {return;} var shift = options.shift+''; var possibleOffset = 0; if(shift.indexOf('%') != -1) { shift = parseInt(width*options.shift.substr(0, options.shift.length-1)/100); } else { shift = parseInt(options.shift); } if (options.center && itemsWidth < width) { possibleOffset = width/2 - itemsWidth/2; setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { if (touchOffset > 0) { possibleOffset = currentOffset - shift; if(itemsWidth + possibleOffset > width) { setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { setCurrentOffset(0 - (itemsWidth - width)); moveTo(currentOffset); } } else { possibleOffset = currentOffset + shift; if(possibleOffset < 0) { setCurrentOffset(possibleOffset); moveTo(currentOffset); } else { setCurrentOffset(0); moveTo(currentOffset); } } } }; function moveNextOffset() { touchOffset = 1; moveShift(); } function movePrevOffset() { touchOffset = -1; moveShift(); } function debug(msg, param) { if (typeof(param) == 'undefined') { param = ''; } if (options.debug) { var d = new Date(); $('#console').prepend('
'+d.getMinutes()+':'+d.getSeconds()+'.'+d.getMilliseconds()+' '+ msg+' '+param+'
'); } }; function setCurrentIndex(index) { if (index != currentIndex) { hasChanges = true; previousIndex = currentIndex; currentIndex = index; if (options.mode == 'auto' && graphItems.length) { graphRealIndex = graphItems[currentIndex][1][0][0]; } else { $(items).removeClass(options.activeClass); $(items[currentIndex]).addClass(options.activeClass); } debug('Setting up current index:', index); } else { hasChanges = true; } }; function setCurrentOffset(offset) { if (offset != currentOffset) { previousOffset = currentOffset; currentOffset = offset; debug('Setting current offset:', offset); } }; function moveToIndex(index) { if (typeof(items[index]) != 'undefined') { setCurrentIndex(parseInt(index)); touchOffset = 0; moveIndex(); } } function moveNextIndex() { touchOffset = 1; moveIndex(); }; function movePrevIndex() { touchOffset = -1; moveIndex(); }; function moveNextAuto() { touchOffset = 1; moveAuto(); }; function movePrevAuto() { touchOffset = -1; moveAuto(); }; function moveTo(coord, now) { var delay = typeof(now) == 'undefined' ? options.duration : 0; if (typeof(now) == 'undefined' && $.isFunction(options.onChange) && hasChanges) { options.onChange(previousIndex, currentIndex); } if (!options.animation) { if (delay) { startAnimation(); box.css({ 'margin-left': coord+'px' }); endAnimation(); } } else { startAnimation(); var delayTransition = typeof(now) == 'undefined' ? options.duration/1000+'s' : '0'; if (cssTransitionsSupported) { box.css({ '-webkit-transition-duration': delayTransition, '-moz-transition-duration': delayTransition, 'transition-duration': delayTransition }); if(has3D) { debug('CSS 3D Transition To:', coord); box.css({ '-webkit-transform': 'translate3d('+coord+'px,0,0)', 'transform': 'translate3d('+coord+'px,0,0)' }); }else { debug('CSS Transition To:', coord); box.css({ '-webkit-transform': 'translate('+coord+'px,0)', '-moz-transform': 'translate('+coord+'px,0)', 'transform': 'translate('+coord+'px,0)' }); } } else { debug('jQuery Animate To:', coord); box.animate({ 'margin-left': coord+'px' },{ queue: false, duration: delay, easing: 'swing', complete: endAnimation }); } } }; function startAnimation() { box.addClass("moving"); debug('Animation start', ''); } function endAnimation() { box.removeClass("moving"); debug('Animation end', ''); } }); return this; }; })(jQuery);