Skip to the content...

Welcome to the David Walsh Blog. I'm a MooTools, Dojo, jQuery, CSS, and PHP Web Developer located in Madison, Wisconsin, United States. Please contact me if I can make your experience on my website better.

Create a Simple Slideshow Using MooTools, Part III: Creating a Class

18 Responses »

Christina Ricci

In my previous two slideshow posts, Create a Simple Slideshow Using MooTools and Create a Simple Slideshow Using MooTools, Part II: Controls and Events, I showed you how to create a slideshow using "inline" MooTools JavaScript. Today we'll take that code and transition it into a MooTools class.

The Original Inline Code

window.addEvent('domready',function() {
	/* settings */
	var showDuration = 3000;
	var container = $('slideshow-container');
	var images = container.getElements('img');
	var currentIndex = 0;
	var interval;
	var toc = [];
	var tocWidth = 20;
	var tocActive = 'toc-active';
	
	/* new: starts the show */
	var start = function() { interval = show.periodical(showDuration); };
	var stop = function() { $clear(interval); };
	/* worker */
	var show = function(to) {
		images[currentIndex].fade('out');
		toc[currentIndex].removeClass(tocActive);
		images[currentIndex = ($defined(to) ? to : (currentIndex < images.length - 1 ? currentIndex+1 : 0))].fade('in');
		toc[currentIndex].addClass(tocActive);
	};
	
	/* new: control: table of contents */
	images.each(function(img,i){
		toc.push(new Element('a',{
			text: i+1,
			href: '#',
			'class': 'toc' + (i == 0 ? ' ' + tocActive : ''),
			events: {
				click: function(e) {
					if(e) e.stop();
					stop();
					show(i);
				}
			},
			styles: {
				left: ((i + 1) * (tocWidth + 10))
			}
		}).inject(container));
		if(i > 0) { img.set('opacity',0); }
	});
	
	/* new: control: next and previous */
	var next = new Element('a',{
		href: '#',
		id: 'next',
		text: '>>',
		events: {
			click: function(e) {
				if(e) e.stop();
				stop(); show();
			}
		}
	}).inject(container);
	var previous = new Element('a',{
		href: '#',
		id: 'previous',
		text: '<<',
		events: {
			click: function(e) {
				if(e) e.stop();
				stop(); show(currentIndex != 0 ? currentIndex -1 : images.length-1);
			}
		}
	}).inject(container);
	
	/* new: control: start/stop on mouseover/mouseout */
	container.addEvents({
		mouseenter: function() { stop(); },
		mouseleave: function() { start(); }
	});
	
	/* start once the page is finished loading */
	window.addEvent('load',function(){
		start();
	});
});

We'll be starting from the above code which was used in the second post.

Step 1: Create a Basic Class Outline

The following MooTools Class template can be downloaded here.

var yourClass = new Class({
	
	//implements
	Implements: [Options],

	//options
	options: {
		yourOption: ''
	},
	
	//initialization
	initialize: function(options) {
		//set options
		this.setOptions(options);
	},
	
	//a method that does whatever you want
	yourMethod: function() {
		
	}
	
});

Step 2: Variables Become Options, Arguments

Remember that our class needs to be flexible (duh, that's the reason we create classes!). For that reason, we'll transition as many of the variables as we can into options for the class. Since the container and elements of the slideshow are mandatory (we can't create a slideshow without them!), we'll make those arguments.

var SimpleSlideshow = new Class({
	options: {
		showControls: true,
		showDuration: 3000,
		showTOC: true,
		tocWidth: 20,
		tocClass: 'toc',
		tocActiveClass: 'toc-active'
	},
	Implements: [Options,Events],
	initialize: function(container,elements,options) {
		//settings
		this.container = $(container);
		this.elements = $$(elements);
		this.currentIndex = 0;
		this.interval = '';
		if(this.options.showTOC) this.toc = [];
		
		//assign
		this.elements.each(function(el,i){
			if(this.options.showTOC) {
				this.toc.push(new Element('a',{
					text: i+1,
					href: '#',
					'class': this.options.tocClass + '' + (i == 0 ? ' ' + this.options.tocActiveClass : ''),
					events: {
						click: function(e) {
							if(e) e.stop();
							this.stop();
							this.show(i);
						}.bind(this)
					},
					styles: {
						left: ((i + 1) * (this.options.tocWidth + 10))
					}
				}).inject(this.container));
			}
			if(i > 0) el.set('opacity',0);
		},this);
		
		//next,previous links
		if(this.options.showControls) {
			this.createControls();
			
		}
		//events
		this.container.addEvents({
			mouseenter: function() { this.stop(); }.bind(this),
			mouseleave: function() { this.start(); }.bind(this)
		});

	},

//...

The usefulness of our class is largely dependent upon the options we bake into our plugin. Don't go overboard though -- it's easy to bloat your plugin by allowing for too many options.

Step 3: Functions Become Methods

This step is really easy: take the global functions we created (start, stop, etc.) and make them the methods within the class. The only big change in doing this will be changing variables references to "this.{variable}" or "this.options.{variable}".

//...
show: function(to) {
	this.elements[this.currentIndex].fade('out');
	if(this.options.showTOC) this.toc[this.currentIndex].removeClass(this.options.tocActiveClass);
	this.elements[this.currentIndex = ($defined(to) ? to : (this.currentIndex < this.elements.length - 1 ? this.currentIndex+1 : 0))].fade('in');
	if(this.options.showTOC) this.toc[this.currentIndex].addClass(this.options.tocActiveClass);
},
start: function() {
	this.interval = this.show.bind(this).periodical(this.options.showDuration);
},
stop: function() {
	$clear(this.interval);
}
//...

Step 4: Controls

We'll use another custom, private method to generate the code for the controls (next,previous):

//...
,
//"private"
createControls: function() {
	var next = new Element('a',{
		href: '#',
		id: 'next',
		text: '>>',
		events: {
			click: function(e) {
				if(e) e.stop();
				this.stop(); 
				this.show();
			}.bind(this)
		}
	}).inject(this.container);
	var previous = new Element('a',{
		href: '#',
		id: 'previous',
		text: '<<',
		events: {
			click: function(e) {
				if(e) e.stop();
				this.stop(); 
				this.show(this.currentIndex != 0 ? this.currentIndex -1 : this.elements.length-1);
			}.bind(this)
		}
	}).inject(this.container);
}
//...

Pulling It All Together

The following is our completed class:

var SimpleSlideshow = new Class({
	options: {
		showControls: true,
		showDuration: 3000,
		showTOC: true,
		tocWidth: 20,
		tocClass: 'toc',
		tocActiveClass: 'toc-active'
	},
	Implements: [Options,Events],
	initialize: function(container,elements,options) {
		//settings
		this.container = $(container);
		this.elements = $$(elements);
		this.currentIndex = 0;
		this.interval = '';
		if(this.options.showTOC) this.toc = [];
		
		//assign
		this.elements.each(function(el,i){
			if(this.options.showTOC) {
				this.toc.push(new Element('a',{
					text: i+1,
					href: '#',
					'class': this.options.tocClass + '' + (i == 0 ? ' ' + this.options.tocActiveClass : ''),
					events: {
						click: function(e) {
							if(e) e.stop();
							this.stop();
							this.show(i);
						}.bind(this)
					},
					styles: {
						left: ((i + 1) * (this.options.tocWidth + 10))
					}
				}).inject(this.container));
			}
			if(i > 0) el.set('opacity',0);
		},this);
		
		//next,previous links
		if(this.options.showControls) {
			this.createControls();
			
		}
		//events
		this.container.addEvents({
			mouseenter: function() { this.stop(); }.bind(this),
			mouseleave: function() { this.start(); }.bind(this)
		});

	},
	show: function(to) {
		this.elements[this.currentIndex].fade('out');
		if(this.options.showTOC) this.toc[this.currentIndex].removeClass(this.options.tocActiveClass);
		this.elements[this.currentIndex = ($defined(to) ? to : (this.currentIndex < this.elements.length - 1 ? this.currentIndex+1 : 0))].fade('in');
		if(this.options.showTOC) this.toc[this.currentIndex].addClass(this.options.tocActiveClass);
	},
	start: function() {
		this.interval = this.show.bind(this).periodical(this.options.showDuration);
	},
	stop: function() {
		$clear(this.interval);
	},
	//"private"
	createControls: function() {
		var next = new Element('a',{
			href: '#',
			id: 'next',
			text: '>>',
			events: {
				click: function(e) {
					if(e) e.stop();
					this.stop(); 
					this.show();
				}.bind(this)
			}
		}).inject(this.container);
		var previous = new Element('a',{
			href: '#',
			id: 'previous',
			text: '<<',
			events: {
				click: function(e) {
					if(e) e.stop();
					this.stop(); 
					this.show(this.currentIndex != 0 ? this.currentIndex -1 : this.elements.length-1);
				}.bind(this)
			}
		}).inject(this.container);
	}
});

...and the usage:

/* usage */
window.addEvent('domready',function() {
	var slideshow = new SimpleSlideshow('slideshow-container','#slideshow-container img');
	slideshow.start();	
});

MooTools Classes FTW!

Now we have a reusable, flexible MooTools class that you can use on any website you create. Hell, you could even share it on the Forge for all to use! How was it? Any questions about creating MooTools classes?

Discussion

  1. January 6, 2010 @ 9:29 am

    Hi david,

    cool thingy! Just wondered about this text that’s in dark-yellow above the slideshow demo:

    “Sit back and enjoy the simple slideshow featuring Christina Ricci below.”

    So I sat back and waited, and anticipated, and waited some more… But nothing happened ;-) Clicking the buttons did the trick, I just assumed reading the text that the slideshow would start automagically and loop endless pictures of the beautiful Miss Ricci in front of my globules.

    But alas, maybe a challenge for the next post?

  2. January 6, 2010 @ 9:40 am

    @Sebastiaan: No, there’s a funky thing going on — fixing now….

  3. January 6, 2010 @ 9:52 am

    Bind with care people…bind with care.

  4. ahmed
    January 6, 2010 @ 11:55 am

    The possibility of using divs & html code instead of images please :X

  5. January 6, 2010 @ 11:59 am

    @Ahmed: var slideshow = new SimpleSlideshow(‘slideshow-container’,'#slideshow-container div’);

    Done.

  6. January 6, 2010 @ 12:04 pm

    Great stuff David, learnt so much from these three tutorials!

  7. champ
    January 6, 2010 @ 1:05 pm

    through up some naked pics of this chick…

  8. alex
    January 6, 2010 @ 2:37 pm

    +1 for Champ’s suggestion

  9. January 6, 2010 @ 2:42 pm

    Google images is a goldmine, my friends.

  10. January 7, 2010 @ 9:39 am

    The thread suddenly died…wonder if they’re all off at Google images? :P

  11. yorker
    January 9, 2010 @ 6:56 am

    Thanks david, you are a star, Now I am going to change this from fadein and out to slide from any direction. would you please give me some idea, how to do that. do I need to use fx.slide class?

    Thanks in advance

  12. claudio ferreira
    January 12, 2010 @ 12:43 pm

    Great set of tutorials. It really helps starting with a simple code and building from there. Hope to see more series like that here. Thanks again David.

  13. January 18, 2010 @ 6:46 am

    Awesome, i have learn so much from these tutorials please share some more useful tutorials regarding to css.

  14. james barrante
    February 13, 2010 @ 3:05 am

    David, thanks for this great work and all the other inspirations you give!

  15. flumi
    February 13, 2010 @ 2:30 pm

    Thanks for this light SlideShow, brilliant!

    Options didn’t work for me, I had to add:

    this.setOptions(options);

  16. wayne
    February 16, 2010 @ 11:58 am

    Just woundering but is there a way to make the next previous buttons images? And maybe even change the image numbers to images??

  17. August 18, 2010 @ 1:25 am

    Nice work David for sure. I have been using for a little while and just realised I can’t get a second slideshow on the page (different div’s)- is this a limitation of the script or of my implementation of it?
    it it can be done would it be rude of me to ask for an example snippet?
    thanks DW,
    pS

  18. August 18, 2010 @ 2:22 am

    okay, I have two slideshows on the page now :) – sorry for the sillyness

Be Heard!

Share your thoughts with fellow developers of all skill levels! I want to hear from you!

Name*:
Email*:
Website:  
Wrap your code with <code> tags, f00!