-
-
Save fabiomcosta/246258 to your computer and use it in GitHub Desktop.
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
/* | |
Copyright (c) 2009 Rob Bast | |
Permission is hereby granted, free of charge, to any person | |
obtaining a copy of this software and associated documentation | |
files (the "Software"), to deal in the Software without | |
restriction, including without limitation the rights to use, | |
copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software | |
is furnished to do so, subject to the following condition: | |
The above copyright notice and this permission notice shall be | |
included in all copies or substantial portions of the Software. | |
slider.js | |
Simple class for sliding elements within a container. | |
Container should be as wide as the total width of slides you | |
intend to show at once (overflow hidden). Slides should be wide | |
enough to fill the container. Slides should have no margin or | |
padding! If you need these, simply add a child element to the | |
slide with desired padding or margin. | |
*/ | |
var Slider = new Class({ | |
Implements: [Options, Events, Chain], | |
options: { | |
childSelector: 'div', // used to grab sliding children of container | |
endless: false, // endless implies next() or previous() always works | |
direction: 'horizontal', // direction of sliding, horizontal or vertical | |
show: 1, // how many items to show at once | |
slidesToSlide: 1, // how many items to slide at once | |
auto: false, // delay between each auto slide action (set to false for off) | |
fxOptions: { | |
duration: 500 // duration of the slide effect | |
}, | |
onStart: function(){ | |
this.next(); | |
}, | |
onFirst: function(){ | |
this.next(); | |
}, | |
onLast: function(){ | |
this.previous(); | |
}, | |
onNext: $empty, | |
onPrevious: $empty, | |
onStop: $empty, | |
onPause: $empty, | |
onResume: $empty | |
}, | |
slides: { | |
next: [], | |
previous: [] | |
}, | |
fx: null, | |
initialize: function(container, options){ | |
// grab container element | |
this.container = this.parent = document.id(container); | |
// check if container exists | |
if(!this.container){ | |
console.error('You failed the internet, do not pass start and do not collect awesome fx effects.'); | |
return; | |
} | |
// process any passed options | |
this.setOptions(options); | |
// grab all children of our container, based on childSelector given && also apply style float:left | |
var slides = this.container.getElements(this.options.childSelector).setStyle('float', 'left'); | |
// check if we have enough child elements to work with | |
if(slides.length < this.options.show + 1){ | |
console.error('Failure is imminent, need more items to slide anything.'); | |
return; | |
} | |
// grab all excess children and loop through them | |
slides.slice(this.options.show, slides.length).each( | |
function(slide){ | |
// remove each element from the DOM and push them onto the 'next' slides stack | |
this.slides.next.push(slide.dispose()); | |
// I bind 'this', because otherwise this.slides is not accessible | |
}.bind(this) | |
); | |
// check if we want to slide multiple slides at once | |
if(this.options.slidesToSlide > 1){ | |
// set slide duration to duration divided by amount of slides to slide | |
this.options.fxOptions = $merge(this.options.fxOptions, {duration: this.options.fxOptions.duration / this.options.slidesToSlide}); | |
} | |
// if auto slide option is on | |
if(this.options.auto){ | |
// start sliding! durrr | |
this.start.delay(this.options.auto, this); | |
} | |
}, | |
start: function(){ | |
this.fireEvent('start'); | |
}, | |
stop: function(){ | |
if(this.timeoutId){ | |
$clear(this.timeoutId); | |
} | |
this.fireEvent('stop'); | |
}, | |
pause: function(){ | |
if(this.fx){ | |
this.fx.pause(); | |
} | |
this.fireEvent('pause'); | |
}, | |
resume: function(){ | |
if(this.fx){ | |
this.fx.resume(); | |
} | |
this.fireEvent('resume'); | |
}, | |
previous: function(slides){ | |
var slides = slides || this.options.slidesToSlide; | |
this.slide(-slides); | |
}, | |
next: function(slides){ | |
var slides = slides || this.options.slidesToSlide; | |
this.slide(slides); | |
}, | |
slide: function(slides){ | |
// check if we don't have an fx instance running | |
if(!this.fx){ | |
// check if we're moving in 'next' direction and are out of slides | |
if(slides > 0 && !this.slides.next.length){ | |
// check if we are running in endless mode | |
if(this.options.endless){ | |
// grab the last slide from the 'previous' slides stack and push it onto the 'next' slides stack | |
this.slides.next.push(this.slides.previous.pop()); | |
// we're not | |
}else{ | |
// fire last event | |
this.fireEvent('last'); | |
// stop further processing | |
return; | |
} | |
} | |
// check if we're moving in 'previous' direction and are out of slides | |
if(slides < 0 && !this.slides.previous.length){ | |
// check if we are running in endless mode | |
if(this.options.endless){ | |
// grab the last slide from the 'next' slides stack and push it onto the 'previous' slides stack | |
this.slides.previous.push(this.slides.next.pop()); | |
// we're not | |
}else{ | |
// fire first event | |
this.fireEvent('first'); | |
// stop further processing | |
return; | |
} | |
} | |
// get the old child about to be removed | |
var oldChild = (slides > 0 | |
? this.container.getFirst(this.options.childSelector) | |
: this.container.getLast(this.options.childSelector) | |
); | |
// get the new child we want to slide in | |
var newChild = (slides > 0 | |
? this.slides.next.shift() | |
: this.slides.previous.shift() | |
); | |
// generate the options object | |
var opts = {'0': {}, '1': {}}; | |
// figure out which direction we are sliding in | |
switch(this.options.direction){ | |
// vertical! | |
case 'vertical': | |
// figure out which margin to adjust depending on 'next' or 'previous' direction | |
opts['0'][(slides > 0 ? 'margin-top' : 'margin-bottom')] = [0, -oldChild.getStyle('height').toInt()]; | |
opts['1'][(slides > 0 ? 'margin-bottom' : 'margin-top')] = [-oldChild.getStyle('height').toInt(), 0]; | |
// inject element into appropriate dom location after having adjusted style | |
newChild.setStyle((slides > 0 ? 'margin-bottom' : 'margin-top'), -oldChild.getStyle('height').toInt()); | |
break; | |
// horizontal! | |
case 'horizontal': | |
default: | |
// figure out which margin to adjust depending on 'next' or 'previous' direction | |
opts['0'][(slides > 0 ? 'margin-left' : 'margin-right')] = [0, -oldChild.getStyle('width').toInt()]; | |
opts['1'][(slides > 0 ? 'margin-right' : 'margin-left')] = [-oldChild.getStyle('width').toInt(), 0]; | |
// inject element into appropriate dom location after having adjusted style | |
newChild.setStyle((slides > 0 ? 'margin-right' : 'margin-left'), -oldChild.getStyle('width').toInt()); | |
break; | |
} | |
// merge some options for the fx instance | |
var fxOptions = $merge(this.options.fxOptions, { | |
// onComplete event | |
onComplete: function(e){ | |
// when we're done, unset fx instance | |
this.fx = null; | |
// dispose of the old child | |
if(slides > 0){ | |
// push it onto the 'previous' stack if we inserted a 'next' slide | |
this.slides.previous.unshift(oldChild.dispose().setStyles({'margin-top':0,'margin-bottom':0,'margin-left':0,'margin-right':0})); | |
// dispose of the old child | |
}else{ | |
// push it onto the 'next' stack if we inserted a 'previous' slide | |
this.slides.next.unshift(oldChild.dispose().setStyles({'margin-top':0,'margin-bottom':0,'margin-left':0,'margin-right':0})); | |
} | |
// do we have more slides to slide? | |
if(slides.toInt()-1 > 0){ | |
// call slide! | |
this.slide((slides > 0 | |
? slides - 1 | |
: slides + 1 | |
)); | |
// are we in auto sliding mode? | |
}else if(this.options.auto){ | |
// check if we were heading for 'next' | |
if(slides > 0){ | |
// call next after a delay | |
this.next.delay(this.options.auto, this); | |
// we were heading for 'previous' | |
}else{ | |
// call previous after a delay | |
this.previous.delay(this.options.auto, this); | |
} | |
} | |
}.bind(this) | |
}); | |
// insert the element | |
newChild.inject(this.container, (slides > 0 ? 'bottom' : 'top')); | |
// create the fx instance | |
this.fx = new Fx.Elements($$(oldChild, newChild), fxOptions).start(opts); | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment