/* jshint browser: true, jquery: true, devel: true */
/* global window, jQuery */
(function($, window, undefined) {
'use strict';
function throttle(func, delay) {
var timer = null;
return function() {
var context = this,
args = arguments;
if ( timer === null ) {
timer = setTimeout(function() {
func.apply(context, args);
timer = null;
}, delay);
}
};
}
// Check for browser CSS support and cache the result for subsequent calls.
var checkStyleSupport = (function() {
var support = {};
return function(prop) {
if ( support[prop] !== undefined ) { return support[prop]; }
var div = document.createElement('div'),
style = div.style,
ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
prefixes = ["webkit", "moz", "ms", "o"],
props = (prop + ' ' + (prefixes).join(ucProp + ' ') + ucProp).split(' ');
for (var i in props) {
if ( props[i] in style ) { return support[prop] = props[i]; }
}
return support[prop] = false;
};
}());
var svgNS = 'http://www.w3.org/2000/svg',
svgSupport = (function() {
var support;
return function() {
if ( support !== undefined ) { return support; }
var div = document.createElement('div');
div.innerHTML = '';
support = ( div.firstChild && div.firstChild.namespaceURI === svgNS );
return support;
};
}());
var $window = $(window),
transformSupport = checkStyleSupport('transform'),
defaults = {
itemContainer: 'ul',
// [string|object]
// Selector for the container of the flippin' items.
itemSelector: 'li',
// [string|object]
// Selector for children of `itemContainer` to flip
start: 'center',
// ['center'|number]
// Zero based index of the starting item, or use 'center' to start in the middle
fadeIn: 400,
// [milliseconds]
// Speed of the fade in animation after items have been setup
loop: false,
// [true|false|number]
// Loop around when the start or end is reached
// If number, this is the number of items that will be shown when the beginning or end is reached
autoplay: false,
// [false|milliseconds]
// If a positive number, Flipster will automatically advance to next item after that number of milliseconds
pauseOnHover: true,
// [true|false]
// If true, autoplay advancement will pause when Flipster is hovered
style: 'coverflow',
// [coverflow|carousel|flat|...]
// Adds a class (e.g. flipster--coverflow) to the flipster element to switch between display styles
// Create your own theme in CSS and use this setting to have Flipster add the custom class
spacing: -0.6,
// [number]
// Space between items relative to each item's width. 0 for no spacing, negative values to overlap
click: true,
// [true|false]
// Clicking an item switches to that item
keyboard: true,
// [true|false]
// Enable left/right arrow navigation
scrollwheel: true,
// [true|false]
// Enable mousewheel/trackpad navigation; up/left = previous, down/right = next
touch: true,
// [true|false]
// Enable swipe navigation for touch devices
nav: false,
// [true|false|'before'|'after']
// If not false, Flipster will build an unordered list of the items
// Values true or 'before' will insert the navigation before the items, 'after' will append the navigation after the items
buttons: false,
// [true|false|'custom']
// If true, Flipster will insert Previous / Next buttons with SVG arrows
// If 'custom', Flipster will not insert the arrows and will instead use the values of `buttonPrev` and `buttonNext`
buttonPrev: 'Previous',
// [text|html]
// Changes the text for the Previous button
buttonNext: 'Next',
// [text|html]
// Changes the text for the Next button
onItemSwitch: false
// [function]
// Callback function when items are switched
// Arguments received: [currentItem, previousItem]
},
classes = {
main: 'flipster',
active: 'flipster--active',
container: 'flipster__container',
nav: 'flipster__nav',
navChild: 'flipster__nav__child',
navItem: 'flipster__nav__item',
navLink: 'flipster__nav__link',
navCurrent: 'flipster__nav__item--current',
navCategory: 'flipster__nav__item--category',
navCategoryLink: 'flipster__nav__link--category',
button: 'flipster__button',
buttonPrev: 'flipster__button--prev',
buttonNext: 'flipster__button--next',
item: 'flipster__item',
itemCurrent: 'flipster__item--current',
itemPast: 'flipster__item--past',
itemFuture: 'flipster__item--future',
itemContent: 'flipster__item__content'
},
classRemover = new RegExp('\\b(' + classes.itemCurrent + '|' + classes.itemPast + '|' + classes.itemFuture + ')(.*?)(\\s|$)', 'g'),
whiteSpaceRemover = new RegExp('\\s\\s+', 'g');
$.fn.flipster = function(options) {
var isMethodCall = (typeof options === 'string' ? true : false);
if ( isMethodCall ) {
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function() {
var methods = $(this).data('methods');
if ( methods[options] ) {
return methods[options].apply(this, args);
} else {
return this;
}
});
}
var settings = $.extend({}, defaults, options);
return this.each(function() {
var self = $(this),
methods,
_container,
_containerWidth,
_items,
_itemOffsets = [],
_currentItem,
_currentIndex = 0,
_nav,
_navItems,
_navLinks,
_playing = false,
_startDrag = false,
_isItemClicked = false;
function buildButtonContent(dir) {
var text = ( dir === 'next' ? settings.buttonNext : settings.buttonPrev );
if ( settings.buttons === 'custom' || !svgSupport ) { return text; }
return '';
}
function buildButton(dir) {
dir = dir || 'next';
return $('')
.html(buildButtonContent(dir))
.on('click', function(e) {
jump(dir);
e.preventDefault();
});
}
function buildButtons() {
if ( settings.buttons && _items.length > 1 ) {
self.find('.' + classes.button).remove();
self.append(buildButton('prev'), buildButton('next'));
}
}
function buildNav() {
var navCategories = {};
if ( !settings.nav || _items.length <= 1 ) { return; }
if ( _nav ) { _nav.remove(); }
_nav = $('
');
_navLinks = $('');
_items.each(function(i) {
var item = $(this),
category = item.data('flip-category'),
itemTitle = item.data('flip-title') || item.attr('title') || i,
navLink = $('' + itemTitle + '')
.data('index', i);
_navLinks = _navLinks.add(navLink);
if ( category ) {
if ( !navCategories[category] ) {
var categoryItem = $('