/* global window, document, jquery */
(function($) {
$.fn.flipster = function(options) {
var ismethodcall = typeof options === 'string' ? true : false;
if (ismethodcall) {
var method = options;
var args = array.prototype.slice.call(arguments, 1);
} else {
var defaults = {
itemcontainer: 'ul', // container for the flippin' items.
itemselector: 'li', // selector for children of itemcontainer to flip
style: 'coverflow', // switch between 'coverflow' or 'carousel' display styles
start: 'center', // starting item. set to 0 to start at the first, 'center' to start in the middle or the index of the item you want to start with.
enablekeyboard: true, // enable left/right arrow navigation
enablemousewheel: true, // enable scrollwheel navigation (up = left, down = right)
enabletouch: true, // enable swipe navigation for touch devices
onitemswitch: $.noop, // callback function when items are switched
disablerotation: false,
enablenav: false, // if true, flipster will insert an unordered list of the slides
navposition: 'before', // [before|after] changes the position of the navigation before or after the flipsterified items - case-insensitive
enablenavbuttons: false, // if true, flipster will insert previous / next buttons
prevtext: 'previous', // changes the text for the previous button
nexttext: 'next' // changes the text for the next button
};
var settings = $.extend({}, defaults, options);
var win = $(window);
}
return this.each(function(){
var _flipster = $(this);
var methods;
if (ismethodcall) {
methods = _flipster.data('methods');
return methods[method].apply(this, args);
}
var _flipitemsouter;
var _flipitems;
var _flipnav;
var _flipnavitems;
var _current = 0;
var _starttouchx = 0;
var _actionthrottle = 0;
var _throttletimeout;
var compatibility;
// public methods
methods = {
jump: jump
};
_flipster.data('methods', methods);
function removethrottle() {
_actionthrottle = 0;
}
function resize() {
_flipitemsouter.height(calculatebiggestflipitemheight());
_flipster.css("height","auto");
if ( settings.style === 'carousel' ) { _flipitemsouter.width(_flipitems.width()); }
}
function calculatebiggestflipitemheight() {
var biggestheight = 0;
_flipitems.each(function() {
if ($(this).height() > biggestheight) biggestheight = $(this).height();
});
return biggestheight;
}
function buildnav() {
if ( settings.enablenav && _flipitems.length > 1 ) {
var navcategories = [],
navitems = [],
navlist = [];
_flipitems.each(function(){
var category = $(this).data("flip-category"),
itemid = $(this).attr("id"),
itemtitle = $(this).attr("title");
if ( typeof category !== 'undefined' ) {
if ( $.inarray(category,navcategories) < 0 ) {
navcategories.push(category);
navlist[category] = '
'+category+'\n\n';
}
}
if ( $.inarray(itemid,navitems) < 0 ) {
navitems.push(itemid);
var link = ''+itemtitle+'
\n';
if ( typeof category !== 'undefined' ) {
navlist[category] = navlist[category] + '' + link;
}
else {
navlist[itemid] = '' + link;
}
}
});
var navdisplay = '\n';
for (var catindex in navcategories) {
navlist[navcategories[catindex]] = navlist[navcategories[catindex]] + "
\n\n";
}
for (var navindex in navlist) {
navdisplay += navlist[navindex];
}
navdisplay += '';
if(settings.navposition.tolowercase() != "after") {
_flipnav = $(navdisplay).prependto(_flipster);
} else {
_flipnav = $(navdisplay).appendto(_flipster);
}
_flipnavitems = _flipnav.find("a").on("click",function(e){
var target;
if ( $(this).hasclass("flip-nav-category-link") ) {
target = _flipitems.filter("[data-flip-category='"+$(this).data("flip-category")+"']");
} else {
target = $(this.hash);
}
if ( target.length ) {
jump(target);
e.preventdefault();
}
});
}
}
function updatenav() {
if ( settings.enablenav && _flipitems.length > 1 ) {
var currentitem = $(_flipitems[_current]);
_flipnav.find(".flip-nav-current").removeclass("flip-nav-current");
_flipnavitems.filter("[href='#"+currentitem.attr("id")+"']").addclass("flip-nav-current");
_flipnavitems.filter("[data-flip-category='"+currentitem.data("flip-category")+"']").parent().addclass("flip-nav-current");
}
}
function buildnavbuttons() {
if ( settings.enablenavbuttons && _flipitems.length > 1 ) {
_flipster.find(".flipto-prev, .flipto-next").remove();
_flipster.append(""+settings.prevtext+" "+settings.nexttext+"");
_flipster.children('.flipto-prev').on("click", function(e) {
jump("left");
e.preventdefault();
});
_flipster.children('.flipto-next').on("click", function(e) {
jump("right");
e.preventdefault();
});
}
}
function center() {
var currentitem = $(_flipitems[_current]).addclass("flip-current");
_flipitems.removeclass("flip-prev flip-next flip-current flip-past flip-future no-transition");
if ( settings.style === 'carousel' ) {
_flipitems.addclass("flip-hidden");
var nextitem = $(_flipitems[_current+1]),
futureitem = $(_flipitems[_current+2]),
previtem = $(_flipitems[_current-1]),
pastitem = $(_flipitems[_current-2]);
if ( _current === 0 ) {
previtem = _flipitems.last();
pastitem = previtem.prev();
}
else if ( _current === 1 ) {
pastitem = _flipitems.last();
}
else if ( _current === _flipitems.length-2 ) {
futureitem = _flipitems.first();
}
else if ( _current === _flipitems.length-1 ) {
nextitem = _flipitems.first();
futureitem = $(_flipitems[1]);
}
futureitem.removeclass("flip-hidden").addclass("flip-future");
pastitem.removeclass("flip-hidden").addclass("flip-past");
nextitem.removeclass("flip-hidden").addclass("flip-next");
previtem.removeclass("flip-hidden").addclass("flip-prev");
}
else {
var spacer = currentitem.outerwidth()/2;
var totalleft = 0;
var totalwidth = _flipitemsouter.width();
var currentwidth = currentitem.outerwidth();
var currentleft = (_flipitems.index(currentitem)*currentwidth)/2 +spacer/2;
_flipitems.removeclass("flip-hidden");
for (var i = 0; i < _flipitems.length; i++) {
var thisitem = $(_flipitems[i]);
var thiswidth = thisitem.outerwidth();
if (i < _current) {
thisitem.addclass("flip-past")
.css({
"z-index" : i,
"left" : (i*thiswidth/2)+"px"
});
}
else if ( i > _current ) {
thisitem.addclass("flip-future")
.css({
"z-index" : _flipitems.length-i,
"left" : (i*thiswidth/2)+spacer+"px"
});
}
}
currentitem.css({
"z-index" : _flipitems.length+1,
"left" : currentleft +"px"
});
totalleft = (currentleft + (currentwidth/2)) - (totalwidth/2);
var newleftpos = -1*(totalleft)+"px";
/* untested compatibility */
if (compatibility) {
var leftitems = $(".flip-past");
var rightitems = $(".flip-future");
$(".flip-current").css("zoom", "1.0");
for (i = 0; i < leftitems.length; i++) {
$(leftitems[i]).css("zoom", (100-((leftitems.length-i)*5)+"%"));
}
for (i = 0; i < rightitems.length; i++) {
$(rightitems[i]).css("zoom", (100-((i+1)*5)+"%"));
}
_flipitemsouter.animate({"left":newleftpos}, 333);
}
else {
_flipitemsouter.css("left", newleftpos);
}
}
currentitem
.addclass("flip-current")
.removeclass("flip-prev flip-next flip-past flip-future flip-hidden");
resize();
updatenav();
settings.onitemswitch.call(this);
}
function jump(to) {
if ( _flipitems.length > 1 ) {
if ( to === "left" ) {
if ( _current > 0 ) { _current--; }
else { _current = _flipitems.length-1; }
}
else if ( to === "right" ) {
if ( _current < _flipitems.length-1 ) { _current++; }
else { _current = 0; }
} else if ( typeof to === 'number' ) {
_current = to;
} else {
// if object is sent, get its index
_current = _flipitems.index(to);
}
center();
}
}
function init() {
// basic setup
_flipster.addclass("flipster flipster-active flipster-"+settings.style).css("visibility","hidden");
if (settings.disablerotation)
_flipster.addclass('no-rotate');
_flipitemsouter = _flipster.find(settings.itemcontainer).addclass("flip-items");
_flipitems = _flipitemsouter.find(settings.itemselector).addclass("flip-item flip-hidden").wrapinner("");
//browsers that don't support css3 transforms get compatibility:
var isiemax8 = ('\v' === 'v'); //ie <= 8
var checkie = document.createelement("b");
checkie.innerhtml = ""; //ie 9
var isie9 = checkie.getelementsbytagname("i").length === 1;
if (isiemax8 || isie9) {
compatibility = true;
_flipitemsouter.addclass("compatibility");
}
// insert navigation if enabled.
buildnav();
buildnavbuttons();
// set the starting item
if (settings.start && _flipitems.length > 1) {
// find the middle item if start = center
if ( settings.start === 'center' ) {
if (!_flipitems.length % 2) {
_current = _flipitems.length/2 + 1;
} else {
_current = math.floor(_flipitems.length/2);
}
} else {
_current = settings.start;
}
}
// initialize containers
resize();
// necessary to start flipster invisible and then fadein so height/width can be set accurately after page load
_flipster.hide().css("visibility","visible").fadein(400,function(){ center(); });
// attach event bindings.
win.on("resize.flipster", function() {
resize();
center();
});
// navigate directly to an item by clicking
_flipitems.on("click", function(e) {
if ( !$(this).hasclass("flip-current") ) { e.preventdefault(); }
jump(_flipitems.index(this));
});
// keyboard navigation
if (settings.enablekeyboard && _flipitems.length > 1) {
win.on("keydown.flipster", function(e) {
_actionthrottle++;
if (_actionthrottle % 7 !== 0 && _actionthrottle !== 1) return; //if holding the key down, ignore most events
var code = e.which;
if (code === 37 ) {
e.preventdefault();
jump('left');
} else if (code === 39 ) {
e.preventdefault();
jump('right');
}
});
win.on("keyup.flipster", function(e){
_actionthrottle = 0; //reset action throttle on key lift to avoid throttling new interactions
});
}
// mousewheel navigation
if (settings.enablemousewheel && _flipitems.length > 1) { // todo: fix scrollwheel on firefox
_flipster.on("mousewheel.flipster", function(e){
_throttletimeout = window.settimeout(removethrottle, 500); //throttling should expire if scrolling pauses for a moment.
_actionthrottle++;
if (_actionthrottle % 4 !==0 && _actionthrottle !== 1) return; //throttling like with held-down keys
window.cleartimeout(_throttletimeout);
if ( e.originalevent.wheeldelta /120 > 0 ) { jump("left"); }
else { jump("right"); }
e.preventdefault();
});
}
// touch navigation
if ( settings.enabletouch && _flipitems.length > 1 ) {
_flipster.on("touchstart.flipster", function(e) {
_starttouchx = e.originalevent.targettouches[0].screenx;
});
_flipster.on("touchmove.flipster", function(e) {
e.preventdefault();
var nowx = e.originalevent.targettouches[0].screenx;
var touchdiff = nowx-_starttouchx;
if (touchdiff > _flipitems[0].clientwidth/1.75){
jump("left");
_starttouchx = nowx;
}else if (touchdiff < -1*(_flipitems[0].clientwidth/1.75)){
jump("right");
_starttouchx = nowx;
}
});
_flipster.on("touchend.flipster", function(e) {
_starttouchx = 0;
});
}
}
// initialize if flipster is not already active.
if ( !_flipster.hasclass("flipster-active") ) { init(); }
});
};
})(jquery);