/*! * @jSlider - a jQuery Plugin * @version 1.0.1 * * MIT License * Copyright (c) 2018 Thuy Nguyen */ (function(factory) { if (typeof define === 'function' && define.amd && define.amd.jQuery) { // AMD. Register as anonymous module. define(['jquery'], factory); } else if (typeof jQuery !== 'undefined') { // Browser globals. factory(jQuery); } })(function($) { "use strict"; /* global touching environment variables */ var isTouch = 'ontouchstart' in window , isPointerIE10 = (window.navigator.msPointerEnabled && !window.navigator.pointerEnabled) || false , isPointer = window.navigator.pointerEnabled || window.navigator.msPointerEnabled || false , isTouchDevice = isTouch || isPointer; var startEvent = isTouchDevice ? (isPointer ? (isPointerIE10 ? 'MSPointerDown' : 'pointerdown') : 'touchstart') : 'mousedown' , moveEvent = isTouchDevice ? (isPointer ? (isPointerIE10 ? 'MSPointerMove' : 'pointermove') : 'touchmove') : 'mousemove' , stopEvent = isTouchDevice ? (isPointer ? (isPointerIE10 ? 'MSPointerUp' : 'pointerup') : 'touchend') : 'mouseup' , enterEvent = isTouchDevice ? null : 'mouseenter' , leaveEvent = isTouchDevice ? null : 'mouseleave' , cancelEvent = isTouchDevice ? (isPointer ? (isPointerIE10 ? 'MSPointerCancel' : 'pointercancel') : 'touchcancel') : null; var cssEndTransition = 'transitionend webkitTransitionEnd oTransitionEnd msTransitionEnd'; var sliderMap = [] , isTouching = false , isSwiping = false , swipeThreshold = 35 , startX = 0 , startY = 0 , deltaX = 0 , deltaY = 0 , activeSlider; var body = document.body || document.documentElement, css = body.style; var isCSSAnimation = (css.transform !== undefined || css.WebkitTransform !== undefined || css.MozTransform !== undefined || css.MsTransform !== undefined || css.OTransform !== undefined) && (css.transition !== undefined || css.WebkitTransition !== undefined || css.MozTransition !== undefined || css.MsTransition !== undefined || css.OTransition !== undefined); /* common functions */ function getXY(evt, val) { var event = evt.originalEvent ? evt.originalEvent : evt; return isTouch && event.touches !== undefined && event.touches.length == 1 ? event.touches[0][val] : evt[val] !== undefined ? evt[val] : event[val] !== undefined ? event[val] : 0; } function getX(evt) { return getXY(evt, 'pageX'); } function getY(evt) { return getXY(evt, 'pageY'); } /* lib extension */ $.fn.extend({ 'setTransition': function(time) { if (isCSSAnimation == true) { var timing = time !== 0 ? 'cubic-bezier(0.39, 0.575, 0.565, 1)' : 'linear' , duration = time + 's' , property = time !== 0 ? 'all' : 'none'; this.css({ '-webkit-transition-property': property , '-moz-transition-property': property , '-ms-transition-property': property , '-o-transition-property': property , 'transition-property': property , '-webkit-transition-duration': duration , '-moz-transition-duration': duration , '-ms-transition-duration': duration , '-o-transition-duration': duration , 'transition-duration': duration , '-webkit-transition-timing-function': timing , '-moz-transition-timing-function': timing , '-ms-transition-timing-function': timing , '-o-transition-timing-function': timing , 'transition-timing-function': timing }); } return this; } , 'translateX': function(val, noanim) { var surfix = ''; if (val.toString().indexOf('px') == -1) { surfix = 'px'; } if (isCSSAnimation == true) { if (noanim !== undefined && noanim !== null && noanim === true) { this.setTransition(0); } this.css({ '-webkit-transform': 'translate3d(' + val + surfix + ', 0, 0)' , '-moz-transform': 'translateX(' + val + surfix + ')' , '-ms-transform': 'translateX(' + val + surfix + ')' , '-o-transform': 'translateX(' + val + surfix + ')' , 'transform': 'translateX(' + val + surfix + ')' }); } else { this.css({ 'margin-left': val }); } return this; } , 'animateX': function(val, time) { if (isCSSAnimation == true) { this .setTransition(time / 1000) .translateX(val); if (!this.hasClass('event-attached')) { this .addClass('event-attached') .on(cssEndTransition, function(evt) { var $this = $(evt.target); if ($this.hasClass('slider-slides')) { $this.getSlider().slideComplete(); $this.setTransition(0); } }); } } else { this .stop(true, true) .animate({ 'margin-left': val } , time , function() { $(this).getSlider().slideComplete(); }); } return this; } , 'animateFade': function(time) { if (isCSSAnimation == true) { this .setTransition(time / 1000) .css({ '-webkit-opacity': 1 , '-moz-opacity': 1 , '-ms-opacity': 1 , '-o-opacity': 1 , 'opacity': 1 }); if (!this.hasClass('event-attached')) { this .addClass('event-attached') .on(cssEndTransition, function(evt) { if (evt.originalEvent.propertyName.indexOf('opacity') != -1 && $(this).css('z-index') != 0) { $(this).getSlider().slideComplete(); } }); } } else { this .stop(true, true) .fadeTo(time , 1 , function() { $(this).getSlider().slideComplete(); }); } return this; } }); /* extend slider to DOM object */ $.fn.extend({ /* setup slider */ 'sliderInit': function(options) { /* do nothing if there is only one slide */ var total = this.children().length; if (total <= 1 || this.data('initialized') == true) { return; } if (!this.hasClass('jSlider')) { this.addClass('jSlider'); } /* SLIDER SETTINGS */ /* ------------------------------------------------------------------------------------------*/ var defaults = { 'navigation': 'hover' , 'indicator': 'always' , 'speed': 500 , 'delay': 5000 , 'transition': 'slide' , 'loop': false , 'group': 1 }; var html_data = { 'navigation': this.data('navigation') , 'indicator': this.data('indicator') , 'speed': this.data('speed') , 'delay': this.data('delay') , 'transition': this.data('transition') , 'loop': this.data('loop') , 'group': this.data('group') } /* extend settings */ var settings = $.extend({}, defaults, html_data, options); /* fixes */ if (isNaN(settings.speed) || settings.speed < 0) { settings.speed = defaults.speed; } if (isNaN(settings.delay) || settings.delay < 0) { settings.delay = defaults.delay; } if (settings.transition != 'slide' && settings.transition != 'fade') { settings.transition = defaults.transition; } if (settings.transition != 'slide') { settings.group = 1; } if (isTouchDevice) { if (settings.navigation == 'hover') { settings.navigation = 'none'; } if (settings.indicator == 'hover') { settings.indicator = 'none'; } } total = Math.ceil(total / settings.group); /* save settings */ this.data('settings', settings); /* GET THE START UP DATA */ /* ------------------------------------------------------------------------------------------*/ var current = 0 , selected = '> div.selected'; /* hash tag is in top priority */ if (window.location.hash != '') { selected = window.location.hash + ',' + selected } /* if found selected item, store the index & update class */ if (this.find(selected).length != 0) { current = Math.ceil(this.find(selected).index() / settings.group); /* update class */ this.find('> div.selected').removeClass('selected'); this.find('> div:eq(' + current + ')').addClass('selected'); } /* SETUP ANIMATION */ this.find('[class*=appear-]').each(function() { var $elem = $(this) , top = parseInt($elem.css('top'), 10) , left = parseInt($elem.css('left'), 10); $elem .data('top', top) .data('left', left); if ($elem.hasClass('appear-top')) { $elem.css('top', top - 15); } if ($elem.hasClass('appear-bottom')) { $elem.css('top', top + 15); } if ($elem.hasClass('appear-left')) { $elem.css('left', top - 15); } if ($elem.hasClass('appear-right')) { $elem.css('left', left + 15); } $elem.css('opacity', 0); if (isCSSAnimation) { $elem.addClass('cssAnimation'); } }); /* SETUP DATA */ /* ------------------------------------------------------------------------------------------*/ this.data('total', total) .data('current', current) .data('cancel-play', false) .data('map-index', sliderMap.length) .data('initialized', true) .wrapInner('
'); this.find('.slider-slides').setTransition(0); /* SAVE TO MAP */ sliderMap.push({ 'slider': this , 'sliderInterval': null , 'showInterval': null }); /* calculate group */ if (settings.group != 1) { this.find('.slider-slides > div').css('width', 100 / settings.group + '%'); } else { this.find('img:eq(0)').clone().prependTo(this); } /* FIX DOM */ if (isPointerIE10 || isPointer) { this.css({ '-ms-scroll-chaining': 'none' , '-ms-touch-action': 'pan-y pinch-zoom' , 'touch-action': 'pan-y pinch-zoom' }); } if (isTouch) { this.addClass('webkit-slider'); } if (settings.transition == 'fade' && (settings.navigation != 'none' || settings.indicator != 'none')) { this.addClass('fade-transition'); } else if (settings.navigation == 'none' && settings.indicator == 'none') { this.addClass('background-transition'); } /* BINDING EVENTS */ /* ------------------------------------------------------------------------------------------*/ if (settings.navigation != 'none' || settings.indicator != 'none') { this.find('.slider-content-wrapper').on(startEvent, function(evt) { var $slider = $(this).getSlider() , $slides = $slider.find('.slider-slides'); if (!isTouchDevice) { evt.preventDefault(); /* change cursor */ $slides.addClass('grabbing'); } $slides.setTransition(0); /* reset touch status */ isTouching = true; isSwiping = false; /* start capture first mouse / finger point position */ startX = getX(evt); startY = getY(evt); /* cancel autoplay */ $slider.sliderStop(); activeSlider = $slider; }).on(moveEvent, function(evt) { var $slider = $(this).getSlider() , $slides = $slider.find('.slider-slides') , settings = $slider.data('settings') , current = $slider.data('current') , w = $slider.width(); /* on desktop, keep firing mouse move event if not drag */ if (isTouching != true) { return; } /* if on desktop, cancel other events */ if (!isTouchDevice) { evt.preventDefault(); } /* capture new mouse / finger point position */ deltaX = getX(evt) - startX; deltaY = getY(evt) - startY; /* on mobile, the vertical swipe distance is bigger, assume this is page scroll */ if (Math.abs(deltaY) > Math.abs(deltaX)) { if (isTouchDevice) { $slider.sliderCancelTouch(); } return; } /* if this is swipe & drag, set swipe on and recalculate the slider-slides */ isSwiping = true; evt.preventDefault(); if (settings.transition == 'slide') { $slides.translateX(- current * w + deltaX, true); } }).on(stopEvent + ' ' + cancelEvent, function(evt) { var $slider = $(this).getSlider() , $slides = $slider.find('.slider-slides') , settings =$slider.data('settings') , current = $slider.data('current') , w = $slider.width() , dir = 1; /* change cursor */ $slides.removeClass('grabbing'); /* finish the touch swipe by moving to the next / previous slider */ if (Math.abs(deltaX) > swipeThreshold) { if (deltaX > 0) { dir = -1; } else { dir = 1; } $slider.sliderGo(dir); } else if (settings.transition == 'slide') { /* if not wipe enough, stay at the current slider */ $slider.sliderUpdate(current); } /* restore default values */ $slider.sliderCancelTouch(); activeSlider = null; }); $(document).on({ 'mouseup': function(evt) { if (activeSlider != null) { activeSlider.find('.slider-content-wrapper').trigger(stopEvent); } } }); /* SHOW NAV / INDICATOR */ /* ------------------------------------------------------------------------------------------*/ if (enterEvent != null && leaveEvent != null) { this.on(enterEvent, function() { var $slider = $(this) , settings = $slider.data('settings'); if (settings.navigation == 'hover') { $slider.find('.navigator').fadeIn(); } if (settings.indicator == 'hover') { $slider.find('.indicator').fadeIn(); } }).on(leaveEvent, function() { var $slider = $(this) , settings = $slider.data('settings'); if (settings.navigation == 'hover') { $slider.find('.navigator').fadeOut(); } if (settings.indicator == 'hover') { $slider.find('.indicator').fadeOut(); } }); } } /* ADD CONTROLLER */ /* ------------------------------------------------------------------------------------------*/ var controller = $('
', { 'class': 'controller' , 'html': '' + '
' }).appendTo(this); if (navigator.userAgent.toLowerCase().indexOf('msie 8') != -1) { controller.addClass('msie8'); } /* navigator */ var nav = this.find('.navigator') , ind = this.find('.indicator'); if (settings.navigation == 'always') { nav.show(); } this .find('.navigator span') .on('click', function(evt) { evt.preventDefault(); $(this).getSlider() .sliderStop() .sliderGo($(this).data('direction')); }); /* indicator */ if (settings.indicator == 'always') { ind.show(); } for (var i = 0; i < total; i++) { $('', { 'class': (i == current ? 'selected' : '') , 'text': i , 'data-slide': i }) .appendTo(controller.find('.indicator')) .on('click', function(evt) { evt.preventDefault(); var $this = $(this) , slider = $this.getSlider() , current = slider.data('current') , next = $this.data('slide'); if (next < 0 || next >= slider.data('total')) { next = current; } slider .sliderStop() .sliderOptimize(current, next) .sliderUpdate(next); }); } /* UPDATE SIZE & SELECTED INDEX */ /* ------------------------------------------------------------------------------------------*/ /* fire event for addition plugins */ this.trigger({ 'type': 'slideCreated' }); this .sliderResized() .sliderUpdate(current) .sliderOptimize() .sliderPlay(); return this; } , 'sliderPlay': function() { var current = this.data('current') , index = this.data('map-index') , settings = this.data('settings') , total = this.data('total') , stop = this.data('cancel-play') , isLoaded = this.data('imageLoaded') == this.data('totalImages'); if (current >= total - 1) { this.sliderStop(); return; } if (stop == true || settings.delay == 0) { return; } var $slider = this; sliderMap[index]['sliderInterval'] = setInterval(function() { var stop = $slider.data('cancel-play'); if (stop == true) { clearInterval(sliderMap[index]['sliderInterval']); return; } if (isLoaded) { $slider.sliderGo(1); } }, settings.delay); } , 'sliderStop': function() { var index = this.data('map-index'); clearInterval(sliderMap[index]['sliderInterval']); if (this.data('cancel-play') == true) { return this; } return this.data('cancel-play', true).trigger('slideCancelAutoPlay'); } , 'slideComplete': function() { /* fire event for addition plugins */ return this.sliderOptimize().trigger({ 'type': 'slideComplete' , 'current': this.data('current') }); } , 'sliderOptimize': function(prev, next) { var settings = this.data('settings') , current = this.data('current') , p1 = prev !== undefined ? prev : current , p2 = next !== undefined ? next : current , $elems = this.find('.slider-slides > div'); if (settings.transition == 'slide') { return this.sliderShowItems(); } /* hide un-use slide */ for (var i = 0; i < $elems.length; i++) { if (p2 != i) { $elems.eq(i).css({ '-webkit-transition-duration': 0 , '-moz-transition-duration': 0 , '-ms-transition-duration': 0 , '-o-transition-duration': 0 , 'transition-duration': 0 , '-webkit-opacity': 0 , '-moz-opacity': 0 , '-ms-opacity': 0 , '-o-opacity': 0 , 'opacity': 0 , 'z-index': 0 }); } } return this.sliderShowItems(); } , 'sliderCancelTouch': function() { /* restore default values */ startX = 0; startY = 0; deltaX = 0; deltaY = 0; isTouching = false; isSwiping = false; return this; } /* update slider dimension */ , 'sliderResized': function() { var i , settings = this.data('settings') , total = this.data('total') , current = this.data('current') , w = this.width() , $elems = this.find('.slider-slides > div'); /* update elements */ for (i = 0; i < $elems.length; i++) { if (settings.transition == 'slide') { $elems.eq(i).css('left', w * i / settings.group); } else if (settings.transition == 'fade') { $elems.eq(i).css('z-index', total - i); if (i == current) { $elems.eq(i).css('z-index', total); } } } /* update container & slider-slides */ if (settings.transition == 'slide') { this.find('.slider-slides') .translateX(- current * w, true); } /* re-chain */ return this; } , 'sliderGo': function(direction) { var settings = this.data('settings') , current = this.data('current') , total = this.data('total'); var next = current + direction; if (next < 0 || next >= total) { if (settings.loop == false) { next = current; } else { if (next < 0) { next = total - 1; } else { next = 0; } } } return this .sliderOptimize(current, next) .sliderUpdate(next); } , 'sliderUpdate': function(current) { if (this.data('current') != current) { /* fire event for addition plugins */ this.trigger({ 'type': 'slideStart' }); } var w = this.width() , settings = this.data('settings'); /* move sliders */ this.data('current', current); if (settings.transition == 'slide') { this .find('.slider-slides') .animateX(- current * w, settings.speed); } else if (settings.transition == 'fade') { this .find('.slider-slides > div:eq(' + current + ')') .css('z-index', this.data('total')) .animateFade(settings.speed); } /* update navigator */ this.find('.navigator span').removeClass('disabled'); if (settings.loop == false) { if (current == 0) { this.find('.navigator .prev').addClass('disabled'); } else if (current == this.data('total') - 1) { this.find('.navigator .next').addClass('disabled'); } } /* update indicator */ this.find('.indicator span.selected').removeClass('selected'); this.find('.indicator span:eq(' + current + ')').addClass('selected'); /* re-chain */ return this; } , 'sliderShowItems': function() { var $slider = this , current = $slider.data('current') , index = $slider.data('map-index') , $elems = $slider.find('.slider-slides > div:eq(' + current + ') [class*=appear-]') , showIndex = 0; $slider.sliderHideItems(); clearInterval(sliderMap[index]['showInterval']); if ($elems.length <= 0) { return $slider; } sliderMap[index]['showInterval'] = setInterval(function() { if (showIndex >= $elems.length) { clearInterval(sliderMap[index]['showInterval']); return $slider; } var $item = $elems.eq(showIndex); if (isCSSAnimation) { $item.css({ 'top': $item.data('top') , 'left': $item.data('left') , 'opacity': 1 }); } else { $item.stop(true, true).animate({ 'top': $item.data('top') , 'left': $item.data('left') , 'opacity': 1 }, 500); } showIndex++; }, 200); return $slider; } , 'sliderHideItems': function() { var current = this.data('current') , index = this.data('map-index'); clearInterval(sliderMap[index]['showInterval']); this.find('.slider-slides > div:not(:eq(' + current + ')) [class*=appear-]').each(function() { var $elem = $(this) , top = $elem.data('top') , left = $elem.data('left'); if ($elem.hasClass('appear-top')) { $elem.css('top', top - 15); } if ($elem.hasClass('appear-bottom')) { $elem.css('top', top + 15); } if ($elem.hasClass('appear-left')) { $elem.css('left', top - 15); } if ($elem.hasClass('appear-right')) { $elem.css('left', left + 15); } $elem.css('opacity', 0); }); return this; } , 'getSlider': function() { if (this.hasClass('jSlider')) { return this; } return this.parents('.jSlider'); } }); /* startup functions */ $(document).ready(function(evt) { $('body .jSlider').each(function() { $(this).sliderInit(); }); }); $(window).resize(function(evt) { $('body .jSlider').each(function() { $(this).sliderResized(); }); }); });