Extending Element With Your MooTools Class Is Awesome

By Ryan Florence, published 2010-03-16

Part of the issue Migrated Articles From Original Site Structure..

Almost every class that is centered around an element deserves a few element shortcuts. You’ve used them plenty of times already but maybe you haven’t written one. Here’s what I’m talking about.

var el = $('myelement');
// element shortcuts
el.fade('in'); // Fx.Tween
el.load('something_impressive.html'); // Request.HTML
el.makeDraggable(); // Drag.Move

I think the best way to do it is the way that Fx.Tween does it–and just about all the other -core and -more scripts that deal with an element–which is two-fold:

  1. Create element properties for your class
  2. Define element extensions

You can skip number 1 if you want and just do:

Element.implement({
	beAwesome: function(options){
	  return this.store('awesome', new AwesomeClass(this, options));
	}
});
// usage
$('element').beAwesome(options);

But you may get more mileage by using step 1.

Create element properties for your class

Element.Properties is what makes el.set('whatever', arg) possible. Let’s use Tween as an example. In order to be able to make el.set('tween', options) available we have to create the element property tween with a setter and getter.

Element.Properties.tween = {
  
	set: function(options){
		var tween = this.retrieve('tween');
		if (tween) tween.cancel();
		return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
	},
  
	get: function(options){
		if (options || !this.retrieve('tween')){
			if (options || !this.retrieve('tween:options')) this.set('tween', options);
			this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
		}
		return this.retrieve('tween');
	}
  
};

I’ll let you check the MooTools docs for the stuff inside there that’s unfamiliar. Essentially it lets you set options for an instance of Fx.Tween on your element, and get the instance if you need if for something–something like an element shortcut for your class!

These methods, called “getters” and “setters”, make it easy to extend Element. Fx.Tween adds a few element methods: tween, fade, and highlight. I’m going to list them all here but split them up to talk a bit.

Element.implement({
  
	tween: function(property, from, to){
		this.get('tween').start(arguments);
		return this;
	},
	// ...

See how simple it becomes once you define the Element.Properties? When you do $('el').tween('height', 300) it only takes one line of code in the method above to make it all happen. Next up is fade.

  // ...
	fade: function(how){
		var fade = this.get('tween'), o = 'opacity', toggle;
		how = $pick(how, 'toggle');
		switch (how){
			case 'in': fade.start(o, 1); break;
			case 'out': fade.start(o, 0); break;
			case 'show': fade.set(o, 1); break;
			case 'hide': fade.set(o, 0); break;
			case 'toggle':
				var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
				fade.start(o, (flag) ? 0 : 1);
				this.store('fade:flag', !flag);
				toggle = true;
			break;
			default: fade.start(o, arguments);
		}
		if (!toggle) this.eliminate('fade:flag');
		return this;
	},
	// ...

This looks bigger than it is. It simply gets the tween from the element (just like before), sets the property to tween as opacity, and then decides how to fade it with the switch statement. If it weren’t for toggle this block would only be 10 or 11 lines long. Pretty awesome. Next is highlight.

  // ...
	highlight: function(start, end){
		if (!end){
			end = this.retrieve('highlight:original', this.getStyle('background-color'));
			end = (end == 'transparent') ? '#fff' : end;
		}
		var tween = this.get('tween');
		tween.start('background-color', start || '#ffff88', end).chain(function(){
			this.setStyle('background-color', this.retrieve('highlight:original'));
			tween.callChain();
		}.bind(this));
		return this;
	}
	
});

If you didn’t know, el.highlight flashes the background color of an element. This is the most complicated of the three for sure because it has to store the original background color or pick a default (#ffff88) and then clean up camp by putting things back to how they were before. However, it’s still a very basic script that’s easy to implement because Fx.Tween has all the logic for animating a property, and Element.properties.tween has all the logic for setting and getting a tween instance for an element. All that’s left to do is come up with a few useful shortcuts and implement them.

Here’s an idea, $('el').grow(100).

Element.implement({
  grow: function(amount){
    var tween = this.get('tween');
    var to = this.getSize().y + amount.toInt();
    tween.start('height', to);
    return this;
  }
});

Here’s some homework, edit the example below to include a shrink method.

Now find one of your classes that is centered around an element and create some element shortcuts.

Hi, I'm Ryan!

Location:
South Jordan, UT
Github:
rpflorence
Twitter:
ryanflorence
Freenode:
rpflo

About Me

I'm a front-end web developer from Salt Lake City, Utah and have been creating websites since the early 90's. I like making awesome user experiences and leaving behind maintainable code. I'm active in the JavaScript community writing plugins, contributing to popular JavaScript libraries, speaking at conferences & meet-ups, and writing about it on the web. I work as the JavaScript guy at Instructure.