Extending MooTools

Exclusive offer: get 50% off this eBook here
MooTools 1.3 Cookbook

MooTools 1.3 Cookbook — Save 50%

Over 110 highly effective recipes to turbo-charge the user interface of any web-enabled Internet application and web page

$26.99    $13.50
by Jay Larry G. Johnston | July 2011 | Open Source

MooTools, an extensible JavaScript library, begins with a base Class and then Implements and Extends classes into useful and reusable objects.

Implement the recipes in this article by Jay Larry G. Johnston, author of MooTools 1.3 Cookbook, to extend what MooTools can do for you:

  • Working directly with the base class, Class
  • Extending and implementing MooTools classes

 

MooTools 1.3 Cookbook

MooTools 1.3 Cookbook

Over 100 highly effective recipes to turbo-charge the user interface of any web-enabled Internet application and web page

        Read more about this book      

(For more resources on this topic, see here.)

The reader can benefit from the previous article on MooTools: Extending and Implementing Elements.

 

Making a Corvette out of a car-extending the base class

The "base class" is a function, a method, that allows extension. Just what does extending a class entail? Buckle up and let us take a drive.

Getting ready

Just to show the output of our work, create a DIV that will be our canvas.

<div id="mycanvas"></div>

How to do it...

Creating a class from the base class is as rudimentary as this: var Car = new Class();. That is not very instructive, so at the least, we add the constructor method to call at the time of instantiation: initialize.

<script type="text/javascript">
var Car = new Class({
initialize: function(owner) {
this.owner = owner;
}
});

The constructor method takes the form of a property named initialize and must be a function; however, it does not have to be the first property declared in the class.

How it works...

So far in our recipe, we have created an instance of the base class and assigned it to the variable Car. We like things to be sporty, of course. Let's mutate the Car into a Corvette using Extends and passing it the name of the Class to make a copy of and extend into a new class.

var Corvette = new Class({
Extends: Car,
mfg: 'Chevrolet',
model: 'Corvette',
setColor: function(color) {
this.color = color;
}
});

Our Corvette is ready for purchase. An instantiation of the extended class will provide some new owner happiness for 5 years or 50,000 miles, whichever comes first. Make the author's red, please.

var little_red = new Corvette('Jay Johnston');
little_red.setColor('red');
$('mycanvas').set('text',little_red.owner+"'s little
"+little_red.color+' '+little_red.model+' made by
'+little_red.mfg);
</script>

There's more...

This entire example will work identically if Corvette Implements rather than Extends Car.

Whether to Extend or to Implement
Extending a class changes the prototype, creating a copy in which the this.parent property allows for the overridden parent class method to be referenced within the extended class's current method.
To derive a mutation that takes class properties from multiple classes, we use Implements.

Be sure to place the Extends or Implements property first before all other methods and properties. And if both extending and implementing, the Implements property follows the Extends property.

See also

See how Moo can muster so much class: http://mootools.net/docs/core/Class/Class#Class.

 

Giving a Corvette a supercharger-Implements versus Extends

Be ready to watch for several things in this recipe. Firstly, note how the extended corvette methods can use this.parent. Secondly, note how the implemented corvette, the ZR1, can implement multiple classes.

Getting ready

Create a canvas to display some output.

<h1>Speed Indexes:</h1>
<div id="mycanvas"></div>

How to do it...

Here we create a class to represent a car. This car does not have an engine until it goes through further steps of manufacturing, so if we ask what its speed is, the output is zero. Next, we create a class to represent a sporty engine, which has an arbitrary speed index of 10.

// create two classes from the base Class
var Car = new Class({
showSpeed: function() { return 0; }
});
var SportyEngine = new Class({
speed: 10
});

Now we get to work. First, we begin by manufacturing corvettes, a process which is the extension of Car, they are faster than an empty chassis, of course, so we have them report their speed as an index rating one more than the parent class.

// Extend one, Implement the other
var Corvette = new Class({
Extends: Car,
showSpeed: function() {
// this.parent calls the overridden class
return this.parent()+1;
}
});

Secondly, we implement both Car and SportyEngine simultaneously as ZR1. We cannot use this.parent so we return the speed if asked. Of course, the ZR1 would not have a speed if only a mutation of Car, but since it is also a mutation of SportyEngine it has the speed index of that class.

var ZR1 = new Class({
// multiple classes may be implemented
Implements: [Car, SportyEngine], // yep
showSpeed: function() {
// this.parent is not available
//return this.parent()+1; // nope
return this.speed;
}
});

How it works...

When an instantiation of Corvette is created and its showSpeed() method called, it reports the speed of the parent class, Car, adding 1 to it. This is thanks to the magic Extends provides via this.parent().

var corvette = new Corvette();
var zr1 = new ZR1();

$('mycanvas').set('html',
'<table>'+
'<tr><th>Corvette:</th>'+
'<td>'+corvette.showSpeed()+'</td></tr>'+
'<tr><th>ZR1:</th>'+
'<td>'+zr1.showSpeed()+'</td></tr>'+
'</table>');

And so, the output of this would be:

Corvette: 1

ZR1: 10

An instantiation of ZR1 has the properties of all classes passed to Implements. When showSpeed() is called, the value conjured by this.speed comes from the property defined within SportyEngine.

 

Upgrading some Corvettes—Extends versus Implements

Now that we have reviewed some of the reasons to extend versus implement, we are ready to examine more closely how inheritance within Extends can be useful in our scripting.

Getting ready

Create a display area for the output of our manufacturing plant.

<h1>Speeds Before</h1>
<div id="before"></div>

<h1>Speeds After</h1>
<div id="after"></div>

How to do it...

Create two classes, one that represents all car chassis with no engine and one that represents a fast engine that can be ordered as an upgrade. This section is identical to the last recipe; if necessary, review once more before continuing as the jist will be to alter our instantiations to display how inheritance patterns affect them.

// create two classes from the base Class
var Car = new Class({
showSpeed: function() { return 0; }
});
var SportyEngine = new Class({
speed: 10
});

// Extend one, Implement the other
var Corvette = new Class({
Extends: Car,
speed: 1,
showSpeed: function() {
// this.parent calls the overridden class
return this.parent()+1;
}
});
var ZR1 = new Class({
// multiple classes may be implemented
Implements: [Car, SportyEngine], // yep
showSpeed: function() {
// this.parent is not available
//return this.parent()+1; // nope
return this.speed;
}
});

Note that the output before mutation is identical to the end of the previous recipe.

var corvette = new Corvette();
var zr1 = new ZR1();

$('before').set('html',
'<table>'+
'<tr><th>Corvette:</th>'+
'<td>'+corvette.showSpeed()+'</td></tr>'+
'<tr><th>ZR1</th>'+
'<td>'+zr1.showSpeed()+'</td></tr>'+
'</table>');

Here is what happens when the manufacturing plant decides to start putting engines in the base car chassis. That gives them a speed, where they did not have one previously. Mutate the base class by having it return an index of five rather than zero.

// the mfg changes base Car speed to be +5 faster
Car = Car.implement({
showSpeed: function() {
return 5;
}
});

// but SportyEngine doesn't use the parent method
$('after').set('html',
'<table>'+
'<tr><th>New Corvette:</th>'+
'<td>'+corvette.showSpeed()+'</td></tr>'+
'<tr><th>New ZR1</th>'+
'<td>'+zr1.showSpeed()+'</td></tr>'+
'</table>');

How it works...

The zr1 instantiation did not mutate. The corvette instantiation did. Since zr1 used implements, there is no inheritance that lets it call the parent method.

In our example, this makes perfect sense. The base chassis comes with an engine rated with a speed of five. The ZR1 model, during manufacturing/instantiation is given a completely different engine/a completely different property, so any change/recall of the original chassis would not be applicable to that model.

For the naysayer, the next recipe shows how to effect a manufacturer recall that will alter all Corvettes, even the ZR1s.

There's more...

There is an interesting syntax used to mutate the new version of Car, Class.implement(). That same syntax is not available to extend elements.

See also

Here is a link to the MooTool documentation for Class.implement(): http://mootools.net/docs/core/Class/Class#Class:implement.

 

MooTools 1.3 Cookbook Over 110 highly effective recipes to turbo-charge the user interface of any web-enabled Internet application and web page
Published: July 2011
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

 

        Read more about this book      

(For more resources on this topic, see here.)

Upgrading all Corvettes via recall-Implement AND Extend in unison!

But wait, we can do even more with Implements and Extends! Prepare to see them used simultaneously.

Getting ready

Starting off from where our last recipe left off will get us ready.

<h1>Speeds Before</h1>
<div id="before"></div>
<h1>Speeds After</h1>
<div id="after"></div>

// create two classes from the base Class
var Car = new Class({
showSpeed: function() { return 0; }
});
var SportyEngine = new Class({
speed: 10,
showSpeed: function() { return this.speed; }
});

// Extend one, Implement the other
var Corvette = new Class({
Extends: Car,
speed: 1,
showSpeed: function() {
// this.parent calls the overridden class
return this.parent()+1;
}
});

How to do it...

In this example, we want to not only speed up the 'vettes that have the base chassis, but also the ones with the sportier engine. To do this we must implement SportyEngine while extending Car, so that the speed can still cascade up from that base class.

var ZR1 = new Class({
// multiple classes may be implemented
//Implements: [Car, SportyEngine], // nope
Extends: Car, // yep
Implements: SportyEngine, // yep
showSpeed: function() {
// this.parent is not available
//return this.parent()+1; // nope
return this.speed+1;
}
});

var corvette = new Corvette();
var zr1 = new ZR1();

$('before').set('html',
'<table><tr><th>Corvette:</th>'+
'<td>'+corvette.showSpeed()+'</td></tr>'+
'<tr><th>ZR1</th><td>'+zr1.showSpeed()+'</td></tr>'+
'</table>');

How it works...

Much like a manufacturer recall, the effort to improve the product is contingent upon the user bringing their vehicle in to receive the service. Implement into Car a method that provides the upgrade in speed, and then upgrade both of our mutated Car instances.

// the mfg now recalls *all* cars to be +5 faster
Car = Car.implement({
upGrade: function() { this.speed+=5; },
showSpeed: function() { return 5; }
});
corvette.upGrade();
zr1.upGrade();

And after the upgrade occurs, both the sportier engine, and the base corvette are an index of five faster than previously.

$('after').set('html',
'<table>'+
'<tr><th>New Corvette:</th>'+
'<td>'+corvette.showSpeed()+'</td></tr>'+
'<tr><th>New ZR1</th>'+
'<td>'+zr1.showSpeed()+'</td></tr>'+
'</table>');

MooTools 1.3 Cookbook

 

Sending a Corvette on a list of errands-extending a class with a chain

Getting ready

Create a canvas where the tasks completed can be written and a trigger to fire each task.

<h1>Taskinator:</h1>
<form action="" method="get">
<input type="button" value="Do Next Task!" id="taskinator"/>
</form>
<h1>Items Done:</h1>
<div id="itemsdone"></div>

How to do it...

  1. Implement the chain
  2. Load the chain with actions
  3. Fire off the actions in the chain

Follow these steps:

  1. Create a class that implements Chain with a method that will append a new action to the class's internal chain:

    var Corvette = new Class({
    Implements: Chain,
    addTask: function(task) {
    this.chain(function(){
    $('itemsdone').set('html',$('itemsdone').
    get('html')+'<br/>'+task);
    if (this.$chain.length<1) $('taskinator').fade('out');
    });
    }
    });

  2. After creating an instantiation of the class, send an array of tasks to the chain to load up the action list that our trigger will fire:

    var little_red = new Corvette();
    // create a list of todo's to put in the chain
    Array.each([
    'drive to work',
    'drive to lunch',
    'drive back to work',
    'drive home',
    'drive to church',
    'drive back home',
    'sleep in the garage'
    ], function(el) {
    little_red.addTask(el);
    });

  3. The trigger is fired by Element.addEvent(), which listens for the onClick event and subsequently runs little_red.callChain():

    // create a trigger to execute each task
    $('taskinator').addEvent('click',function() {
    little_red.callChain();
    });

How it works...

An internal set of actions is stored in an array-like format within the internal storage mechanism $chain. We can use the raw length of that storage mechanism to determine how many actions remain.

There's more...

MooTools Element has a method, Element.appendText(), that will allow us to append text to the top or bottom of an element node, or before or after the element node. What we need here is appendHTML, but that does not exist yet. Could we extend MooTools Element Class to handle that for us?

var Element = Element.implement({
appendHTML: function(html) {
var existing_html = this.get('html');
this.set('html',existing_html+html);
}
});

Ha ha! MooTools, makes it easy! Now our code is even more legible.

var Corvette = new Class({
Implements: Chain,
addTask: function(task) {
this.chain(function(){
$('itemsdone').appendHTML('<br/>'+task);
if (this.$chain.length<1) $('taskinator').fade('out');
});
}
});

 

Loading Google fonts!

The world is a-buzz with the excitement of every designer on the planet. Finally, we can use something other than Arial, Helvetica, and Verdana!

Get ready

Produce some markup that we can use to apply our Google fonting to.

<h1 style="font-family:'Miltonian'">Hello, my fine world</h1>
<h2 style="font-family:'UnifrakturMaguntia'">World, you are
fine indeed</h2>

The styling using font-family does not have to be inline. Using it within the stylesheet is perfectly acceptable. All information in Google's documentation for the font library stands; our extended class will only abstract and simplify the loading of the fonts.

How to do it...

The embed code for Google Fonts is pretty straightforward. Still, in an effort to make it simple even for non-technical designers, reduce the instantiation to a mere:

new GWFLoader({fontcsv: 'Miltonian,UnifrakturMaguntia' });

In order to pass the options and deep set them, extend the Options class in MooTools. That way we can pass in the comma-separated list of fonts that we wish to load from Google's library.

var GWFLoader = new Class({
Implements: Options,
options: { fontcsv: '' },
initialize: function(options) {
this.setOptions(options);

The next step to take while still in the constructor is to explode the CSV of fonts and validate them. A free, JSON service that returns a list of valid fonts exists at http://jayjohnston.com/google_font_directory.php.

this.fonts = this.options.fontcsv.split(',');
new Element('script',{ src: 'http://jayjohnston.com/
google_font_directory.php?callback=GWFLoadingBinding&x='
+GWFInstance, type: 'text/javascript' }).
inject(document.head);
eval('GWFLoaderBinding'+GWFInstance+' = function(gwfdir) {
this.set_fonts(gwfdir); }.bind(this);');
GWFInstance++;
},

When that Ajax request returns, call several internal methods, in turn, which finally embed the requested fonts.

set_fonts: function(gwfdir) {
this.gwfdirfonts = gwfdir.fonts;
if (this.fonts[0]!='') this.validate_fonts();
},
validate_fonts: function() {
// check to be sure the font requested exists in the
google library
this.fonts.each(function(font){
font = font.clean().replace(/ /g,'+');
if (!(this.gwfdirfonts).contains(font)) {
this.fonts.erase(font);
alert('font '+unescape(font)+' is not in the google
library');
}
},this);
this.embed_fonts();
},
embed_fonts: function() {
var family = 'family=';
this.fonts.each(function(font,i) {
family += escape(font.clean());
if (i<this.fonts.length-1) family += '|';
},this);
new Element('link',{ rel: 'stylesheet', type: 'text/css',
href: '<code>http://fonts.googleapis.com/css?</code>'+family }).
inject(document.head);
}
});

How it works...

Google fonts itself returns, based on browser type, an embedded font file, which the browser then parses to fulfill the styles request for a given font-family.

Take a look at the beauty of embedded web fonts. NOTE: These are not images; they are text!

MooTools 1.3 Cookbook

There's more...

The next recipe shows how to dynamically load a multi-select box that shows all the available font-families and dynamically builds the instantiation code. How much easier can it get?

See also

More and more fonts are being loaded all the time: http://code.google.com/apis/webfonts/.

 

Extending the Google Font Loader

In the recipe we just looked at, we extended the Options class, took an option in the form of a CSV of Google fonts, and styled text using CSS. Get ready to see how even the instantiation line can be generated based on a few clicks. That way, no typos or issues with unavailable fonts can creep in and catch us off guard.

Designers, especially, love this one-time-use class method.

How to do it...

Dabble in a bit of polymorphism. When no fonts are passed during instantiation, route the flow of action to a new method that generates an interface. That interface will have a multi-select input widget that onClick updates a TEXTAREA with an instantiation code that designers can use to embed their Google web fonts.

For brevity, only the new method is shown:

...
generate_code: function() {
// for each of the styles available, create an li
// display in multiselect format, generate code on click
this.fonts = [];
this.gwfdirfonts.each(function(font) {
this.fonts.include(font); },this);
this.embed_fonts();
new Element('select',{
multiple:'multiple',
size:'10',
style:'width:500px;font-size:20px;line-height:20px;',
id:'gwfpicker'
}).inject(document.body,'bottom');
new Element('textarea',{id:'gwfcode',style:'height:500px;
width:400px;vertical-align:top;'}).
inject('gwfpicker','after');
this.fonts.each(function(font) {
new Element('option',{
text: font.replace(/[+]/g,' '),
style:'font-family:''+font.replace(/[+]/g,' ')+'''
}).inject('gwfpicker','bottom');
});
$('gwfpicker').addEvent('change',function() {
var fonts = '';
var ops = this.getChildren('option');
ops.each(function(op,i) { if (op.selected)
fonts += op.get('text').replace(/ /g,'+')+',';
}); // replace space w/ +
var js = 'new GWFLoader({fontcsv:';
js += "'"+fonts.substr(0,fonts.length-1)+"'";
js += '});';
$('gwfcode').set('html',js);
});
}
});

How it works...

Two new elements are created. The first is a multi-select, which contains one SELECT OPTION for each of the currently available Google web fonts returned by the free JSON service. For additional user friendliness, each option is further styled by a background embedding of every Google web font. Be sure to give it a few seconds to load.

Instantiation of the Google web font picker is the same as loading fonts with the class; just do not send any argument, and the option to generate the desired instantiation is presented. Click while holding the control key (Ctrl) to select multiple fonts.

// instantiation *without any options*
// routes flow to GWFLoader::generate_code();

new GWFLoader(); // handled by GWFLoader::generate_code();

The Google web font loader font picker (yay)...

MooTools 1.3 Cookbook

Summary

MooTools is highly extensible and allows for simple extension of existing classes and DOM elements. In this article we implemented recipes to work directly with base class and to extend and implement MooTools classes.


Further resources on this subject:


MooTools 1.3 Cookbook Over 110 highly effective recipes to turbo-charge the user interface of any web-enabled Internet application and web page
Published: July 2011
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Jay Larry G. Johnston

Jay's first web work was in 1996 for the United States Army where he served the 5/5 Battalion Headquarters with the 2nd Infantry Division in South Korea.

Currently full time as Senior PHP Developer for ICGLink, Inc. managing high-end, custom development for the 2,000+ client base, Jay holds certifications in Linux, MySQL, and PHP5.

Introduced to the MooTools framework in 2007 while on permanent contract at Marshall Space Flight Center, Jay has incorporated Moo into every single new development since and frequently writes canned moo-solutions for use within the company.

Books From Packt


iPhone JavaScript Cookbook
iPhone JavaScript Cookbook

Apache Wicket Cookbook
Apache Wicket Cookbook

Joomla! 1.5 JavaScript jQuery
Joomla! 1.5 JavaScript jQuery

Java EE 6 with GlassFish 3 Application Server
Java EE 6 with GlassFish 3 Application Server

JavaScript Testing Beginner's Guide
JavaScript Testing Beginner's Guide

Apache Maven 3 Cookbook
Apache Maven 3 Cookbook

NetBeans IDE 7 Cookbook
NetBeans IDE 7 Cookbook

Learning jQuery 1.3
Learning jQuery 1.3


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Q
P
1
G
E
x
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software