Pourquoi ce FrameWork et ce programme ?
Tout simplement parce que je n'aime pas ATLAS et sa gestion des classes en JavaScript.
De plus je suis très attaché à Prototype (ce framework est basé dessus) et les frameworks basés dessus.
Alors j'ai décidé de mettre la POO de prototype au gout du jour !
Voici un petit programme qui vous permettra de faire de la POO en JavaScript comme vous n'en avez jamais fait avant. Notez que toutes vos classes réalisées avec l'ancienne méthode de Prototype restent tout à fait valides, et bénéficieront des fonctionnalités de cette nouvelle mouture, excepté les évènements. Ceci pourrait vous faire gagner beaucoup de temps si votre ancien site était sous Prototype !
Pour utiliser mon FrameWork, vous devez remplacer le fichier prototype.js par System.js, fichié de base de mon FrameWork. Si vous voulez bénéfichier de la Sérialisation, je vous conseille d'ajouter json.js à votre page aussi.
Pour télécharger le programme, je vous conseille de faire un tour dans Codes-Sources, catégorie VB .NET, je devrais y poster le code d'ici peu, n'ayant pas de serveur perso. De toute façon, le code est totalement libre de droit. Toute remarque est bienvenue !
L'interface utilisateur.
FC JavaScript Editor possède une interface graphique proche de celle offerte par n'importe quel éditeur de texte, ainsi qu'évidemment les propres à la programmation objet.
La barre de menu
Fichier Edition Affichage ?
Nouveau Analyser Explorateur d'objets (F6)
Ouvrir Compiler Coloration syntaxique
Sauvegarder Couper / Coller Analyse syntaxique
Fermer Sélectionner tout
Rechercher (CTRL+F)
Précédent (CTRL+F3)
Suivant (F3)
La barre de fonction
Nouveau, Ouvrir, Sauvegarder, Imprimer, Couper / Coller, Aide
& [Sélecteur de classe (v)], [Sélecteur de champs (v)]
La barre latérale "Explorateur d'objets"
- TreeView contenant l'ensemble des espaces de noms (package), sous-espaces de nom, classes, sous-classes, interfaces, champs, propriétés, fonction de classe, évènement
- Menu contextuel utilisable pour ajouter automatiquement du code
- Renommage des objets par double clic
La barre de statut
- Numéro de ligne (+Atteindre), de colonne
- Rechercher / Remplacer
- Analyser / Compiler
Auto-complétion.
- S'ouvre automatiquement lors d'un frappe de "." "new " ou de CTRL+Enter
- Contenu dynamique en fonction de l'objet (window, document, style, Object, …)
- Vous permet de taper autre chose que le contenu proposé
- Se ferme quand le contenu est introuvable dans les données depuis 2 car.
- Prend en charge l'arborescence des classes
- Prend en charge les classes de base (String, ActiveXObject, Number, …)
- Propose des snippets (document.getElementById, …)
Captures d'écran
http://blogs.codes-sources.com/photos/fremycompany/picture33217.aspx
http://blogs.codes-sources.com/photos/fremycompany/picture33218.aspx
http://blogs.codes-sources.com/photos/fremycompany/picture33219.aspx
http://blogs.codes-sources.com/photos/fremycompany/picture33220.aspx
http://blogs.codes-sources.com/photos/fremycompany/picture33221.aspx
http://blogs.codes-sources.com/photos/fremycompany/picture33222.aspx
http://blogs.codes-sources.com/photos/fremycompany/picture33223.aspx
Exemple de code
Sample.js
|
package System {
package My
{
class MyClass
{
//// Fields
field fieldName1 = null;
field.new fieldName2;
field.static fieldName3="true";
//// Functions
void funcName1(args) {
// ...
} end;
void.static funcName2 () { /* ... */ }
end;
//// Properties
property PropertyName1 = false;
property.new PropertyName2;
//// Events
event EventName1; event.new EventName2;
}
}
}
package System {
package My2 {
interface IAlert {
void alert(txt) {
throw ("Not implemented");
} end;
}
class MyClass {
implements(System.My2.IAlert);
void initialize(msg) {
this.msg = msg;
} end;
void alert(txt) { window.alert(this.msg + "\n" + txt); } end;
}
class MyClass2 {
extends(System.My2.MyClass);
void initialize(msg) {
System.My2.MyClass.apply(this, [msg]);
} end;
}
}
} |
Explication du contenu
Espace de nom
- Package : Déclare un espace de nom
Classe
- Class : Déclare une classe
- Interface : Déclare une interface (mappé en classe)
Prototype de classe
- Field : Déclare un champ
La valeur d'initialisation est dynamique (new Array() : eval("new Array()"))
- Property : Déclare une propriété modifiable uniquement via setPropertyName
==> Crée lors d'une nouvelle instanciation : getP, setP et onPChange
- Void : Déclare une nouvelle fonction
==> End : Déclare une fin de fonction, obligatoire
- Event : déclare un évènement
==> Voir System.Event
Accesseurs
- New : (Défaut) Membre normal, réinstancié à chaque nouvelle instance (o.dynamicF)
- Static : Membre static, n'appartient qu'à la classe (o.getType().staticF)
Disposent des deux accesseurs : field, void, event
Sont toujours ".new" : property
Sont toujours ".static" : pacakge, class, interface
Héritage
Comme vous pouvez le constatez, il y a trois méthodes pour faire hérité une classe d'un autre
Inherits, Extends et Implements. Il n'existe aucune différence entre les trois, utilisez les comme vous le préférez.
Si vous faite un héritage d'une classe vers une autre, vous devez alors créer le constructeur initialize et y faire l'appel suivant : theBaseClass.apply(this, [arg01, arg02, arg03, …])
Code compilé (Sample.compiled.js)
|
with(addNameSpace("System")){
with(addNameSpace("My")) {
with(addClass("MyClass")) {
//// Fields
addField("fieldName1",'null');
addField("fieldName2",'');
addSharedField("fieldName3",'"true"');
//// Functions
addSub("funcName1", function(args) {
// ...
} );
addSharedSub("funcName2", function () { /* ... */ } );
//// Properties
addProperty("PropertyName1",'false');
addProperty("PropertyName2",'');
//// Events
addEvent("EventName1"); addEvent("EventName2");
}
}
}
with(addNameSpace("System")){
with(addNameSpace("My2")){
with(addClass("IAlert")){
addSub("alert", function(txt) {
throw ("Not implemented");
} );
}
with(addClass("MyClass")){
inherits(System.My2.IAlert);
addSub("initialize", function(msg) {
this.msg = msg;
} );
addSub("alert", function(txt) { window.alert(this.msg + "\n" + txt); } );
}
with(addClass("MyClass2")){
inherits(System.My2.MyClass);
addSub("initialize", function(msg) {
System.My2.MyClass.apply(this, [msg]);
} );
}
}
} |
La gestion des types / introspection
Récupérer le type d'un objet
Vous pouvez récupérer le type d'un objet selon deux méthodes :
- Sécurisée : getTypeOf(obj)
- Normale : obj.getType()
Vous recevrez alors un objet de type System.Class (ou System.Type, qui est son alias)
Vous remarquerez aussi à l'occasion que System possède l'alias Sys.
System.Class / NameSpace
- reflectName : nom court de la classe ("MyClass")
- parent : Espace de nom ou classe parent (System.My)
- getPath : Nom complet de la classe ("System.My.MyClass")
- baseClasses : Array contenat les classes héritées
La gestion des évènements
Les Handlers
Ajouter un "Common-Handler" : o.eventName.addHandler(func)
===> Ajoute un Handler sans nom
Ajouter un "Named-Handler" : o.eventName.addHandler(func, name)
===> Remplace tout autre Handler du même nom
Enlever un "Common-Handler" : o.eventName.removeHandler(func)
Enlever un "Named-Handler" : o.eventName.removeHandlerByName(name)
Lancer un évènement
o.eventName(arg01, argo02, arg03, …)
o.eventName.raise(sender, args)
Code d'un Handler
|
o.eventName.addHandler(function(text) { this.alert(text) })
o.eventName.raise(window, ["Hello !"]) |
La sérialisation
Par défaut, tout objet gère toJSONString() qui le transforme en chaine JSON pour pouvoir être stocké
Ensuite, chaque objet peut redéfinir dans sa classe toJSONString pour renvoyer des chaines de caractères différentes (ex : "new X(3)") pour conserver le type de l'objet ou éviter sa corruption
Les délégués
Les habitué au JavaScript détecteront tout de suite la faute du code suivant :
|
var o = new X(); o.text = "L'évènement onClick a été appelé";
x.alert=function() { window.alert(this.text); }
document.body.onclick = x.alert; |
En effet, lorsque l'évènement onClick sera appelé, le this de "alert" aura changé et sera devenu document.body. Pour éviter cela, voici la solution :
|
var o = new X(); o.text = "L'évènement onClick a été appelé";
x.alert=function() { window.alert(this.text); }
document.body.onclick = x.alert.toDelegate(); |
Pour avoir plus d'information à propos de ce framework
Je vous conseille de le télécharger et de jeter un œil à test.html. Et aussi à l'excellente documentation de Prototype.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :