artlung
artlung

Reputation: 33823

Hidden Features of MooTools

What are the hidden or obscure features of MooTools that every MooTools developer should be aware of?

One feature per answer, please.

Upvotes: 9

Views: 586

Answers (6)

Dimitar Christoff
Dimitar Christoff

Reputation: 26165

There are many features that one can use if you read the source code, although the official line is: if it's not in the documentation, it is not in the api and it's not supported so do not base your code around it as it may change

That being said, there are a few things that really can be quite useful. One of my favourites undocumented features is this:

Referenced Elements have a uid

Any element that has either being created or is passed on through a selector, gets assigned a property uid, which is incremental and unique. Since MooTools 1.4.2, this is only readable via Slick.uidOf(node) and not via the old element attr .uid. You can now use the new uniqueNumber property of any MooTools Element object.

How is that being used? For starters, Element Storage. It relies on the uid as the key in the Storage object inside a closure, which will have anything you have .store'd for that element.

element.store('foo', 'bar');

translates to:

Storage[Slick.uidOf(element)].foo = 'bar';

and

element.retrieve('foo'); // getter of the storage key
element.eliminate('foo'); // delete Storage[Slick.uidOf(element)].foo

Initializing storage for an element you have created externally, eg, via var foo = document.createElement('div') and not Element constructor

Slick.uidOf(foo); // makes it compatible with Storage

// same as:
document.id(foo);

Things that are stored by the framework into Storage also include all events callbacks, validators instances, Fx instances (tween, morph etc) and so forth.

What can you do knowing the UIDs of elements? Well, cloning an element does NOT get the element's storage or events. You can actually write a new Element.cloneWithStorage prototype that will also copy all of the stored values you may have, which is useful upto a point - instances that reference a particular element (such as, Fx.Tween) will continue referencing the old element, so it may have unexpected results. This can be useful in moving your own storage, though, all you need is a similar method that will record what you have stored and allow you to clone it.

Example Storage puncture of another Element's data:

var foo = new Element('div'),
    uid = foo.uniqueNumber;

foo.store('foo', 'foo only');

var bar = new Element('div');

console.log(bar.retrieve('foo')); // null

bar.uniqueNumber = uid; // force overwrite of uid to the other el

console.log(bar.retrieve('foo')); // foo only - OH NOES

console.log(Object.keys(foo)); // ["uniqueNumber"] - oh dear. enumerable!

Upvotes: 4

Joshua Dwire
Joshua Dwire

Reputation: 5443

One of my favorite features that I learned later but wished I knew from the beginning - event pseudos, especially :once.

See http://mootools.net/docs/more/Class/Events.Pseudos#Pseudos:once

Upvotes: 3

Dimitar Christoff
Dimitar Christoff

Reputation: 26165

Class Mutators

MooTools has a wonderful feature that allows you to create your own Class mutators. Eg, to add a logger for particular class methods being referenced, you can do:

// define the mutator as 'Monitor', use as Mointor: ['methodname', 'method2'...]
Class.Mutators.Monitor = function(methods){
    if (!this.prototype.initialize) this.implement('initialize', function(){});
    return Array.from(methods).concat(this.prototype.Monitor || []);
};

Class.Mutators.initialize = function(initialize){
    return function(){
        Array.from(this.Monitor).each(function(name){
           var original = this[name];
           if (original) this[name] = function() {
               console.log("[LOG] " + name, "[SCOPE]:", this, "[ARGS]", arguments);
               original.apply(this, arguments);
           }
        }, this);
        return initialize.apply(this, arguments);
    };
};

and then in the Class:

var foo = new Class({

    Monitor: 'bar',

    initialize: function() {
        this.bar("mootools");
    },

    bar: function(what) {
        alert(what);
    }

});

var f = new foo();
f.bar.call({hi:"there from a custom scope"}, "scope 2");

Try the jsfiddle: http://jsfiddle.net/BMsZ7/2/

This little gem has been instrumental to me catching nested bugfoot race condition issues inside a HUUUGE async webapp that would have been so difficult to trace otherwise.

Upvotes: 9

MattiSG
MattiSG

Reputation: 4026

I'd recommend reading the excellent Up the Moo Herd series by Mark Obcena, author of Pro Javascript With MooTools  :)

Upvotes: 2

arian
arian

Reputation: 708

Function.prototype.protect is maybe a lesser known nice one.

Is used to have protected methods in classes:

var Foo = new Class({

    fooify: function(){
        console.log('can\'t touch me');
    }.protect(),

    barify: function(){
        this.fooify();
    }

});

 var foo = new Foo();
 foo.fooify(); // throws error
 foo.barify(); // logs "can't touch me"

Personally I don't use it very often, but it might be useful in some cases.

Upvotes: 6

arian
arian

Reputation: 708

Function.prototype.overloadGetter and Function.prototype.overloadSetter

See this post: What does MooTools' Function.prototype.overloadSetter() do?

Upvotes: 5

Related Questions