Mootools en 30 jours : jour 21 - Les classes partie 2

I. Introduction aux classes avec Mootools 1.2

Si vous ne l'avez pas encore fait, assurez-vous d'avoir lu les tutoriels Mootools 1.2 précédents de notre série de 30 jours.

II. Explications

Maintenant que notre classe de base est définie, nous pouvons accéder à ses fonctionnalités en créant une autre classe qui l'implémente. Notre dans les exemples ci-dessous que notre nouvelle classe ne fait rien d'autre qu'implémenter "BaseClass".

//Construction d'un classe appelée ImplementingClass
var ImplementingClass = new Class({
//Elle implémente juste Baseclass
Implements : BaseClass
});

Maintenant nous pouvons créer une instance de ImplementingClass et accéder aux fonctionnalités définies dans BaseClass de façon complètement transparente.

var demo_one = function(){
//Création d'une nouvelle instance de ImplementingClass
var test_class = new ImplementingClass();
//Appel de testFunction, qui est définie dans BaseClass
test_class.testFunction();
}

Vous pouvez faire le même avec les variables et la fonction initialize. Presque tout ce que vous définissez dans la classe de base sera transféré à la classe qui l'implémente, comme si vous déclariez dans la classe qui implémente.

Note: Nous allons utiliser cette version de BaseClass dans les exemples qui vont suivre :

var BaseClass = new Class({
//Assigne la valeur du parametre
//à une variable nommée inputVariable
//qui appartient à cette classe
initialize: function(input){
this.inputVariable = input;
},
//Affiche la valeur de InputVariable
testFunction : function(){
alert('BaseClass.testFunction() : ' + this.inputVariable);
},
//Definit une variable interne
//pour toutes les instances de cette classe
definedVariable : "Defined in BaseClass",
});
 
var ImplementingClass = new Class({
//Encore uen fois, tout ce que nous faisons
//c'est implémenter la BaseClass
Implements : BaseClass
});

La demo ci-dessous démontre comment on peut accéder à la routine d'initialisation, aux appels de fonction, et variables, s'il appartient à la classe qui implémente.

var demo_two = function(){
//création d'un instance de ImplementingClass
var test_class = new ImplementingClass('this is the input value');
 
//appel de testFunction() (definit dans BaseClass)
test_class.testFunction();
 
//Affiche definedVariable
alert('test_class.testVariable : ' + test_class.definedVariable);
}

Une fois que vous avez implémenté une classe, vous pouvez ajouter toutes les fonctionnalités que vous voulez en les définissant dans cette nouvelle classe.

var ImplementingClass = new Class({
Implements : BaseClass,
//Ceci est défini dans BaseClass
definedVariable : "Defined in ImplementingClass",
testFunction : function(){
alert('This function is also defined in BaseClass');
},
 
//Mais ces variables ne sont pas définies dans BaseClass
anotherDefinedVariable : "Also Defined in ImplementingClass",
anotherTestFunction : function(){
alert('This function is defined in ImplementingClass');
}
});

Notez que nous redéfinissons testFunction et definedVariable dans la classe qui implémente, et nous ajoutons une nouvelle fonction et une nouvelle variable. Sachez que si vous essayez de définir une fonction ou variable qui est déjà déclarée dans la classe de base en utilisant implements, la définition de la classe de base remplacera la définition de la classe qui implémente. Regardez la démo pour bien voir ce que je veux dire :

var demo_three = function(){
//Créé une instance de ImplementingClass
var test_class = new ImplementingClass('this is the input value');
 
//(défini dans BaseClass)
test_class.testFunction();
 
//Affiche definedVariable (définie dans BaseClass)
alert('test_class.testVariable : ' + test_class.definedVariable);
 
// (définie dans ImplementingClass)
test_class.anotherTestFunction();
 
//Affiche anotherDefinedVariable (définie dans ImplementingClass)
alert('test_class.anotherDefinedVariable : ' + test_class.anotherDefinedVariable);
}



Extends

Pour les cas de figure dans lequels vous voulez écraser ce qui est défini dans la classe de base, vous pouvez utiliser Extends. Remplacez simplement Implements par Extends.

var ExtendingClass = new Class({
//Notez l'utilisation de Extends au lieu de Implements
Extends : BaseClass,
//Chacune de ces 2 là est définie dans BaseClass,
//mais comme nous utilisons extend au lieu de
//implement, celles-ci vont écraser celles définies
//dans BaseClass
definedVariable : "Defined in ImplementingClass",
testFunction : function(){
alert('This function is also defined in BaseClass');
}
});
 
var demo_four = function(){
//Créé une instance de ExtendingClass
var test_class = new ExtendingClass('this is the input value');
 
//Appel de testFunction() (défini dans BaseClass et ExtendingClass)
test_class.testFunction();
 
//Affiche definedVariable (défini dans BaseClass et ExtendingClass)
alert('test_class.definedVariable : ' + test_class.definedVariable);
}

Une autre fonctionnalité pratique quand vous utilisez "extends" est la possibilité d'écraser la fonction d'initialisation définie dans la classe de base tout en exécutant toujours cette dernière. Donc si vous définissez cette fonction d'initialisation dans une classe de base…

initialize : function(){
alert('base class');
}

…puis que vous définissez la fonction d'initialisation suivante dans la classe d'extension, vous obtiendrez deux boites d'alertes disant “base class” et “extending class.”

initialize : function(){
//Appel du constructeur parent
this.parent();
alert('extending class');
}

Si la fonction initialization parente attend un paramètre, assurez-vous d'inclure le même paramètre et de le passer au constructeur parent. Dans l'exemple ci-dessous, notez que nous n'assignons aucune valeur au paramètre, nous le passons simplement au constructeur parent qui s'en occupe pour nous.

var ExtendingClass = new Class({
//Encore une fois, nous étendons, nous n'implémentons pas
Extends : BaseClass,
initialize: function(input){
//L'appel à this.parent lance la fonction
//d'initialisation définie dans la baseclass
this.parent(input);
//Faire ceci nous permet de faire des tâches
//supplémentaires pendant l'initialisation sans
//écrase le code d'initalisation de la classe
//de base
this.otherVariable = "Original Input Was : " + input;
}
});
 
var demo_five = function(){
//Construction de notre classe
var test_class = new ExtendingClass('this is the input value');
 
//exécution de testFunction
test_class.testFunction();
 
//affichage de otherVariable
alert("test_class.otherVariable : " + test_class.otherVariable);
}



.implement()

Non seulement vous pouvez implémenter et étendre dans vos définitions de classes, mais vous pouvez aussi les utiliser sur des classes déjà existentes pour ajouter des fonctionnalités une par une. Pour cet exemple nous allons utiliser une classe de calculatrice simple qui ajoute et soustrait deux nombres que vous définissez en créant la classe.

var Calculator = new Class({
//définition de 2 variables pendant l'initialisation
initialize: function(first_number, second_number){
this.first = first_number;
this.second = second_number;
},
//Fonction pour ajouter les deux variables
//internes et renvoyer le résultat
add : function(){
result = this.first + this.second;
alert(result);
},
//Fonction pour soustraire les deux variables
//internes et renvoyer le résultat
subtract : function(){
result = this.first - this.second;
alert(result);
}
 
});

Ceci est très bien si vous souhaitez juste additionner ou soustraire des nombres, mais que se passe-t'il si vous voulez les multiplier? En utilisant .implement(), nous pouvons simplement ajouter une fonction sur la classe et l'utiliser comme si nous avions créé une autre classe implémentant la classe Calculator comme base.

var demo_six = function(){
//implémente une nouvelle fonction
//dans la classe calculator
Calculator.implement({
//Fonction qui multiplie les deux variables
//internes et renvoie le résultat
multiply : function(){
result = this.first * this.second;
alert(result);
}
});
 
//Construction d'une classe calculator
var myCalculator = new Calculator(100, 50);
 
//Appelle la fonction de multiplication
myCalculator.multiply();
}

Dans la partie I des Classes, nous avons utilisé les fonction print_r pour débugger le javascript. En utilisant implement, nous pouvons rendre cela vraiment facile d'afficher les contenus d'une variable de classe simplement en implémentant une fonction dans la classe Calculator.

var demo_seven = function(){
//Implemente une fonction pour afficher
//le contenu de la classe Calculator
Calculator.implement({
show_class : function(){
alert(print_r(this, true));
}
});
 
//Construit une calculatrice
var myCalculator = new Calculator(100, 50);
 
//Affiche les details de la classe
myCalculator.show_class();
}



Exemple

Bien que soigné, ce n'est pas une fonctionnalité très utile pour la classe calculator étant donné sa nature relativement simple. Toutefois, comme la plupart des objets Mootools sont construits en tant que classes, nous pouvons utiliser la même méthode sur ceux-ci pour obtenir quelque chose d'un peu plus utile. L'exemple ci-dessous implémente une fonction qui envoie une fenêtre pop-up contenant la structure de n'importe quel élément HTML que vous voulez examiner. Cette fonctionnalité est maintenant ajoutée automatiquement à n'importe que élément HTML sur lequel vous intéragissez, donc tout ce que vous avez à faire est d'ajouter une commande showStructure() à votre élément pour obtenir une description complète de l'élément en question.

var demo_eight = function(){
Element.implement({
showStructure : function(){
//les < and > ont été retirés des tags pre
//car ils sont interpretés par le navigateur, et
//le site ne dialogue pas bien avec des caractères
//imbriqués dans des blocks pre
var structure = 'pre' + print_r(this, true) + '/pre';
//Ouverture d'une fenetre popup
newWindow = window.open('','Element Debug','height=600,width=600,scrollbars=yes');
//Ecrit la structure dans la fenetre popup
newWindow.document.write(structure);
}
});
 
$('demo_eight').showStructure();
}

Note: il faut désactiver vos bloqueurs de popup pour que cela puisse fonctionner.

III. Conclusion du tutorial

Pour en savoir plus

Télécharger un zip contenant tout ce qu'il vous faut pour débuter

Mootools Class Docs
Un article excellent en anglais qui détaille bien les finesses des classes dans Mootools.

Tutoriel de demain

Morphing sur plusieurs éléments avec Fx.Morph