dist/plugin/carousel.js

File

			(function(global, undefined) { var kafe = global.kafe, $ = kafe.dependencies.jQuery; kafe.bonify({name:'plugin.carousel', version:'1.0.2', obj:(function(){
			
				var
					// refresh active/inactive controls, and statuses
					refresh = function(self) {
						var
							__ = self.__,
							none = function(e) { e.preventDefault(); }
						;
			
						if (!__.wrap) {
			
							// précédent
							if (__.curr === 0) {
								__.$start
									.addClass('kafecarousel-inactive')
									.off('click', __.startClick)
									.on('click',  none)
								;
								__.$previous
									.addClass('kafecarousel-inactive')
									.off('click', __.previousClick)
									.on('click',  none)
								;
							} else {
								__.$start
									.removeClass('kafecarousel-inactive')
									.off('click', __.startClick)
									.on('click',  __.startClick)
								;
								__.$previous
									.removeClass('kafecarousel-inactive')
									.off('click', __.previousClick)
									.on('click',  __.previousClick)
								;
							}
			
							// next
							if (__.curr == (__.total-1)) {
								__.$next
									.addClass('kafecarousel-inactive')
									.off('click', __.nextClick)
									.on('click',  none)
								;
								__.$end
									.addClass('kafecarousel-inactive')
									.off('click', __.endClick)
									.on('click',  none)
								;
							} else {
								__.$next
									.removeClass('kafecarousel-inactive')
									.off('click', __.nextClick)
									.on('click',  __.nextClick)
								;
								__.$end
									.removeClass('kafecarousel-inactive')
									.off('click', __.endClick)
									.on('click',  __.endClick)
								;
							}
						}
			
			
						// position
						__.$position.html(__.curr+1);
			
						// status
						__.$status.html('');
						__.$statusNum.html('');
						for (var i=0; i<__.total; ++i) {
							if (i == __.curr) {
								__.$status.append('<span class="kafecarousel-highlight">'+__.statusBullet+'</span>');
								__.$statusNum.append('<span class="kafecarousel-highlight">'+(i+1)+'</span>');
							} else {
								if(!!__.statusLink) {
									__.$status.append(
										$('<a>')
											.attr('href','#')
											.attr('data-kafecarousel-target', i+1)
											.on('click',__.itemSimpleClick)
											.html('<span>'+__.statusBullet+'</span>')
									);
									__.$statusNum.append(
										$('<a>')
											.attr('href','#')
											.attr('data-kafecarousel-target', i+1)
											.on('click',__.itemSimpleClick)
											.html('<span>'+(i+1)+'</span>')
									);
								} else {
									__.$status.append(__.statusBullet);
									__.$statusNum.append(i+1);
								}
							}
						}
			
						// items highlight
						__.$itemsimple.removeClass('kafecarousel-highlight')
							.filter('[data-kafecarousel-target="'+(__.curr+1)+'"]').addClass('kafecarousel-highlight')
						;
			
						__.$items.each(function() {
							$(this).children().removeClass('kafecarousel-highlight')
								.eq(__.curr).addClass('kafecarousel-highlight')
							;
						});
					},
			
			
					// change the slide
					change = function(self, target) {
						var __ = self.__;
			
						if (!!__.changing) {
							return false;
						}
						if (target == __.curr) {
							return false;
						}
						__.changing = true;
						__.slideStopAuto();
			
						var callbackData = {
							action: (Number(target) == target) ? 'item' : target,
							source: {
								position: __.curr+1
							},
							target: {}
						};
			
						var way;
			
						var postCallback = function() {
							if (!!__.postSwitchCallback) {
								__.postSwitchCallback(callbackData);
							}
						};
			
						// current li
						var $liCurr = __.$slides.eq(__.curr);
			
						// prev/next
						if (target == 'prev' || target == 'next') {
			
							way = (target == 'prev') ? -1 : 1;
			
							__.curr =
								(__.wrap) ?
									(__.curr === 0 && way == -1) ?
										(__.total-1)
										: ((__.curr + way) % __.total)
									: (__.curr + way)
							;
			
						// item
						} else {
							target = Number(target);
			
							way = (target < __.curr) ? -1 : 1;
							__.curr = target;
						}
			
						// new li
						var $liNew = __.$slides.eq(__.curr);
			
			
						// add callback data
						callbackData.source.obj      = $liCurr.get(0);
						callbackData.target.position = __.curr+1;
						callbackData.target.obj      = $liNew.get(0);
			
						if (!!__.preSwitchCallback) {
							__.preSwitchCallback(callbackData);
						}
			
			
			
						// transitions
						switch (__.transition) {
			
							// fade
							case 'fade':
								$liCurr.css('z-index',1);
			
								$liNew
									.css('z-index',2)
									.fadeIn(__.speed, function(){
										$liCurr.hide();
										__.changing = false;
										postCallback();
									})
								;
							break;
			
			
							// move right-bottom > top-left
							/*
							case 'slideTopLeft': 
								var height = __.$container.height() + 'px';
								var width = __.$container.width() + 'px';
			
								$liCurr.animate({
									top:  (way == 1) ? '-'+height : height,
									left: (way == 1) ? '-'+width  : width
								});
			
								$liNew
									.css('top',  (way == 1) ? height : '-'+height)
									.css('left', (way == 1) ? width  : '-'+width)
									.animate({
										top:  '0px',
										left: '0px'
									}, postCallback)
								;
							break;
							*/
			
							// slide horizontal
							case 'slideUp':
							case 'slideDown':
								way = (__.transition == 'slideDown') ? -way : way;
			
								var height = __.$container.height() + 'px';
			
								$liCurr.animate(
									{ top: (way == 1) ? '-'+height : height},
									__.speed,
									function() { $(this).hide(); __.changing = false; }
								);
			
								$liNew
									.css({
										top:     (way == 1) ? height : '-'+height,
										display: 'block'
									})
									.animate({
										top: '0px'
									}, __.speed, postCallback)
								;
							break;
			
							// slide vertical
							//case 'slideLeft':
							//case 'slideRight':
							default:
								way = (__.transition == 'slideRight') ? -way : way;
			
								var width = __.$container.width() + 'px';
			
								$liCurr.animate(
									{ left: (way == 1) ? '-'+width : width },
									__.speed,
									function() { $(this).hide(); __.changing = false; }
								);
			
								$liNew
									.css({
										left:     (way == 1) ? width : '-'+width,
										display: 'block'
									})
									.animate({
										left: '0px'
									}, __.speed, postCallback)
								;
							break;
						}
			
						refresh(self);
						// TODO wrap:false autostart bug
						__.slideStartAuto();
					}
				;
			
			
			
			
				/**
				* ### Version 1.0.2
				* Carousel, image scroller, ticker, whatever you wanna call it...
				*
				* @module kafe.plugin
				* @class kafe.plugin.carousel
				*/
				var carousel = kafe.fn.createInstantiableObject();
			
				/**
				* Attach behaviors to the carousel structure.
				*
				* @method __constructor
				* @param {Object} options Initial configurations
				*	@param {Object} options.selector The carousel elements
				*		@param {String|jQueryObject|DOMElement} options.selector.container The carousel container.
				*		@param {String|jQueryObject|DOMElement} [options.selector.slides] The carousel slides.
				*		@param {String|jQueryObject|DOMElement} [options.selector.start] Clickable elements that will switch the carousel to the first slide.
				*		@param {String|jQueryObject|DOMElement} [options.selector.prev] Clickable elements that will switch the carousel to the previous slide.
				*		@param {String|jQueryObject|DOMElement} [options.selector.next] Clickable elements that will switch the carousel to the next slide.
				*		@param {String|jQueryObject|DOMElement} [options.selector.end] Clickable elements that will switch the carousel to the last slide.
				*		@param {String|jQueryObject|DOMElement} [options.selector.items] Clickable parent container of elements that will switch the carousel to a specific slide, assumes the children are in slide order.
				*		@param {String|jQueryObject|DOMElement} [options.selector.item] Clickable elements that will switch the carousel to a specific slide via the `data-kafecarousel-target` attribute.
				*		@param {String|jQueryObject|DOMElement} [options.selector.play] Clickable elements that will switch the carousel to autoplay.
				*		@param {String|jQueryObject|DOMElement} [options.selector.pause] Clickable elements that will stop the autoplay of the carousel.
				*		@param {String|jQueryObject|DOMElement} [options.selector.position] Elements that will contain the current position.
				*		@param {String|jQueryObject|DOMElement} [options.selector.total] Elements that will contain the total number of slides.
				*		@param {String|jQueryObject|DOMElement} [options.selector.status] Elements that will contain a list of bullets indicating the status of the carousel.
				*		@param {String|jQueryObject|DOMElement} [options.selector.statusNum] Elements that will contain a list of numbers indicating the status of the carousel.
				*	@param {Boolean} [options.wrap=true] If true, will loop back to the first slide upon reaching the last one. The same is enabled in reverse.
				*	@param {String} [options.transition='slideLeft'] Animation used during a transition. Possible values are `slideLeft`, `slideRight`, `slideUp`, `slideDown` and `fade`.
				*	@param {Number} [options.speed=500] Duration (in milliseconds) of the transition.
				*	@param {Number} [options.startId=1] Index of the starting slide, starting at 1.
				*	@param {Object} [options.autostart] Allows slides to change without a user interaction after a chosen delay.
				*		@param {Number} [options.autostart.interval=3000] Delay (in milliseconds) before starting a transition to the next slide. The transition duration is included in the delay. As an example, an `interval` of 3000 combined with a `speed` of 500 will hold a slide still for 2500 milliseconds before starting the transition.
				*	@param {Function} [options.preSwitchCallback] Trigged upon receiving an instruction to change the current slide but before starting the transition. The following object is passed as a first argument:
				*		@param {Object} options.preSwitchCallback.data An object containing information relative to the transition in progress.
				*			@param {String} options.preSwitchCallback.data.action Current action being performed. Possible values are `prev`, `next` or `item` when using a specific index.
				*			@param {Object} options.preSwitchCallback.data.source Information about the slide being changed.
				*				@param {Number} options.preSwitchCallback.data.source.position Index of the source slide.
				*				@param {DOMElement} options.preSwitchCallback.data.source.obj Reference to the source slide.
				*			@param {Object} options.preSwitchCallback.data.target Information about the destination slide.
				*				@param {Number} options.preSwitchCallback.data.target.position Index of the target slide.
				*				@param {DOMElement} options.preSwitchCallback.data.target.obj Reference to the target slide.
				*	@param {Function} [options.postSwitchCallback] Trigged upon receiving an instruction to change the current slide but before starting the transition. Passes the same argument object as the `preSwitchCallback`.
				*	@param {Boolean} [options.statusLink=false] If true, will generate navigation links in elements linked to the carousel via `data-kafecarousel-id` and the `data-kafecarousel-action="status"` attribute.
				*	@param {String} [options.statusBullet='&bull;'] Text used as the content of generated link in a `statusLink` navigation.
				*	@param {Boolean} [options.pauseOnHover=true] If true, autoswitch will be paused while the mouse hovers a slide.
				*
				* @example
				*	// Sample carousel structure
				*	<section class="home-carousel">
				*		<ul class="home-slides">
				*			<li><a href="#"><img src="/images/slide-01.jpg" /></a></li>
				*			<li><a href="#"><img src="/images/slide-01.jpg" /></a></li>
				*			<li><a href="#"><img src="/images/slide-01.jpg" /></a></li>
				*		</ul>
				*		<span class="home-prev">Back</span>
				*		<span class="home-next">Next</span>
				*		<div class="home-status"></div>
				*	</section>
				*	
				* @example
				*	// Attach behaviors using...
				*	var myCarousel = kafe.plugin.carousel({ selector: { container: '.home-slides' } });
				* @example
				*	// Carousels can be remotely interacted with using custom data attributes...
				*	var myCarousel = kafe.plugin.carousel({ selector: { container: '.home-slides' } });
				* @example
				*	// The jQuery alternative...
				*	$('.home-slides').kafeCarousel('init', {});
				*/
				carousel.prototype.__constructor = function(options) {
					var self = this, __ = self.__;
			
					// elements
					__.$container  = $(options.selector.container).data('kafecarousel-self', self);
					__.$slides     = (options.selector.slides) ? $(options.selector.slides) : __.$container.children();
					__.$start      = $(options.selector.start);
					__.$previous   = $(options.selector.prev);
					__.$next       = $(options.selector.next);
					__.$end        = $(options.selector.end);
					__.$items      = $(options.selector.items);
					__.$itemsimple = $(options.selector.item);
					__.$play       = $(options.selector.play);
					__.$pause      = $(options.selector.pause);
					__.$position   = $(options.selector.position);
					__.$total      = $(options.selector.total);
					__.$status     = $(options.selector.status);
					__.$statusNum  = $(options.selector.statusNum);
			
					__.wrap         = (options.wrap === false)  ? false                   : true;
					__.transition   = (options.transition)      ? options.transition      : 'slideLeft';
					__.speed        = (Number(options.speed))   ? Number(options.speed)   : 500;
					__.startId      = (Number(options.startId)) ? Number(options.startId) : 1;
					__.autointerval = (
						(options.autostart) ? (
							(Number(options.autostart.interval)) ?
								Number(options.autostart.interval)
								: 3000)
							: undefined
					);
					__.preSwitchCallback    = (typeof(options.preSwitchCallback)    == 'function') ? options.preSwitchCallback    : undefined;
					__.postSwitchCallback   = (typeof(options.postSwitchCallback)   == 'function') ? options.postSwitchCallback   : undefined;
					__.initCompleteCallback = (typeof(options.initCompleteCallback) == 'function') ? options.initCompleteCallback : undefined;
					__.statusLink           = !!options.statusLink;
					__.statusBullet         = (options.statusBullet) ? options.statusBullet : '&bull';
					__.pauseOnHover         = (options.pauseOnHover === false) ? false : true;
			
			
					// cache
					__.$slidesFirst = __.$slides.eq(0);
					__.total        = __.$slides.length;
			
			
					// désactiver tout si un seul item
					if (__.total == 1) {
						__.$previous.addClass('kafecarousel-none');
						__.$next.addClass('kafecarousel-none');
						__.$items.addClass('kafecarousel-none');
						__.$itemsimple.addClass('kafecarousel-none');
						__.$position.addClass('kafecarousel-none');
						__.$total.addClass('kafecarousel-none');
						__.$status.addClass('kafecarousel-none');
						__.$statusNum.addClass('kafecarousel-none');
			
					// sinon préparer carousel
					} else {
			
						// initial
						__.curr     = __.startId-1;
						__.changing = false;
			
						// general events				
						__.startClick = function(e) {
							e.preventDefault();
							change(self, 0);
						};
			
						__.previousClick = function(e) {
							e.preventDefault();
							change(self, 'prev');
						};
			
						__.nextClick = function(e) {
							e.preventDefault();
							change(self, 'next');
						};
			
						__.endClick = function(e) {
							e.preventDefault();
							change(self, __.total-1);
						};
			
						__.itemSimpleClick = function(e) {
							e.preventDefault();
							change(self, $(this).data('kafecarousel-target') - 1);
						};
			
						__.playClick = function(e) {
							e.preventDefault();
							__.AutoRunning = true;
							__.slideStartAuto();
						};
			
						__.pauseClick = function(e) {
							e.preventDefault();
							__.AutoRunning = false;
							__.slideStopAuto();
						};
			
						__.slideStartAuto = function() {
							if (__.AutoRunning) {
								__.Timeout = setTimeout(function(){ change(self, 'next', true); }, __.autointerval);
							}
						};
			
						__.slideStopAuto = function() {
							clearTimeout(__.Timeout);
							__.Timeout = undefined;
						};
			
			
			
			
						// on events
						__.$start.on('click',__.startClick);
						__.$previous.on('click',__.previousClick);
						__.$next.on('click',__.nextClick);
						__.$end.on('click',__.endClick);
						__.$itemsimple.on('click',__.itemSimpleClick);
			
						__.$items.each(function() {
							$(this).children().each(function(i) {
								$(this).on('click',function(e){
									e.preventDefault();
									change(self, i);
								});
							});
						});
			
						__.$play.on('click',__.playClick);
						__.$pause.on('click',__.pauseClick);
			
						if (__.pauseOnHover) {
							__.$slides.on({
								mouseenter: __.slideStopAuto,
								mouseleave: __.slideStartAuto
							});
						}
			
			
			
			
			
						// intialiser look
						__.$total.html(__.total);
						refresh(self);
			
						__.$slides.hide()
							.eq(__.startId-1).show()
						;
			
						switch (__.transition) {
							// fade
							case 'fade':
							break;
			
			
							// move vertical
							case 'slideUp':
							case 'slideDown':
								__.$slides.css({
									left: '0px'
								});
								__.$slidesFirst.css('top','0px');
							break;
			
							// move horizontal
							//case 'slideLeft':
							//case 'slideRight':
							default:
								__.$slides.css({
									top: '0px'
								});
								__.$slidesFirst.css('left','0px');
							break;
						}
			
			
						// autostart	
						if (__.autointerval !== undefined) {
							__.AutoRunning = true;
							__.slideStartAuto();
						}
					}
			
					// Init. Completed callback
					if (!!__.initCompleteCallback) {
						__.initCompleteCallback(self);
					}
				};
			
			
				/**
				* Manually call a slide change
				*
				* @method change
				* @param {String|Number} target Action or 1-based slide position
				*
				* @example
				*	// Go to next slide
				*	myCarousel.change('next');
				* @example
				*	// Go to first slide 
				*	myCarousel.change(1);
				* @example
				*	// The jQuery alternative...
				*	$('#home-slides').kafeCarousel('change', 1);
				*/
				carousel.prototype.change = function(target) {
					var self = this, __ = self.__;
					return change(self, (Number(target) == target) ? target-1 : target);
				};
			
			
			
				// Add as jQuery plugin
				kafe.fn.plugIntojQuery('Carousel', {
					init: function(obj, parameters) {
						carousel($.extend(true, {}, parameters[0], {selector:{container:obj}}));
					},
					change: function(obj, parameters) {
						$(obj).data('kafecarousel-self').change(parameters[0]);
					}
				});
			
				return carousel;
			
			})()}); })(typeof window !== 'undefined' ? window : this);