Skip to content

Instantly share code, notes, and snippets.

@fabiomcosta
Forked from anonymous/slider.js
Created December 1, 2009 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabiomcosta/246258 to your computer and use it in GitHub Desktop.
Save fabiomcosta/246258 to your computer and use it in GitHub Desktop.
/*
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