Make your MooTools Code Shorter, Faster, and Stronger

Make your MooTools Code Shorter, Faster, and Stronger

MooTools is one of the most flexible, modular, and well written JavaScript frameworks available. So many people use it but many of them don’t optimize their code. This post will provide you with fifteen simple tips for making your MooTools code shorter, faster, and stronger.

1. Create Your Own MooTools Build or Pull From Google AJAX Libraries

One of the great advantages to using MooTools is that it’s incredibly modular. What does that mean?
Almost nothing is required unless you need it. The advantage of MooTools’ modularity is that your
limited, custom MooTools build can keep your JavaScript load time short.

MooTools Core Builder

Want to create a custom MooTools build for your next project? Follow these steps:

  • Go to http://mootools.net/core (and/or http://mootools.net/more if you’d like additional plugins)
  • Select the plugins of your choosing. Don’t worry about accounting for dependencies — the plugin builder does that for you!
  • Select the compression option of your choosing — the YUI Compressor will provide the you with the smallest possible build of MooTools

That’s it! Sometimes, however, your project requires the entire MooTools Core library. In that case, your website can save itself thousands
of requests per day by using the Google AJAX Libraries complete build of MooTools. You may do this two ways:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js"></script>

This first method simply includes MooTools into the page per normal. The second method allows more functionality and performance:

<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("mootools", "1.2.4"); //older versions also available
</script>

What’s great about using the Google AJAX Libraries API is that if another website uses the AJAX Library API, that version of MooTools is already cached
within their browser and the site will load faster!

2. Use jQuery and MooTools Together

While it’s best to stick to one library in a given page to avoid a bunch of overhead, sometimes you can’t avoid needing multiple frameworks.
Luckily MooTools can coexist with any non-prototype-based JavaScript frameworks. Here’s how you can use jQuery and MooTools in the same page:

<!-- jquery gets the "$" method -->
<script type="text/javascript" src="jquery-1.4.js" />
<!-- mootools doesn't steal the "$" method; instead, document.id will be used -->
<script type="text/javascript" src="mootools.js" />
<!-- lets use them -->
<script type="text/javascript">
//with jquery, grab all links, make then red
$('a').css('color','red');
//with mootools, get the content div, set it's background color to pink
document.id('content').setStyle('background','pink');
//with mootools, get the content div, set it's background color to pink
//this time, we'll give mootools the "$" method
(function($) {
	$('content').setStyle('background','pink');
})(document.id);
</script>

Thanks to MooTools’ Dollar Safe Mode, MooTools no longer assumes the “$” method if it’s already taken!

3. Save Elements and Element Collections

Developers often need to collect one element or a collection of elements. For example, you may need to grab all A elements within the page, change their color, and create tooltips from them.

//grab links, change color */
$$('#footer a').setStyle('color','#f00');
//make links tooltips
var tippers = new Tips($$('#footer a'));

The code above is grossly inefficient. Why query the DOM twice (with $$) if you can collect all of the elements once? Let’s make this more efficient:

//"save" links into a variable
var links = $$('#footer a');
//grab links, change color */
links.setStyle('color','#f00');
//make links tooltips
var tippers = new Tips(links);

You could make this even shorter, but it’s not as readable:

var tippers = new Tips($$('#footer a').setStyle('color','#f00'));

Readability is important, so I wouldn’t recommend coding this way if you work with a team.

4. Use Element Methods on Element Collections

Cycling through an array of elements is not unique to any JavaScript framework:

//for every link...
$$('a').each(function(a) {
	//add link nudging to the element
	a.addEvents({
		mouseenter: function() { //animate to the right
			if(!a.retrieve('oPad')) { a.store('oPad',a.getStyle('padding-left')); }
			a.tween('padding-left',30);
		},
		mouseleave: function() { //animate back to the left
			a.tween('padding-left',a.retrieve('oPad'));
		}
	});
});

What many developers aren’t aware that Element collections have the same methods as Elements,
so there’s no need to cycle through them — simply apply the desired functionality to the collection:

$$('a').addEvents({
	mouseenter: function() { //animate to the right
		if(!this.retrieve('oPad')) { this.store('oPad',this.getStyle('padding-left')); }
		this.tween('padding-left',30);
	},
	mouseleave: function() { //animate back to the left
		this.tween('padding-left',this.retrieve('oPad'));
	}
});

Note that the “this” keyword is used to reference the “current” element within the collection, not the collection itself.

5. Use MooTools Alias

MooTools’ “alias” method allows you to rename or alias an existing method. Take the following snippet of code which is currently in the MooTools Core source:

Array.alias('forEach', 'each');

The above code lets you call the “each” method instead of “forEach”. Using “each” is more readable, a quiet standard between most JavaScript frameworks, and
it even saves you a few bytes in your code. If you prefer to give MooTools’ Native or Class methods a custom name, feel free to!

For example, the Element Class’ method for removing an Element form the DOM is:

$('myElement').dispose();

Suppose your web app is about a given topic and you’d like to stay within that terminology for your code. Here are a few examples:

Element.alias('dispose','can'); //career site?
Element.alias('dispose','shank'); //prison site?

Whatever your reasons are for calling a method by a different name, just don’t be afraid to do so!

6. Create Custom Pseudo Selectors

Accessing a collection of Elements in the DOM is a core responsibility of any JavaScript framework. Unfortunately it can also be taxing and
the pseudo selectors you want aren’t always available. Luckily MooTools allows you to easily implement your own pseudo selectors! Let’s
create a pseudo selector named “disabled” that returns an element if it’s disabled.

//grab disabled elements
Selectors.Pseudo.disabled = function() {
	return this.disabled;
}

//how you use it
var disabledInputs = $$('input:disabled');

Simply add your selector to the Selectors.Pseudo object. If the new pseudo’s function returns “true”, the element is a match and will be returned.

Defining you own pseudo selectors is a great way to take control of your selectors!

7. Implement Methods on Existing Objects

MooTools’ philosophy is that it’s acceptable, even encouraged, to modify Native (String, Function, Number, etc.) prototypes when needed.
Implementing new methods on these Natives will empower them even more. Let’s create a String method that will turn any string of text into
“tweet” format (add links for @reply’s, links, etc.):

String.implement({
	toTweet: function() {
		 return this.replace(/(https?:\/\/\S+)/gi,'<a href="$1">$1</a>').replace(/(^|\s)@(\w+)/g,'$1<a href="http://twitter.com/$2">@$2</a>').replace(/(^|\s)#(\w+)/g,'$1<a href="http://search.twitter.com/search?q=%23$2">#$2</a>');
	}
});

Now you can call “toTweet” on any string and you’ll get the string back as a “tweet”. Here are a few examples:

//set an element's html to a tweet value
var el = $('myElement');
el.set('html',el.get('html').toTweet()); //sets the element's html to a linked, tweet value.

//alert the tweeted value
alert('Yo @NetTuts, check out my #MooTools website: http://davidwalsh.name'.toTweet());
//alerts:  Yo <a href="http://twitter.com/nettuts">@NetTuts</a>, check out my <a href="http://search.twitter.com/search?q=%23MooTools">MooTools</a> website: <a href="http://davidwalsh.name">http://davidwalsh.name</a>

Implementing custom methods on Objects strengthens every existing and future instance of that object.

8. Extend Existing Classes

MooTools’ OOP philosophy allows for a super-powerful inheritance model. Extending existing classes
allows you to avoid repeating code, empower existing objects, and leverage existing functionality.
MooTools Core, More, and your custom classes extend existing functionality. Consider the Request class:

var Request = new Class({

	Implements: [Chain, Events, Options],

	options: {/*
		onRequest: $empty,
		onComplete: $empty,
		onCancel: $empty,
		onSuccess: $empty,
		onFailure: $empty,
		onException: $empty,*/
		url: '',
		data: '',
		headers: {
			'X-Requested-With': 'XMLHttpRequest',
			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
		},
		async: true,
		format: false,
		method: 'post',
		link: 'ignore',
		isSuccess: null,
		emulation: true,
		urlEncoded: true,
		encoding: 'utf-8',
		evalScripts: false,
		evalResponse: false,
		noCache: false
	},

	initialize: function(options){
		this.xhr = new Browser.Request();
		this.setOptions(options);
		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
		this.headers = new Hash(this.options.headers);
	},

	onStateChange: function(){
		if (this.xhr.readyState != 4 || !this.running) return;
		this.running = false;
		this.status = 0;
		$try(function(){
			this.status = this.xhr.status;
		}.bind(this));
		this.xhr.onreadystatechange = $empty;
		if (this.options.isSuccess.call(this, this.status)){
			this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
			this.success(this.response.text, this.response.xml);
		} else {
			this.response = {text: null, xml: null};
			this.failure();
		}
	},

	isSuccess: function(){
		return ((this.status >= 200) && (this.status < 300));
	},

	processScripts: function(text){
		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
		return text.stripScripts(this.options.evalScripts);
	},

	success: function(text, xml){
		this.onSuccess(this.processScripts(text), xml);
	},

	onSuccess: function(){
		this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
	},

	failure: function(){
		this.onFailure();
	},

	onFailure: function(){
		this.fireEvent('complete').fireEvent('failure', this.xhr);
	},

	setHeader: function(name, value){
		this.headers.set(name, value);
		return this;
	},

	getHeader: function(name){
		return $try(function(){
			return this.xhr.getResponseHeader(name);
		}.bind(this));
	},

	check: function(){
		if (!this.running) return true;
		switch (this.options.link){
			case 'cancel': this.cancel(); return true;
			case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
		}
		return false;
	},

	send: function(options){
		if (!this.check(options)) return this;
		this.running = true;

		var type = $type(options);
		if (type == 'string' || type == 'element') options = {data: options};

		var old = this.options;
		options = $extend({data: old.data, url: old.url, method: old.method}, options);
		var data = options.data, url = String(options.url), method = options.method.toLowerCase();

		switch ($type(data)){
			case 'element': data = document.id(data).toQueryString(); break;
			case 'object': case 'hash': data = Hash.toQueryString(data);
		}

		if (this.options.format){
			var format = 'format=' + this.options.format;
			data = (data) ? format + '&' + data : format;
		}

		if (this.options.emulation && !['get', 'post'].contains(method)){
			var _method = '_method=' + method;
			data = (data) ? _method + '&' + data : _method;
			method = 'post';
		}

		if (this.options.urlEncoded && method == 'post'){
			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
			this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
		}

		if (this.options.noCache){
			var noCache = 'noCache=' + new Date().getTime();
			data = (data) ? noCache + '&' + data : noCache;
		}

		var trimPosition = url.lastIndexOf('/');
		if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);

		if (data && method == 'get'){
			url = url + (url.contains('?') ? '&' : '?') + data;
			data = null;
		}

		this.xhr.open(method.toUpperCase(), url, this.options.async);

		this.xhr.onreadystatechange = this.onStateChange.bind(this);

		this.headers.each(function(value, key){
			try {
				this.xhr.setRequestHeader(key, value);
			} catch (e){
				this.fireEvent('exception', [key, value]);
			}
		}, this);

		this.fireEvent('request');
		this.xhr.send(data);
		if (!this.options.async) this.onStateChange();
		return this;
	},

	cancel: function(){
		if (!this.running) return this;
		this.running = false;
		this.xhr.abort();
		this.xhr.onreadystatechange = $empty;
		this.xhr = new Browser.Request();
		this.fireEvent('cancel');
		return this;
	}

});

Then consider Request.JSONP, which extends Request:

Request.JSON = new Class({

	Extends: Request,

	options: {
		secure: true
	},

	initialize: function(options){
		this.parent(options);
		this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
	},

	success: function(text){
		this.response.json = JSON.decode(text, this.options.secure);
		this.onSuccess(this.response.json, text);
	}

});

You see how small the Request.JSONP class is? By adding “Extends: Request”, the Request.JSONP class gets all
of the Request Class’ methods. Essentially, this small snippet of code becomes a powerhouse because it extends
Request. You can even add extensions to extensions. Now consider Request.JSONP and then Scott Kyle’s Request.Twitter
class:

//Request.JSONP
/*
---

script: Request.JSONP.js

description: Defines Request.JSONP, a class for cross domain JavaScript via script injection.

license: MIT-style license

authors:
- Aaron Newton
- Guillermo Rauch

requires:
- core:1.2.4/Element
- core:1.2.4/Request
- /Log

provides: [Request.JSONP]

...
*/

Request.JSONP = new Class({

	Implements: [Chain, Events, Options, Log],

	options: {/*
		onRetry: $empty(intRetries),
		onRequest: $empty(scriptElement),
		onComplete: $empty(data),
		onSuccess: $empty(data),
		onCancel: $empty(),
		log: false,
		*/
		url: '',
		data: {},
		retries: 0,
		timeout: 0,
		link: 'ignore',
		callbackKey: 'callback',
		injectScript: document.head
	},

	initialize: function(options){
		this.setOptions(options);
		if (this.options.log) this.enableLog();
		this.running = false;
		this.requests = 0;
		this.triesRemaining = [];
	},

	check: function(){
		if (!this.running) return true;
		switch (this.options.link){
			case 'cancel': this.cancel(); return true;
			case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
		}
		return false;
	},

	send: function(options){
		if (!$chk(arguments[1]) && !this.check(options)) return this;

		var type = $type(options),
				old = this.options,
				index = $chk(arguments[1]) ? arguments[1] : this.requests++;
		if (type == 'string' || type == 'element') options = {data: options};

		options = $extend({data: old.data, url: old.url}, options);

		if (!$chk(this.triesRemaining[index])) this.triesRemaining[index] = this.options.retries;
		var remaining = this.triesRemaining[index];

		(function(){
			var script = this.getScript(options);
			this.log('JSONP retrieving script with url: ' + script.get('src'));
			this.fireEvent('request', script);
			this.running = true;

			(function(){
				if (remaining){
					this.triesRemaining[index] = remaining - 1;
					if (script){
						script.destroy();
						this.send(options, index).fireEvent('retry', this.triesRemaining[index]);
					}
				} else if(script && this.options.timeout){
					script.destroy();
					this.cancel().fireEvent('failure');
				}
			}).delay(this.options.timeout, this);
		}).delay(Browser.Engine.trident ? 50 : 0, this);
		return this;
	},

	cancel: function(){
		if (!this.running) return this;
		this.running = false;
		this.fireEvent('cancel');
		return this;
	},

	getScript: function(options){
		var index = Request.JSONP.counter,
				data;
		Request.JSONP.counter++;

		switch ($type(options.data)){
			case 'element': data = document.id(options.data).toQueryString(); break;
			case 'object': case 'hash': data = Hash.toQueryString(options.data);
		}

		var src = options.url +
			 (options.url.test('\\?') ? '&' :'?') +
			 (options.callbackKey || this.options.callbackKey) +
			 '=Request.JSONP.request_map.request_'+ index +
			 (data ? '&' + data : '');
		if (src.length > 2083) this.log('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs');

		var script = new Element('script', {type: 'text/javascript', src: src});
		Request.JSONP.request_map['request_' + index] = function(){ this.success(arguments, script); }.bind(this);
		return script.inject(this.options.injectScript);
	},

	success: function(args, script){
		if (script) script.destroy();
		this.running = false;
		this.log('JSONP successfully retrieved: ', args);
		this.fireEvent('complete', args).fireEvent('success', args).callChain();
	}

});

Request.JSONP.counter = 0;
Request.JSONP.request_map = {};

…and now Request.Twitter:

Request.Twitter = new Class({

	Extends: Request.JSONP,

	options: {
	  linkify: true,
	  url: 'http://twitter.com/statuses/user_timeline/{term}.json',
	  data: {
	    count: 5
	  }
	},

	initialize: function(term, options){
	  this.parent(options);
	  this.options.url = this.options.url.substitute({term: term});
	},

	success: function(data, script){
	  if (this.options.linkify) data.each(function(tweet){
	    tweet.text = this.linkify(tweet.text);
	  }, this);

	  // keep subsequent calls newer
	  if (data[0]) this.options.data.since_id = data[0].id;

	  this.parent(data, script);
	},

	linkify: function(text){
	  // modified from TwitterGitter by David Walsh (davidwalsh.name)
	  // courtesy of Jeremy Parrish (rrish.org)
	  return text.replace(/(https?:\/\/[\w\-:;?&=+.%#\/]+)/gi, '<a href="$1">$1</a>')
	             .replace(/(^|\W)@(\w+)/g, '$1<a href="http://twitter.com/$2">@$2</a>')
	             .replace(/(^|\W)#(\w+)/g, '$1#<a href="http://search.twitter.com/search?q=%23$2">$2</a>');
	}

});

You see how a waterfall effect of extending objects can make the smallest of classes an absolute beast of a class?
Experiment with MooTools’ inheritance model and don’t repeat code!

9. Create Custom Events

I’ve already explained how flexible the MooTools selector engine is, the class system is, and how modular the framework is.
Why would you expect anything different from MooTools’ event system? Creating custom events within MooTools is as simple
as it gets. Here’s a basic outline of your MooTools custom event:

Element.Events.altClick = {
	base: 'click', //the "base" event
	condition: function(event) {
		return event.alt; // alt key?
	},
	onAdd: function() {
		//do something when the event is added
	},
	onRemove: function() {
		//do something when the event is removed
	}
};

Here’s a great example of a custom event — listening for “alt” and “click” at the same time:

//alt click
Element.Events.altClick = {
	base: 'click',
	condition: function(event) {
		return event.alt; // alt key?
	}
};

//usage
$(document.body).addEvent('altClick',function() {
	alert('You alt-clicked me!');
});

Or you can simply define a custom event so that a specific function executes any time that type of event is assigned.
In my next example, any time a click event is assigned to an element, that element’s cursor will be automatically changed
to the “pointer” cursor.

/* update cursor on add/remove click event */
Element.Events.click = {
	base:'click',
	onAdd: function() {
		if(this.setStyle) {
			this.store('original-cursor',this.getStyle('cursor'));
			this.setStyle('cursor','pointer');
		}
	},
	onRemove: function() {
		if(this.setStyle) {
			this.setStyle('cursor',this.retrieve('original-cursor'));
		}
	}
};

You’ll notice that if the click event is removed, the original cursor will be restored.

10. jQuery-Style Events

While the MooTools event sytax is different from jQuery’s, it doesn’t have to be! With a minimal amount of
javascript you can make MooTools’ event syntax reflect jQuery’s.

MooTools holds all of its events in the Element.NativeElements object:

Element.NativeEvents = {
	click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
	mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
	mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
	keydown: 2, keypress: 2, keyup: 2, //keyboard
	focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
	load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
	error: 1, abort: 1, scroll: 1 //misc
};

Essentially all you need to do is cycle through each element type and implement a method on the Element class, named like the event type,
that simulates what addEvent does:

//hash the element.natives so you can do stuff with it
var hash = new Hash(Element.NativeEvents);
//remove items that need to be replaced, add their replacements
hash.erase('mouseover').erase('mouseout').erase('DOMMouseScroll');
hash.include('mouseenter',1).include('mouseleave',1);
//initialize this
var eventHash = new Hash({});
//for every event type, add to the hash
hash.getKeys().each(function(event){
	eventHash[event] = function(fn) {
		this.addEvent(event,fn);
		return this;
	};
});
//make it happen
Element.implement(eventHash);

Now you can listen for events like:

$('myElement').click(function() {
	//do stuff
});

11. Add Events During Element Creation

If you have experience coding with MooTools, at some point you’ve no doubt created an element and subsequently added events to it:

var myElement = new Element('a',{
	href: 'mypage.php',
	text: 'Click here!'
});

myElement.addEvent('click',function(e) {
	//stop the event
	if(e) e.stop();
	//do stuff
});

There’s nothing wrong with the above, per say, but you could just add those events during element creation:

var myElement = new Element('a',{
	href: 'mypage.php',
	text: 'Click here!',
	events: {
		click: function() {
			//stop the event
			if(e) e.stop();
			//do stuff
		}
	}
});

12. Implement Events Within Classes

Extending classes was discussed in tip #8 above. Now lets explore the *implement* functionality within MooTools classes.
What’s the difference? MooTools contributor Mark Obcena says it best in his article titled
Up The Moo Herd IV: There’s A Class For This:

MooTools has two built-in mutators: Extends and Implements. The Extends mutator takes the class name passed on to it and makes the new class inherit directly from it, while Implements takes the class (or classes) passed and adds their methods to the new class (or mixes them in—thus mixin).

With the difference between extending and implementing, lets get back to it. Implementing events within your MooTools classes
can make your classes much more flexible. Consider the following simple Overlay class:

var Overlay = new Class({

	Implements: [Options,Events],

	options:  {
		id: 'overlay',
		color: '#000',
		duration: 500,
		opacity: 0.5,
		zIndex: 5000
	},

	initialize: function(container,options) {
		this.setOptions(options);
		this.container = document.id(container);
		this.overlay = new Element('div',{
			id: this.options.id,
			opacity: 0,
			styles: {
				position: 'absolute',
				background: this.options.color,
				left: 0,
				top: 0,
				'z-index': this.options.zIndex
			},
		}).inject(this.container);
		this.tween = new Fx.Tween(this.overlay,{
			duration: this.options.duration,
			link: 'cancel',
			property: 'opacity',
			onStart: function() {
				this.overlay.setStyles({
					width: '100%',
					height: this.container.getScrollSize().y
				});
			}.bind(this)
		});
	},
	open: function() {
		this.tween.start(this.options.opacity);
		return this;
	},
	close: function() {
		this.tween.start(0);
		return this;
	}
});

Sure the class does what it’s supposed to but it isn’t nearly as flexible it could be. Now lets implement
onClick, onClose, onHide, onOpen, and onShow events:

var Overlay = new Class({

	Implements: [Options,Events],  // EVENTS IMPLEMENTED HERE!

	options:  {
		id: 'overlay',
		color: '#000',
		duration: 500,
		opacity: 0.5,
		zIndex: 5000/*,
		onClick: $empty,
		onClose: $empty,
		onHide: $empty,
		onOpen: $empty,
		onShow: $empty
		*/
	},

	initialize: function(container,options) {
		this.setOptions(options);
		this.container = document.id(container);
		this.overlay = new Element('div',{
			id: this.options.id,
			opacity: 0,
			styles: {
				position: 'absolute',
				background: this.options.color,
				left: 0,
				top: 0,
				'z-index': this.options.zIndex
			},
			events: {
				click: function() {    // CLICK EVENT
					this.fireEvent('click');
				}.bind(this)
			}
		}).inject(this.container);
		this.tween = new Fx.Tween(this.overlay,{
			duration: this.options.duration,
			link: 'cancel',
			property: 'opacity',
			onStart: function() {
				this.overlay.setStyles({
					width: '100%',
					height: this.container.getScrollSize().y
				});
			}.bind(this),
			onComplete: function() {
				this.fireEvent(this.overlay.get('opacity') == this.options.opacity ? 'show' : 'hide');  // SHOW OR HIDE EVENT
			}.bind(this)
		});
	},
	open: function() {
		this.fireEvent('open');  // OPEN EVENT
		this.tween.start(this.options.opacity);
		return this;
	},
	close: function() {
		this.fireEvent('close');  // CLOSE EVENT
		this.tween.start(0);
		return this;
	}
});

What’s great about adding events to a class is that events allow your to give more options and trigger functionality when
our class methods execute. In the above example, you can execute any functionality when the overlay opens, closes, shows, hides, or gets clicked.
Essentially you added two tiny snippets of code to the class:

Implements: [Events]

…and the following wherever you’d like an event to be signaled…

this.fireEvent('someEvent',[argument1, argument2]);

So how can you control these events when you create an instance of the class? Add them in the options like this:

var overlay = new Overlay({
	onClick: function() {
		this.hide();
	},
	onOpen: function() {
		alert('Thank you for opening!');
	}
});

You’d be hard pressed to find a class that wouldn’t benefit from implementing events!

13. Use Event Delegation

Event delegation is the process of adding an event to a parent for all of its children instead of assigning the
event to each individual child. The advantage of event delegation is that you may add child elements to the
parent element without needing to assign the event to that new element. If you choose to remove the event,
you need only remove it from one element.

So, instead of:

$$('a').addEvent('click',function() {
	//do stuff -- individually assigned
});

…you do this:

$('myContainer').addEvent('click:relay(a)',function() {
	//assigned to the parent of all A elements (in this case, #myContainer), to listen to A element click event
})/

Don’t let the “:relay()” pseudo-syntax fool you; Element.Delegation rewrites the event methods to accommodate for :relay.

14. Use Class.toElement

One hidden gem within MooTools’ Class is the Class.toElement method. Class.toElement plays a small role but can help you out
when it comes to accessing the primary element within a class, especially if you don’t know what that element is otherwise.
Implementing toElement on your class is easy:

var myClass = new Class({

	Implements: [Options],

	initialize: function(container,options) {
		this.container = $(container);
	},

	toElement: function() {
		return this.container;
	}
});

Once you have toElement defined, you can use your class just like an element:

var myInstance = new MyClass('myElement');
myInstance.setStyle('color','#f00').set('html','This is my element!');

Look at that — a class virtually manipulated by Element methods.

15. “return this” Within Methods For Chainability

So we’ve all seen how the JavaScript frameworks allow you to chain the hell out of methods. Chaining looks like this:

$('myElement').setStyles('color','#f00').set('html','Click Here').fade('out').addClass('cssClass').addEvent('click',function(e) {
	if(e) e.stop();
	alert('Clicked'!);
});

Holy chaining Batman! Want your classes to chain forever? No problem — all you need to do is return “this”:

var myClass = new Class({

	//options, initialize, implements, etc.

	doSomething: function() {
		//do a whole bunch of functionality here and...
		return this;
	},
	doAnotherThing: function() {
		//do a whole bunch of functionality here and...
		return this;
	},
	doYetAnotherThing: function() {
		//do a whole bunch of functionality here and...
		return this.
	}
});

Since you placed “return this” in each method, now you can do:

var klass = new myClass();
klass.doSomething().doAnotherThing().doYetAnotherThing();

Make sure to return “this” wherever it makes sense. Doing so can make your Class much easier to work with and your code will be shorter!

BONUS! 16. Use Fx Shortcuts on Elements

MooTools effects are unarguably the smoothest of any JavaScript framework. The Fx library also provides loads of control through numerous options.
Lets take a look at a basic Tween which fades an element to 50%:

var myTween = new Fx.Tween('myElement',{
	duration: 500,
	fps: 200,
	//a bunch of options here
});
//fade to 50%
$('myElement').addEvent('click',function() {
	myTween.start('opacity',0.5);
});

Did you know you didn’t need to type out all of this? You could use element shortcuts like:

$('myElement').fade(0.5); //fading: Fx.Tween
$('myElement').tween('width',300); //tweening: Fx.Tween
$('myElement').morph({
	width: 200,
	height: 300
}); //morph:  Fx.Morph

The above snippets, of course, rely on you wanting to use the default options. You can actually set custom options for these shortcut methods per element:

$('myElement').set('tween',{ duration:500, fps: 200 }).tween('width',300);

Save your self a few bytes by using Fx shortcuts!

MooTools FTW!

Hopefully I’ve given you some tips to improve your MooTools JavaScript code, making it shorter, faster, and stronger. Have some of your own tips to share?
Place them in the comments below!



Ebook Rewriting

Ebook Rewriting
I have few ebooks in pdf format. I want to re write those ebooks ( WITH ATTRACTIVE TITLE) and link with my affilate urls. rewriting can be very simple and minor ( to cut the cost ) . main point is to remove the links, remove the copyright present and include my affiliate links ( whereever present).

PLease reply with experience and cost per page, so that I can workout how many ebooks I want to rewrite. I have around 5 ebooks ranging from 25 pages to 50 pages.

Flippa Clone Needed

Flippa Clone Needed
Looking for a unique Flippa Clone installed. Please visit flippa.com to get an idea of what I am looking for.

This project is from beginning to end with long term relationship possible. I know very little about programming and will need ongoing support as business grows.

Project/Site must haves:

Must be able to assist with design logo
site must have area for blog/forum
site must have search tool
site must be able to sort most viewed and complete auctions
would love for site to pull 3rd party info ie Alexa
site must be able to charge listing fee which I can edit

My initial budget is not large but the opportunity for future work is great. Will pay at completion of the project once site is reviewed and installed.

Music Download Site

Music Download Site
i want a site that can have
music downloads
ipod movies downloads
make music into ring tones
and send them to friends
were you can listen to the music for free and have the option to pay membership for downloads
adjust player to a custome size
and install payment system i already have site were i want to integrate all of this here is a example of how i want the music section to look
http://demo.componentone.com//Silverlight/SilverTunes/
i already have this site http://newmoviereleases-online.com/

will escrow 20% before you start (if you have no feed back don’t bid)

Send Mail Using Php Over Tls

Send Mail Using Php Over Tls
Hi, I have some PHP code which sends mail via SMTP. It has worked in the past, but our new provider requires TLS when sending:

http://blogs.technet.com/msonline/archive/2009/09/02/using-smtp-relay-with-exchange-online.aspx

I’ve filled out all the variables in the script, with the exception of the correct password. I will provide that upon request.

I’d basically like someone to modify the existing attached script so that it can use TLS and work with our new provider.

Pap4-wishlist Member -paypal

Pap4-wishlist Member -paypal
I currently have a membership site whose main engine is WishList Member (a WordPress plugin).

I did not have a built-in affiliate program/script, so I purchased/acquired Post Affiliate Pro 4 (PAP4)

WishList Member has the ability to integrate with PayPal for payment processing, as does PAP4.

Whenever a purchase is made via the PayPal button on my site, two things need to happen:

1) The sale needs to be tracked via PAP4
2) The purchaser should be auto-redirected to a WishList Member generated page that enables him/her to complete their membership/signup process

Currently, only #2 (above) is working properly.

I have spent numerous hours trying to figure it out on my own. PAP4 support has been responsive. However, WishList Member will not support any coding issues/needs due to “lack of time”.

Where things are now:
PAP4 support has indicated that some curl code needs to be added to the “thank you” page (one that is specified via the PayPal form code as specified via the “return” or “notify_url” input field). However, this URL does not point to a specific page, exactly.
Here is the URL in question:
http://tweetperformance.com/main/index.php/register/BZajxy

No page or folder exists by the name “register” or “BZajxy” on the server … so I assume that index.php is somehow processing “/register/BZajxy”. The URL is required exactly as shown by Wishlist Member, as it is tied to PayPal. The programmer chosen for this project must be able to determine exactly where (which php file on the server) to place the aforementioned curl code.

The requirements for the programmer of this project are:
1) Must have intimate knowledge of integrating PayPal w/ PAP4
2) Must have intimate knowledge of integrating PayPal w/ WishList Member
3) Must understand PHP and callbacks

I do not wish (nor intend) to spend any time training with respect to the specifics of integrating the 3 pieces (PAP4, WLM & PayPal)

The project will be deemed “complete” once PAP4 is properly tracking sales, AND the proper WishList Member registration form is being displayed (redirected to) upon successful PayPal transaction.

Joomla Fix

Joomla Fix
We need a good Joomla programmer to fix a module on a live site. We would also like to use this person to work on the site in the future to maintian and install new modules. The work need to be done immediatley. Shouldn’t take more than a few minutes for an experienced programmer.

Translation Of Site Texts

Translation Of Site Texts
We want to translate the content of one of our websites to several European languages. The total number of words is 524. The full text is supplied in English and will be in a flat text document. There is no need to change text formatting etc. The text should be translated to a number of European languages from the list at the end of this description. Please keep in mind that we don’t accept machine translations. These are easy to recognize. We further won’t accept offers from people who don’t speak the destination language as a mother tongue. It should therefore be obvious that offers from countries outside Europe won’t be considered as serious offers.

Please bid per language, and indicate in your bid which language is your specialism. Just to make sure that you fully understood this text, please include in your response in your local language the name of the local dish you most like from your country.

The language list:
German, French, Polish, Hungarian, Croatian (Latin), Serbian (Cyrillic), Romanian, Russian, Ukrainian, Bulgarian, Czech, Danish, Swedish, Finnish, Spanish, Norwegian

Paintball Website

Paintball Website
I need a website that people can purchase paintball gear. I need the store designed, and a checkout feature. I’m working with a company to install a credit card “terminal” … but I may need some help installing that into the site as well.

I’m also working with a company to provide the merchandise that the order will be sent to. The list of items will be availble (with pictures) a little later, but right now I need to focus on getting someone to build the site.

It must have a design that has a little attitude and sport’ish. I’m thinking of using black, white, and blue colors in the site.

I’m only listing the auction for a week, so hurry and bid! 🙂

Future changes may be needed, and I’ll contact the same person who builds this site for me to do the job. I’ll also pay them for the new work also.

Form Submission Script Fix

Form Submission Script Fix
I Have a PHP script that uses libCurl to submit the POST variables to another PHP script on a remote server. The script on the remote server is suppose to redirect to specified url through PHP header location but I’m having a problem with that. So I need the scripts fixed to properly redirect after the form is submited or another set of scripts that do the same.