Skip to content

Instantly share code, notes, and snippets.

@shshaw
Created September 17, 2014 20:59
Show Gist options
  • Save shshaw/c34f247b2181b779aa73 to your computer and use it in GitHub Desktop.
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.
(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