Created
March 20, 2020 15:19
-
-
Save cannap/ded375a38eb40ca826c654856d9d027a to your computer and use it in GitHub Desktop.
This file contains hidden or 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($) { | |
// cache some values | |
var cache = { | |
idx_expanded : -1, // the index of the current expanded slice | |
sliceH : 0, // the default slice's height | |
current : 0, // controls the current slider position | |
totalSlices : 0 // total number of slices | |
}, | |
aux = { | |
// triggered when we click a slice. If the slice is expanded, | |
// we close it, otherwise we open it.. | |
selectSlice : function( $el, $slices, $navNext, $navPrev, settings ) { | |
return $.Deferred( | |
function( dfd ) { | |
var expanded = $el.data('expanded'), | |
pos = $el.data('position'), | |
itemHeight, othersHeight, | |
$others = $slices.not( $el ); | |
// if it's opened.. | |
if( expanded ) { | |
$el.data( 'expanded', false ); | |
cache.idx_expanded = -1; | |
// the default values of each slices's height | |
itemHeight = cache.sliceH; | |
othersHeight= cache.sliceH; | |
// hide the content div | |
$el.find('.va-content').hide(); | |
// control the navigation buttons visibility | |
if( aux.canSlideUp( $slices, settings ) ) | |
$navPrev.fadeIn(); | |
else | |
$navPrev.fadeOut(); | |
if( aux.canSlideDown( $slices, settings ) ) | |
$navNext.fadeIn(); | |
else | |
$navNext.fadeOut(); | |
} | |
// if it's closed.. | |
else { | |
$el.data( 'expanded', true ); | |
cache.idx_expanded = $el.index(); | |
$others.data( 'expanded', false ); | |
// the current slice's height | |
itemHeight = settings.expandedHeight; | |
// the height the other slices will have | |
othersHeight= Math.ceil( ( settings.accordionH - settings.expandedHeight ) / ( settings.visibleSlices - 1 ) ); | |
// control the navigation buttons visibility | |
if( cache.idx_expanded > 0 ) | |
$navPrev.fadeIn(); | |
else | |
$navPrev.fadeOut(); | |
if( cache.idx_expanded < cache.totalSlices - 1 ) | |
$navNext.fadeIn(); | |
else | |
$navNext.fadeOut(); | |
} | |
// the animation parameters for the clicked slice | |
var animParam = { | |
height : itemHeight + 'px', | |
opacity : 1, | |
top : ( pos - 1 ) * othersHeight + 'px' | |
}; | |
// animate the clicked slice and also its title (<h3>) | |
$el.stop() | |
.animate( animParam, settings.animSpeed, settings.animEasing, function() { | |
if( !expanded ) | |
$el.find('.va-content').fadeIn( settings.contentAnimSpeed ); | |
}) | |
.find('.va-title') | |
.stop() | |
.animate({ | |
lineHeight : cache.sliceH + 'px' | |
}, settings.animSpeed, settings.animEasing ); | |
// animate all the others | |
$others.each(function(i){ | |
var $other = $(this), | |
posother= $other.data('position'), | |
t; | |
if( expanded ) | |
t = ( posother - 1 ) * othersHeight ; | |
else { | |
if( posother < pos ) | |
t = ( posother - 1 ) * othersHeight ; | |
else | |
t = ( ( posother - 2 ) * othersHeight ) + settings.expandedHeight; | |
} | |
$other.stop() | |
.animate( { | |
top : t + 'px', | |
height : othersHeight + 'px', | |
opacity : ( expanded ) ? 1 : settings.animOpacity | |
}, settings.animSpeed, settings.animEasing, dfd.resolve ) | |
.find('.va-title') | |
.stop() | |
.animate({ | |
lineHeight : othersHeight + 'px' | |
}, settings.animSpeed, settings.animEasing ) | |
.end() | |
.find('.va-content') | |
.hide(); | |
}); | |
} | |
).promise(); | |
}, | |
// triggered when clicking the navigation buttons / mouse scrolling | |
navigate : function( dir, $slices, $navNext, $navPrev, settings ) { | |
// if animating return | |
if( $slices.is(':animated') ) | |
return false; | |
// all move up / down one position | |
// if settings.savePositions is false, then we need to close any expanded slice before sliding | |
// otherwise we slide, and the next one will open automatically | |
var $el; | |
if( cache.idx_expanded != -1 && !settings.savePositions ) { | |
$el = $slices.eq( cache.idx_expanded ); | |
$.when( aux.selectSlice( $el, $slices, $navNext, $navPrev, settings ) ).done(function(){ | |
setTimeout(function() { | |
aux.slide( dir, $slices, $navNext, $navPrev, settings ); | |
}, 10); | |
}); | |
} | |
else { | |
aux.slide( dir, $slices, $navNext, $navPrev, settings ); | |
} | |
}, | |
slide : function( dir, $slices, $navNext, $navPrev, settings ) { | |
// control if we can navigate. | |
// control the navigation buttons visibility. | |
// the navigation will behave differently for the cases we have all the slices closed, | |
// and when one is opened. It will also depend on settings.savePositions | |
if( cache.idx_expanded === -1 || !settings.savePositions ) { | |
if( dir === 1 && cache.current + settings.visibleSlices >= cache.totalSlices ) | |
return false; | |
else if( dir === -1 && cache.current === 0 ) | |
return false; | |
if( dir === -1 && cache.current === 1 ) | |
$navPrev.fadeOut(); | |
else | |
$navPrev.fadeIn(); | |
if( dir === 1 && cache.current + settings.visibleSlices === cache.totalSlices - 1 ) | |
$navNext.fadeOut(); | |
else | |
$navNext.fadeIn(); | |
} | |
else { | |
if( dir === 1 && cache.idx_expanded === cache.totalSlices - 1 ) | |
return false; | |
else if( dir === -1 && cache.idx_expanded === 0 ) | |
return false; | |
if( dir === -1 && cache.idx_expanded === 1 ) | |
$navPrev.fadeOut(); | |
else | |
$navPrev.fadeIn(); | |
if( dir === 1 && cache.idx_expanded === cache.totalSlices - 2 ) | |
$navNext.fadeOut(); | |
else | |
$navNext.fadeIn(); | |
} | |
var $currentSlice = $slices.eq( cache.idx_expanded ), | |
$nextSlice, | |
t; | |
( dir === 1 ) ? $nextSlice = $currentSlice.next() : $nextSlice = $currentSlice.prev(); | |
// if we cannot slide up / down, then we just call the selectSlice for the previous / next slice | |
if( ( dir === 1 && !aux.canSlideDown( $slices, settings ) ) || | |
( dir === -1 && !aux.canSlideUp( $slices, settings ) ) ) { | |
aux.selectSlice( $nextSlice, $slices, $navNext, $navPrev, settings ); | |
return false; | |
} | |
// if we slide down, the top and position of each slice will decrease | |
if( dir === 1 ) { | |
cache.current++; | |
t = '-=' + cache.sliceH; | |
pos_increment = -1; | |
} | |
else { | |
cache.current--; | |
t = '+=' + cache.sliceH; | |
pos_increment = 1; | |
} | |
$slices.each(function(i) { | |
var $slice = $(this), | |
pos = $slice.data('position'); | |
// all closed or savePositions is false | |
if( !settings.savePositions || cache.idx_expanded === -1 ) | |
$slice.stop().animate({top : t}, settings.animSpeed, settings.animEasing); | |
else { | |
var itemHeight, othersHeight; | |
// if the slice is the one we should open.. | |
if( i === $nextSlice.index() ) { | |
$slice.data( 'expanded', true ); | |
cache.idx_expanded = $slice.index(); | |
itemHeight = settings.expandedHeight; | |
othersHeight = ( settings.accordionH - settings.expandedHeight ) / ( settings.visibleSlices - 1 ); | |
$slice.stop() | |
.animate({ | |
height : itemHeight + 'px', | |
opacity : 1, | |
top : ( dir === 1 ) ? ( pos - 2 ) * othersHeight + 'px' : pos * othersHeight + 'px' | |
}, settings.animSpeed, settings.animEasing, function() { | |
$slice.find('.va-content').fadeIn( settings.contentAnimSpeed ); | |
}) | |
.find('.va-title') | |
.stop() | |
.animate({ | |
lineHeight : cache.sliceH + 'px' | |
}, settings.animSpeed, settings.animEasing ); | |
} | |
// if the slice is the one opened, lets close it | |
else if( $slice.data('expanded') ){ | |
// collapse | |
$slice.data( 'expanded', false ); | |
othersHeight = ( settings.accordionH - settings.expandedHeight ) / ( settings.visibleSlices - 1 ); | |
$slice.stop() | |
.animate({ | |
height : othersHeight + 'px', | |
opacity : settings.animOpacity, | |
top : ( dir === 1 ) ? '-=' + othersHeight : '+=' + settings.expandedHeight | |
}, settings.animSpeed, settings.animEasing ) | |
.find('.va-title') | |
.stop() | |
.animate({ | |
lineHeight : othersHeight + 'px' | |
}, settings.animSpeed, settings.animEasing ) | |
.end() | |
.find('.va-content') | |
.hide(); | |
} | |
// all the others.. | |
else { | |
$slice.data( 'expanded', false ); | |
othersHeight = ( settings.accordionH - settings.expandedHeight ) / ( settings.visibleSlices - 1 ); | |
$slice.stop() | |
.animate({ | |
top : ( dir === 1 ) ? '-=' + othersHeight : '+=' + othersHeight | |
}, settings.animSpeed, settings.animEasing ); | |
} | |
} | |
// change the slice's position | |
$slice.data().position += pos_increment; | |
}); | |
}, | |
canSlideUp : function( $slices, settings ) { | |
var $first = $slices.eq( cache.current ); | |
if( $first.index() !== 0 ) | |
return true; | |
}, | |
canSlideDown : function( $slices, settings ) { | |
var $last = $slices.eq( cache.current + settings.visibleSlices - 1 ); | |
if( $last.index() !== cache.totalSlices - 1 ) | |
return true; | |
} | |
}, | |
methods = { | |
init : function( options ) { | |
if( this.length ) { | |
var settings = { | |
// the accordion's width | |
accordionW : 1000, | |
// the accordion's height | |
accordionH : 450, | |
// number of visible slices | |
visibleSlices : 3, | |
// the height of a opened slice | |
// should not be more than accordionH | |
expandedHeight : 350, | |
// speed when opening / closing a slice | |
animSpeed : 250, | |
// easing when opening / closing a slice | |
animEasing : 'jswing', | |
// opacity value for the collapsed slices | |
animOpacity : 0.2, | |
// time to fade in the slice's content | |
contentAnimSpeed: 900, | |
// if this is set to false, then before | |
// sliding we collapse any opened slice | |
savePositions : true | |
}; | |
return this.each(function() { | |
// if options exist, lets merge them with our default settings | |
if ( options ) { | |
$.extend( settings, options ); | |
} | |
var $el = $(this), | |
// the accordion's slices | |
$slices = $el.find('div.va-slice'), | |
// the navigation buttons | |
$navNext = $el.find('span.va-nav-next'), | |
$navPrev = $el.find('span.va-nav-prev'); | |
// each slice's height | |
cache.sliceH = Math.ceil( settings.accordionH / settings.visibleSlices ); | |
// total slices | |
cache.totalSlices = $slices.length; | |
// control some user config parameters | |
if( settings.expandedHeight > settings.accordionH ) | |
settings.expandedHeight = settings.accordionH; | |
else if( settings.expandedHeight <= cache.sliceH ) | |
settings.expandedHeight = cache.sliceH + 50; // give it a minimum | |
// set the accordion's width & height | |
$el.css({ | |
width : settings.accordionW + 'px', | |
height : settings.accordionH + 'px' | |
}); | |
// show / hide $navNext | |
if( settings.visibleSlices < cache.totalSlices ) | |
$navNext.show(); | |
// set the top & height for each slice. | |
// also save the position of each one. | |
// as we navigate, the first one in the accordion | |
// will have position 1 and the last settings.visibleSlices. | |
// finally set line-height of the title (<h3>) | |
$slices.each(function(i){ | |
var $slice = $(this); | |
$slice.css({ | |
top : i * cache.sliceH + 'px', | |
height : cache.sliceH + 'px' | |
}).data( 'position', (i + 1) ); | |
}) | |
.children('.va-title') | |
.css( 'line-height', cache.sliceH + 'px' ); | |
// click event | |
$slices.bind('click.vaccordion', function(e) { | |
// only if we have more than 1 visible slice. | |
// otherwise we will just be able to slide. | |
if( settings.visibleSlices > 1 ) { | |
var $el = $(this); | |
aux.selectSlice( $el, $slices, $navNext, $navPrev, settings ); | |
} | |
}); | |
// navigation events | |
$navNext.bind('click.vaccordion', function(e){ | |
aux.navigate( 1, $slices, $navNext, $navPrev, settings ); | |
}); | |
$navPrev.bind('click.vaccordion', function(e){ | |
aux.navigate( -1, $slices, $navNext, $navPrev, settings ); | |
}); | |
// adds events to the mouse | |
$el.bind('mousewheel.vaccordion', function(e, delta) { | |
if(delta > 0) { | |
aux.navigate( -1, $slices, $navNext, $navPrev, settings ); | |
} | |
else { | |
aux.navigate( 1, $slices, $navNext, $navPrev, settings ); | |
} | |
return false; | |
}); | |
}); | |
} | |
} | |
}; | |
$.fn.vaccordion = function(method) { | |
if ( methods[method] ) { | |
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); | |
} else if ( typeof method === 'object' || ! method ) { | |
return methods.init.apply( this, arguments ); | |
} else { | |
$.error( 'Method ' + method + ' does not exist on jQuery.vaccordion' ); | |
} | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment