Created
September 17, 2014 20:59
-
-
Save shshaw/c34f247b2181b779aa73 to your computer and use it in GitHub Desktop.
Attempt at rewriting some of the core functions of flipster to be a little more compartmentalized and reusable.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($) { | |
$.fn.flipster = function(options) { | |
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 | |
// display: 'all', // Number of items to display. Set to 'all' to show all | |
sideItems: 'all', // Number of items to display on each side. Set to 'all' to show all. | |
loop: false, | |
itemWidthPercent: 1, | |
spacing: 0, | |
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. | |
align: 'center', // Align selected item 'center', 'left' or 'right'; | |
offset: 0, // Offset from the aligned side | |
enableKeyboard: true, // Enable left/right arrow navigation | |
enableMousewheel: true, // Enable scrollwheel navigation (up = left, down = right) | |
enableTouch: true, // Enable swipe navigation for touch devices | |
enableNav: false, // If true, flipster will insert an unordered list of the slides | |
enableNavButtons: false, // If true, flipster will insert Previous / Next buttons | |
onItemSwitch: function(){}, // Callback function when items are switched | |
}; | |
var settings = $.extend({}, defaults, options); | |
var win = $(window); | |
return this.each(function(){ | |
var _flipster = $(this); | |
var _flipItemsOuter; | |
var _flipItems; | |
var _flipNav; | |
var _flipNavItems; | |
var _current = 0; | |
var _startTouchX = 0; | |
var _actionThrottle = 0; | |
var _throttleTimeout; | |
var compatibility; | |
function removeThrottle() { | |
_actionThrottle = 0; | |
} | |
function resize() { | |
_flipItemsOuter.css("height",_flipItems.height()); | |
_flipster.css("height","auto"); | |
if ( settings.style === 'carousel' ) { _flipItemsOuter.width(_flipItems.width()); } | |
var currentItem = $(_flipItems[_current]); | |
var currentWidth = currentItem.outerWidth(); | |
// var spacer = (currentWidth * settings.itemWidthPercent);//currentItem.outerWidth(); | |
var prevLeft = 0; | |
var totalWidth = 0; | |
console.log("Resize, aligning items"); | |
for (i = 0, totalItems = _flipItems.length; i < totalItems; i++) { | |
var thisItem = $(_flipItems[i]); | |
//.css({ 'position' : 'relative', 'float' : 'left' }); // Switch to float left | |
var thisWidth = thisItem.outerWidth(); | |
var thisLeft = prevLeft + ((thisWidth * settings.itemWidthPercent)+settings.spacing); | |
totalWidth += thisWidth; | |
if ( i === _current ) { | |
thisItem.addClass("flip-current") | |
.css({ | |
"z-index" : _flipItems.length+1, | |
"left" : thisLeft+"px"//currentLeft+"px" | |
}); | |
currentLeft = thisLeft; | |
} | |
else if (i < _current ) { | |
if ( i === _current-1 ) { thisItem.addClass("flip-prev"); } | |
thisItem.addClass("flip-past") | |
.css({ | |
"z-index" : i, | |
"left" : (thisLeft)+"px" | |
}); | |
} | |
else if ( i > _current ) { | |
if ( i === _current+1 ) { thisItem.addClass("flip-next"); } | |
thisItem.addClass("flip-future") | |
.css({ | |
"z-index" : _flipItems.length-i, | |
"left" : (thisLeft)+"px" | |
}); | |
} | |
prevLeft = thisLeft; | |
//_flipItemsOuter.css("width",totalWidth); | |
//console.log("totalWidth",totalWidth,"thisWidth",thisWidth); | |
if ( settings.sideItems !== 'all' ) { | |
var sideItems = Math.abs(Math.round(settings.sideItems)); | |
console.log("sideItems",sideItems); | |
if ( i < _current && i > _current - sideItems - 1 ) { } | |
else if ( i > _current && i < _current + sideItems + 1 ) { } | |
else { thisItem.addClass("flip-hidden"); } | |
} | |
} | |
} | |
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] = '<li class="flip-nav-category"><a href="#" class="flip-nav-category-link" data-flip-category="'+category+'">'+category+'</a>\n<ul class="flip-nav-items">\n'; | |
} | |
} | |
if ( $.inArray(itemId,navItems) < 0 ) { | |
navItems.push(itemId); | |
link = '<a href="#'+itemId+'" class="flip-nav-item-link">'+itemTitle+'</a></li>\n'; | |
if ( typeof category !== 'undefined' ) { | |
navList[category] = navList[category] + '<li class="flip-nav-item">' + link; | |
} else { | |
navList[itemId] = '<li class="flip-nav-item no-category">' + link; | |
} | |
} | |
}); | |
navDisplay = '<ul class="flipster-nav">\n'; | |
for ( var catIndex in navCategories ) { | |
navList[navCategories[catIndex]] = navList[navCategories[catIndex]] + "</ul>\n</li>\n"; | |
} | |
for ( var navIndex in navList ) { navDisplay += navList[navIndex]; } | |
navDisplay += '</ul>'; | |
_flipNav = $(navDisplay).prependTo(_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 ) { | |
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("<a href='#' class='flipto-prev'>Previous</a> <a href='#' class='flipto-next'>Next</a>"); | |
_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]); | |
_flipItems.removeClass("flip-hidden flip-prev flip-next flip-current flip-past flip-future no-transition"); | |
for (i = 0; i < _flipItems.length; i++) { | |
var thisItem = $(_flipItems[i]); | |
if ( i === _current ) { | |
thisItem.addClass("flip-current") | |
.css({ "z-index" : _flipItems.length+1 }); | |
} | |
else if (i < _current ) { | |
if ( i === _current-1 ) { thisItem.addClass("flip-prev"); } | |
thisItem.addClass("flip-past") | |
.css({ "z-index" : i }); | |
} | |
else if ( i > _current ) { | |
if ( i === _current+1 ) { thisItem.addClass("flip-next"); } | |
thisItem.addClass("flip-future") | |
.css({ "z-index" : _flipItems.length-i }); | |
} | |
if ( settings.sideItems !== 'all' ) { | |
var sideItems = Math.abs(Math.round(settings.sideItems)); | |
console.log("sideItems",sideItems); | |
if ( i < _current && i > _current - sideItems - 1 ) { } | |
else if ( i > _current && i < _current + sideItems + 1 ) { } | |
else { thisItem.addClass("flip-hidden"); } | |
} | |
} | |
// Alignment | |
var totalWidth = _flipItemsOuter.width(); | |
var currentWidth = currentItem.outerWidth(); | |
var currentLeft = currentItem.position().left; | |
var totalLeft = currentLeft; | |
console.log("currentLeft",currentLeft); | |
if ( settings.align === 'center' ) { | |
totalLeft = (totalLeft + (currentWidth/2)) - (totalWidth/2); | |
} else if ( settings.align === 'right' ) { | |
totalLeft = totalLeft + currentWidth - totalWidth; | |
} | |
// Offset | |
if ( settings.align === 'right' ) { | |
totalLeft += settings.offset; | |
} else { | |
totalLeft -= settings.offset; | |
} | |
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"); | |
updateNav(); | |
settings.onItemSwitch.call(this); | |
} | |
function jump(to) { | |
if ( _flipItems.length > 1 ) { | |
if ( to === "left" ) { | |
if ( _current > 0 ) { _current--; } | |
else if ( settings.loop === true ) { _current = _flipItems.length-1; } | |
} | |
else if ( to === "right" ) { | |
if ( _current < _flipItems.length-1 ) { _current++; } | |
else if ( settings.loop === true ) { _current = 0; } | |
} else if ( typeof to === 'number' ) { | |
_current = to; | |
} else { | |
// if object is sent, get its index | |
_current = _flipItems.index(to); | |
} | |
center(); | |
} | |
} | |
function init() { | |
/* Untested Compatibility */ | |
// Basic setup | |
_flipster.addClass("flipster flipster-active").css("visibility","hidden"); | |
_flipItemsOuter = _flipster.find(settings.itemContainer).addClass("flip-items"); | |
_flipItems = _flipItemsOuter.find(settings.itemSelector).addClass("flip-item flip-hidden").wrapInner("<div class='flip-content' />"); | |
_flipster.addClass("flipster-align"+settings.align); | |
//Browsers that don't support CSS3 transforms get compatibility: | |
var isIEmax8 = ('\v' === 'v'); //IE <= 8 | |
var checkIE = document.createElement("b"); | |
checkIE.innerHTML = "<!--[if IE 9]><i></i><![endif]-->"; //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(){ resize(); center(); }); | |
// Attach event bindings. | |
win.resize(function(){ resize(); center(); }); | |
// Navigate directly to an item by clicking | |
_flipItems.on("click", function(e) { | |
if ( !$(this).hasClass("flip-current") ) { e.preventDefault(); } | |
_throttleTimeout = window.setTimeout(removeThrottle, 500); | |
_actionThrottle++; | |
if (_actionThrottle % 7 !== 0 && _actionThrottle !== 1) return; | |
jump(_flipItems.index(this)); | |
}); | |
// Keyboard Navigation | |
if ( settings.enableKeyboard && _flipItems.length > 1 ) { | |
win.on("keydown.flipster", function(e) { | |
_throttleTimeout = window.setTimeout(removeThrottle, 500); | |
_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 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment