Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- 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
- slideToSlide: 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,
- timeoutId: 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)
- );
- // 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're moving in next direction, are out of slides and have endless mode on
- if(slides > 0 && !this.slides.next.length && 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());
- }
- // check if we're moving in previous direction, are out of slides and have endless mode on
- if(slides < 0 && !this.slides.previous.length && 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());
- }
- // get the current child about to be removed
- var curChild = (slides > 0
- ? this.container.getFirst(this.options.childSelector)
- : this.container.getLast(this.options.childSelector)
- );
- // get the next 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, -curChild.getStyle('height').toInt()];
- opts['1'][(slides > 0 ? 'margin-bottom' : 'margin-top')] = [-curChild.getStyle('height').toInt(), 0];
- // inject element into appropriate dom location after having adjusted style
- newChild.setStyle((slides > 0 ? 'margin-bottom' : 'margin-top'), -curChild.getStyle('height').toInt())
- .inject(this.container, (slides > 0 ? 'bottom' : 'top'));
- 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, -curChild.getStyle('width').toInt()];
- opts['1'][(slides > 0 ? 'margin-right' : 'margin-left')] = [-curChild.getStyle('width').toInt(), 0];
- // inject element into appropriate dom location after having adjusted style
- newChild.setStyle((slides > 0 ? 'margin-right' : 'margin-left'), -curChild.getStyle('width').toInt())
- .inject(this.container, (slides > 0 ? 'bottom' : 'top'));
- break;
- }
- }
- // are we in auto slide mode?
- if(this.options.auto){
- // is there a timer active?
- if(this.timeoutId){
- // clear it
- $clear(this.timeoutId);
- }
- // generate the fxOptions object by merging default with some extra options
- var fxOptions = $merge(this.options.fxOptions, {
- // add a onComplete event
- onComplete: function(e){
- // when we're done, set a timer again, cause this is like, auto slide mode, mkay
- this.timeoutId = this.next.delay(this.options.auto, this);
- // binding 'this' cause otherwise this.next and such are not accessible
- }.bind(this)
- });
- // no autoslide mode
- }else{
- // default options are sufficient
- var fxOptions = this.options.fxOptions;
- }
- // are we sliding multiple elements at once?
- if(this.options.slidePer > 1){
- // set slide duration to duration divided by amount of slides to process
- var fxOptions = $merge(this.options.fxOptions, {duration: this.options.fxOptions.duration / this.options.slidePer});
- }
- // create the fx instance with the custom options, and add a chained function
- this.fx = new Fx.Elements($$(currChild, nextChild), fxOptions).start(opts).chain(
- function(){
- // unset the existing fx instance when we're done
- this.fx = null;
- // When we are done, dispose of the current child and put it on the 'previous' slides
- this.slides.previous.unshift(currChild.dispose().setStyles({'margin-top':0,'margin-bottom':0,'margin-left':0,'margin-right':0}));
- // check if it's a multislide action
- if(this.slidePerCurrent <= this.options.slidePer){
- // adjust counter
- this.slidePerCurrent = this.slidePerCurrent + 1;
- if(this.slidePerCurrent > this.options.slidePer){
- this.slidePerCurrent = 1;
- }else{
- // slide to next
- this.next();
- }
- }
- // again, binding 'this' for accessibility
- }.bind(this)
- );
- // we've moved to the next element, fire event!
- this.fireEvent('next', nextChild);
- // no more elements and no endless mode :(
- }else{
- // since there are no more elements, fire the last event
- this.fireEvent('last');
- }
- }
- return this;
- },
- previous: function(){
- // check if an fx instance isn't currently active
- if(!this.fx){
- // check if we still have elements in the 'previous' slides stack OR if endless mode is set
- if(this.slides.previous.length || this.options.endless){
- // If we have no more elements on the 'previous' slides stack, we assume endless mode is true
- if(!this.slides.previous.length){
- // grab the last slide from the 'next' slides and push it onto the 'previous' slides stack
- this.slides.previous.push(this.slides.next.pop());
- }
- // get the current child, use childSelector given just to be sure we get the right one
- var currChild = this.container.getLast(this.options.childSelector);
- // get the previous child we want
- var prevChild = this.slides.previous.shift();
- // generate the options object
- var opts = {'0': {}, '1': {}};
- // figure out which direction we are running in
- switch (this.options.direction){
- // vertical is ^ v
- case 'vertical':
- // so we mess with bottom margin of current child
- opts['0']['margin-bottom'] = [0, -currChild.getStyle('height').toInt()],
- // and with top margin of the previous child
- opts['1']['margin-top'] = [-currChild.getStyle('height').toInt(), 0];
- // apply the top margin to the to be inserted child and inject it into the dom
- prevChild.setStyle('margin-top', -currChild.getStyle('height').toInt()).inject(this.container, 'top');
- break;
- // horizontal is < >
- case 'horizontal':
- default:
- // so we mess with right margin of current child
- opts['0']['margin-right'] = [0, -currChild.getStyle('width').toInt()],
- // and with left margin of the next child
- opts['1']['margin-left'] = [-currChild.getStyle('width').toInt(), 0];
- // apply the left margin to the to be inserted child and inject it into the dom
- prevChild.setStyle('margin-left', -currChild.getStyle('width').toInt()).inject(this.container, 'top');
- break;
- }
- // are we in auto slide mode?
- if(this.options.auto){
- // is there a timer active?
- if(this.timeoutId){
- // clear it
- $clear(this.timeoutId);
- }
- // generate the fxOptions object by merging default with some extra options
- var fxOptions = $merge(this.options.fxOptions, {
- // add a onComplete event
- onComplete: function(e){
- // when we're done, set a timer again, cause this is like, auto slide mode, mkay
- this.timeoutId = this.previous.delay(this.options.auto, this);
- // binding 'this' cause otherwise this.previous and such are not accessible
- }.bind(this)
- });
- // not in auto slide mode
- }else{
- // default options are sufficient
- var fxOptions = this.options.fxOptions;
- }
- // are we sliding multiple elements at once?
- if(this.options.slidePer > 1){
- // set the duration of each slide effect to duration divided by amount of slides to be processed
- var fxOptions = $merge(this.options.fxOptions, {duration: this.options.fxOptions.duration / this.options.slidePer});
- }
- // create the fx instance with the custom options, and add a chained function
- this.fx = new Fx.Elements($$(currChild, prevChild), fxOptions).start(opts).chain(
- function(){
- // unset the fx instance
- this.fx = null;
- // when we are done, dispose of the current child and put it on the 'next' slides
- this.slides.next.unshift(currChild.dispose().setStyles({'margin-top':0,'margin-bottom':0,'margin-left':0,'margin-right':0}));
- // check if it's a multislide action
- if(this.slidePerCurrent <= this.options.slidePer){
- // adjust counter
- this.slidePerCurrent = this.slidePerCurrent + 1;
- if(this.slidePerCurrent > this.options.slidePer){
- this.slidePerCurrent = 1;
- }else{
- // slide to next
- this.previous();
- }
- }
- // again, binding 'this' for accessibility
- }.bind(this)
- );
- // we've moved to the previous element, fire event!
- this.fireEvent('previous', prevChild);
- // no more elements and no endless mode :(
- }else{
- // since there are no more elements, fire the first event
- this.fireEvent('first');
- }
- }
- return this;
- }
- });
Add Comment
Please, Sign In to add comment