Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Petite annonce pour un changement important dans le noyau du package
events. Je change après une longue réflection la classe
AbstractCoreEventDispatcher en simplifiant son nom. Nous utiliserons
donc maintenant la classe
... [More]
CoreEventDispatcher pour créer des
IEventDispatcher pouvant switcher entre un mode de diffusion des [Less]
Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Petit message rapide pour faire un point sur la version AS3 de VEGAS.
Cela fait un petit moment maintenant que VEGAS se base sur le package
system de maashaack mais depuis quelques semaines nous travaillons
Zwetan et moi
... [More]
sur de nombreuses nouvelles implémentations qui ont
entrainé une petite modification (très transparente) du noyau de VEGAS [Less]
Posted about 1 year ago by eKameleon
Il est très important de pouvoir "localiser" (ou régionaliser) nos applications. Localiser une application permet de rendre dynamique son contenu (texte, sonore ou autres) en créant une interface utilisateur qui peut changer en fonction d'une
... [More]
langue en particulier. La localisation d'une application permet d'améliorer l'accessibilité pour différents utilisateurs et il est certain qu'avec toutes les difficultés que l'on peut avoir pour communiquer de façon général, il est tout de même sympathique de pouvoir le faire avec le plus grand nombre dans le monde entier.
Une bon moteur de localisation permet de changer à tout moment les traductions et éléments graphiques de l'application en fonction de données traduites dans plusieurs langues. Il est certain que le plus souvent la localisation d'un site passe par une page d'accueil simple qui permet de diriger l'utilisateur vers une version spécifique de l'application avec un contenu régionalisé. Pour ma part dans VEGAS j'ai préféré créer un moteur qui possède les caractéristiques suivantes :
Externalisation des traductions et documents.
Utilisation de fichiers ou données externes encodées en UTF8.
Moteur dynamique au "runtime". La localisation doit être totalement dynamique et doit intervenir après la compilation (plus léger et plus simple à maintenir)
API simplifiée permettant de centraliser les mises à jours de l'interface utilisateur via un mapping utilisant plusieurs stratégies selon les besoins.
Par défaut, utilisation du format de donnée eden (http://code.google.com/p/edenrr/) ou JSON (http://www.json.org) même si il est vrai que j'utilise très peu cette dernière notation. Malgré tout il est assez simple de créer un module de parsing basé sur une autre notation comme par exemple du XML.
Dans Flash et surtout dans le framework de base ActionScript nous trouvons la propriété flash.system.Capabilites.language qui permet à tout moment de renvoyer le code langue du système dans lequel l'application swf vient d'être lancée. L'ActionScript se base sur des noms des "codes langue" au format ISO 639-1, par exemple la propriété language aura pour valeur "fr" si le système par défaut est un système français.
Implémentation du moteur de localisation de VEGAS
Dans VEGAS le moteur de localisation se trouve dans le package asgard.system.
1 - La classe asgard.system.Lang
La première classe que nous allons étudier dans ce package est la classe asgard.system.Lang qui permet d'énumérer les "codes langue" par défaut définis par la norme ISO 639-1 dans le FlashPlayer. Cette classe donne un outil simple pour valider dans vos applications les langues disponibles. Il est ainsi possible d'ajouter d'autres langues en cas de besoin dans la liste des langues par défaut du FlashPlayer mais bien entendu elle ne seront pas prises en compte automatiquement par la propriété System.capabilities.language(AS2) ou flash.system.Capabilities.language(AS3) du Flash Player.
Voici un exemple d'utilisation de cette classe :
import asgard.system.Lang ;
trace( "Lang.ES.toString() : " Lang.ES.toString() ) ; // es
trace( "Lang.ES.valueOf() : " Lang.ES.valueOf() ) ; // es
trace( "Lang.ES.toSource() : " Lang.ES.toSource() ) ; // new asgard.system.Lang("es","Spanish")
trace( "Lang.ES.label : " Lang.ES.label ) ; // Spanish
trace( "Lang.get('fr') == Lang.FR : " ( Lang.get("fr") == Lang.FR ) ) ; // true
trace( "Lang.validate('fr') : " Lang.validate('fr') ) ; // true
trace( "Lang.validate( Lang.FR ) : " Lang.validate( Lang.FR ) ) ; // true
trace( "Lang.LANGS : " Lang.LANGS ) ;
// {pl:pl,nl:nl,es:es,tr:tr,it:it,da:da,pt:pt,fi:fi,zh-CN:zh-CN,no:no,ja:ja,de:de,ru:ru,fr:fr,zh-TW:zh-TW,xu:xu,ko:ko,en:en,sv:sv,cs:cs,hu:hu}
trace( "Lang.LANGS.size() : " Lang.LANGS.size() ) ; // 21
2 - Fichier externe et nomenclature
Les données externes permettant la création des différentes versions du contenu de l'application localisée doivent être par défaut au format eden dans vos applications développées avec VEGAS. Le format eden permet de créer rapidement des fichiers de configuration simples. Je ne vais pas entrer dans le détail ici sur ce format mais pour résumer rapidement son action, je peux simplement illustrer ce format par un petit exemple.
De façon général, j'utilise une nomenclature spécifique pour créer mes fichiers textes externes de localisation. En effet si par exemple je cherche à réaliser un fichier de configuration en français avec un contexte spécifique : "locale/localize_fr.eden".
Nous isolons donc cette notation en la divisant en 4 éléments distincts : {path}{prefix}{lang}[suffix}
J'ai centralisé ces éléments dans une interface simple qui permet de créer facilement des classes qui permettent de charger les fichiers de localisation. Cette interface en AS3 est l'interface asgard.systems.ILocalizationLoader qui définie les propriétés et méthodes suivantes :
/**
* (Read-write) Indicates the Localization object.
*/
function get localization():Localization ;
function set localization( localization:Localization ):void ;
/**
* (Read-write) The path of the localization file.
*/
function get path():String ;
function set path( value:String ):void ;
/**
* Determinates the prefix value of the localization files.
*/
function get prefix():String ;
function set prefix(s:String):void ;
/**
* (Read-write) The suffix of the localization file.
*/
function get suffix():String ;
function set suffix( value:String ):void ;
/**
* Sends and loads data from the specified passed-in lang value (the passed-in argument must be a Lang reference or a valid string).
* @param lang The localization Lang value.
*/
function loadLang( lang:* ):void
Ainsi par défaut vous pouvez utiliser la classe EdenLocalizationLoader ou la classe JSONLocalizationLoader pour charger vos fichiers de localisation et mettre à jour automatiquement la ou les moteur de localisation de votre application.
Donc imaginons que j'ai une application qui doit contenir une contenu en version française et anglaise, je vais donc créer 2 fichiers textes au format eden comme ceci :
Contenu du fichier localize_fr.eden (français) :
{
lang : "fr" ,
namespace : "http://www.ekameleon.net/2008/asgard" ,
version : "1.0.0.0" ,
type : "eden" ,
door :
{
connectStarted : "DEBUT CONNEXION" ,
connectFinished : "FIN CONNEXION" ,
connectInProgress : "CONNEXION EN COURS" ,
connectOutOfTime : "DELAIS DE CONNEXION DEPASSE"
}
,
info :
{
finish_loading : "Fin du chargement" ,
progress_loading : "Chargement en cours" ,
start_loading : "Début du chargement"
}
,
myField :
{
selectable : true ,
text : "Bonjour le monde"
}
}
Contenu du fichier localize_en.eden (anglais) :
{
lang : "en" ,
namespace : "http://www.ekameleon.net/2008/asgard" ,
version : "1.0.0.0" ,
type : "eden" ,
door :
{
connectStarted : "START CONNECTION" ,
connectFinished : "FINISH CONNECTION" ,
connectInProgress : "CONNECTION IN PROGRESS" ,
connectOutOfTime : "THE CONNECTION IS OUT OF TIME"
}
,
info :
{
finish_loading : "THE LOADING IS FINISHED" ,
progress_loading : "THE LOADING IS IN PROGRESS" ,
start_loading : "THE LOADING IS STARTED"
}
,
myField :
{
selectable : false ,
text : "Hello world"
}
}
Les 2 fichiers au dessus contiennent donc un objet ECMAScript totalement compatible avec un objet défini en ActionScript ou Javascript. Il est tout à fait possible d'ailleurs de copier/coller le contenu des fichiers texte et de le tester rapidement sur un script de scénario dans Flash par exemple. J'apprécie avant toute chose cette notation car contrairement au XML ou autre, elle permet d'être testée et validée rapidement.. surtout par un développeur ActionScript débutant ou non
Comme le format JSON, le format eden permet d'utiliser une notation ECMAScript et donc d'utiliser des objets simples de type Object, Array, Number, Boolean, String, Date, etc... mais aussi des objets avec un type personnalisé.
Par exemple si l'on souhaite définir un format de texte spécifique pour un champ de texte dynamique dans l'application en fonction de la langue il sera possible dans le fichier de localisation au format eden d'ajouter un attribut "format" comme ceci :
{
format : new flash.text.TextFormat("arial", 12) , // utilisation d'un objet de type "custom"
// etc...
}
Le format eden permet de réaliser bien d'autres choses .. mais j'écrirai un tutoriel complet sur le sujet et il serait vraiment dommage de bâcler mes explications sur le sujet ici.
3 - La classe Localization
La classe asgard.system.Localization centralise le moteur de localisation de VEGAS avec une gestion globale via multi-singletons des références de type Localization. En effet il est possible de créer plusieurs références distinctes et globales pour gérer de façon séparé plusieurs localisations dans une même application. Malgré cela je vous avoue qu'il est assez rare d'utiliser plusieurs référence de type Localization dans une même application.
La classe Localization contient donc une méthode statique "getInstance(id:String)" qui renvoie à tout moment un singleton de type Localization dans le code de l'application.
Exemple :
var localization:Localization = Localization.getInstance() ;
Je vous conseille de lire tranquillement la documentation de cette classe avant de lire la suite : http://www.ekameleon.net/vegas/docs/asgard/system/Localization.html
La classe Localization contient une HashMap qui lui permet de stocker simplement des objets de type asgard.system.Locale dynamiques qui contiendront les propriétés chargées dans les fichiers de texte externes en fonction des "code langues" utilisés dans l'application.
La classe Locale est une classe très très simple et surtout "dynamique" qui permet de créer des objets typés compatibles avec le moteur de localisation. Les instances de type Locale servent avant tout à récupérer les données contenus dans les objets externes.
La classe Localization peut diffuser des événements, le plus important de tous est l'évènement LocalizationEvent.CHANGE qui notifie la mise à jour du moteur de localisation. L'application utilisateur peut ainsi changer si la langue courante du moteur change.
Exemple :
import asgard.events.LocalizationEvent ;
import asgard.system.Localization ;
var change:Function = function( e:LocalizationEvent )
{
trace( e ) ; // changer les vues de l'application maintenant
}
var localization:Localization = Localization.getInstance() ;
localization.addEventListener( LocalizationEvent.CHANGE , change ) ;
Voyons maintenant de plus prêt comment fonctionne le moteur de localisation. La classe Localization possède une gestion des langues par via un buffer, pour toutes les langues utilisées dans l'application un objet de type Locale correspond et permet de récupérer simplement les textes et données. Si pour un identifiant de langue donné l'instance de type Localization ne possède pas encore les données (aucun objet Locale existe encore), alors la Localization utilise un objet spécialisé qui va charger automatiquement les données nécessaires dans le fichier externe correspondant à la langue courante sélectionnée.
Pour changer à tout moment de langue courante il suffit donc sur l'objet de type Localization d'utiliser la propriété virtuelle "current" comme ceci :
Localization.getInstance().current = Lang.FR ; // français avec utilisation de l'énumération Lang.
ou directement :
Localization.getInstance().current = "en" ; // anglais utilisation directe d'un identifiant String valide.
Pour charger les données externes, la localisation utilise en interne un chargeur qui implémente l'interface asgard.systems.ILocalizationLoader comme défini au début de cet tutoriel. Il est possible à tout moment de récupérer ou modifier la référence interne du loader de la Localization via la propriété "loader" :
var loader:EdenLocalizationLoader = localization.loader as EdenLocalizationLoader ;
loader.addEventListener( ActionEvent.START , debug ) ;
loader.addEventListener( ActionEvent.FINISH , debug ) ;
loader.path = "locale/" ;
Dans ce petit bout de code je récupère la référence du chargeur et j'écoute les événements ActionEvent.START et ActionEvent.FINISH qui notifient le début et la fin du chargement opéré par le loader. Je modifie aussi la propriété "path" de l'objet pour définir un chemin différent pour le fichier "localize_ID.eden" que je vais charger quand la propriété "current" sera utilisé pour la première fois pour un identifiant de langue donné.
A noter que si pour un identifiant de langue, l'objet de type Locale existe déjà dans la Localization, l'évènement LocalizationEvent.CHANGE est directement invoqué étant donné que le moteur n'a pas besoin de charger à nouveau les données. Cette optimisation permet d'éviter certaines lourdeurs dans une application. Il est évidant qu'il est assez rare de devoir modifier plusieurs fois dynamiquement le contenu pour une langue donnée des données externes d'une même application.
En cas de soucis il est tout de même possible à tout moment d'utiliser la méthode "remove( id )" pour vider pour un identifiant de langue spécifique le buffer interne de la Localization. Par la suite si la propriété "current" est réutilisé pour le même identifiant de langue, les données externes seront chargées à nouveau et remplies dans le buffer du moteur de localisation.
Localization.getInstance().remove( Lang.FR ) ; // vider le cache
Localization.getInstance().current = Lang.FR ; // recharger et remettre à jour la vue
4 - La méthode Localization.getLocale()
Dans les points précédents nous avons pu voir comment charger les données externes et modifier à tout moment la langue courante du moteur de localisation avec notification de ce changement par un événement. Maintenant il reste à comprendre comment récupérer les données contenues dans l'objet de type Locale défini pour la langue courante.
Pour récupérer à tout moment l'objet de type Locale il suffit donc d'utiliser la méthode getLocale() comme ceci :
var locale:Locale = Localization.getInstance().getLocale() ;
for (var prop:String in locale)
{
trace(" * " prop " : " locale[prop]) ; // énumération des données contenues dans l'objet
}
Si par exemple je cherche à récupérer dans les exemples définis au début du tutoriel un texte en particulier je peux taper par exemple directement :
var message:String = Localization.getInstance().getLocale().info.start_loading ;
trace(message) ; // Début du chargement
Maintenant j'ai ajouté une petite fonctionnalité particulière dans cette méthode avec la possibilité d'inclure un paramètre dans la méthode "id" qui permet de localiser plus finement un attribut en particulier dans l'objet Locale, par exemple si je tape :
var message:String = Localization.getInstance().start_loading ;
trace(message) ; // Début du chargement
Je vais récupérer automatiquement dans l'objet "info" contenu dans l'objet Locale la valeur voulue. J'utilise beaucoup cette fonctionnalité avec un câblage un peu particulier de mes éléments graphiques. En effet de façon général tous mes éléments graphiques (clips, champs de texte etc... ) sont identifiables et possèdent tous un identifiant unique qui leur permet d'être unique dans l'application. Mais je me sers beaucoup de cette fonctionnalité pour récupérer pour chacun de mes éléments graphiques le contenu localisé qui leur est destiné.
5 - La méthode Localization.init()
Dernière petite méthode particulière du moteur de localisation avec la méthode "init()", cette méthode est définie comme ceci :
function init( o:Object , id:String=null , callback:Function=null ):void
Elle prend en paramètre les arguments suivant :
o : un objet que l'on souhaite mapper avec toutes les valeurs contenues dans la localisation pour un identifiant donné.
id : un identifiant de type String qui permet une recherche dans l'objet Locale pour la langue courante et qui permet de copier membre à membre toutes les propriétés contenus dans l'attribut spécifique dans l'objet spécifié dans la méthode. Si cet argument n'est pas défini, la recherche se fait dans l'objet Locale directement.
callback : une méthode optionnelle que l'on souhaite invoquer une fois que l'opération est terminée.
6 - Exemple complet.
Voici un exemple simple et complet des fonctionnalités décrites au dessus.
A noter que tous les exemples de ce tutoriel se trouvent dans le repository SVN de VEGAS dans le répertoire AS3/trunk/bin/test/asgard/system . Vous trouverez dans ce répertoire des exemples utilisant eden ou JSON avec les flas pour Flash CS3 et les fichiers textes encodés en UTF8 (voir définition de ces fichiers plus haut). (A noter que vous trouverez un exemple AS2 dans le répertoire AS2/trunk/bin/test/asgard/system du repository SVN du projet)
import andromeda.events.ActionEvent ;
import asgard.events.LocalizationEvent ;
import asgard.text.CoreTextField ;
import asgard.system.EdenLocalizationLoader ;
import asgard.system.Lang ;
import asgard.system.Locale ;
import asgard.system.Localization ;
import flash.text.TextFormat ;
var field:CoreTextField = new CoreTextField("myField") ;
field.defaultTextFormat = new TextFormat("arial", 12) ;
field.width = 300 ;
field.height = 20 ;
field.x = 25 ;
field.y = 25 ;
var debug:Function = function( e:Event ):void
{
trace("------- " e.type ) ;
}
var change:Function = function( e:LocalizationEvent )
{
var target:Localization = e.getTarget() ;
var current:Lang = e.getCurrent() ;
var locale:Locale = e.getLocale() ;
trace("# change current " current ) ;
trace("# change locale " locale ) ;
for (var each:String in locale)
{
trace(" * " each " : " locale[each]) ;
for (var prop:String in locale[each])
{
trace(" * " prop " : " locale[each][prop]) ;
}
}
// map the CoreTextField instance with this id attribute
Localization.getInstance().init( field , field.id ) ; // field.id == "myField", see this attribute in the localize_fr.eden file for example
}
var localization:Localization = Localization.getInstance() ;
localization.addEventListener( LocalizationEvent.CHANGE , change ) ;
var loader:EdenLocalizationLoader = localization.loader as EdenLocalizationLoader ;
loader.addEventListener( ActionEvent.START , debug ) ;
loader.addEventListener( ActionEvent.FINISH , debug ) ;
loader.path = "locale/" ;
localization.current = Lang.FR ;
var onKeyDown:Function = function( e:KeyboardEvent ):void
{
var code:uint = e.keyCode ;
switch( code )
{
case Keyboard.UP :
{
localization.current = Lang.EN ;
break ;
}
case Keyboard.DOWN :
{
localization.current = "fr" ;
break ;
}
}
}
stage.addEventListener( KeyboardEvent.KEY_DOWN , onKeyDown ) ;
Dans cet exemple j'utilise à peu prêt toutes les fonctionnalités décrites précédemment. A noter que pour le petit test, j'utilise la classe asgard.text.CoreTextField qui est une superclasse de la classe flash.text.TextField. Cette classe implémente l'interface vegas.core.Identifiable comme toutes les implémentations visuelles de ASGard (CoreSprite, CoreMovieClip, CoreBitmap, etc.), ainsi chaque instance possède un identifiant unique "id" dans l'application. Nous nous servons donc de cet identifiant dans les fichiers de configuration ou de localisation de l'application pour retrouver rapidement dans la structure objet de l'objet Locale l'attribut correspondant à l'élément graphique voulu. Voir la ligne de code suivante :
Localization.getInstance().init( field , field.id ) ; // field.id == "myField", see this attribute in the localize_fr.eden file for example
Conclusion
Voilà donc fini mon petit tutoriel sur le moteur de localisation de VEGAS. A noter pour bientôt un tutoriel à peu prêt identique sur le moteur de configuration de VEGAS qui fonctionne en gros de la même manière mais pour gérer un objet singleton global Config.getInstance() qui contient dans une application toutes les valeurs et données importantes chargée au runtime dans un fichier config.eden par exemple. Dans un fichier de configuration on pourra trouver de nombreuses informations importantes (chemin du serveur web pour les connexions HTTP, feuille de style des éléments graphique avec choix des couleurs, taille, position etc... )
A noter que pour me donner vos idées et remarques sur le sujet ou pour toutes les questions concernant précisément l'utilisation de ce moteur, vous pouvez abuser du Google Groups du projet :
http://groups.google.com/group/vegasos
Je vous invite également à télécharger mon framework opensource documentaire AST'r qui contient en AS2 et AS3 (avec IOC) des exemples d'utilisation de ce moteur de localisation dans des cas concrets :
http://code.google.com/p/astr/
PS : il y a de forte chance que j'ajoute prochainement une fonctionnalité pour ajouter dans le fichier Locale courant des données, c'est à dire passer au dessus de la sécurité actuelle qui oblige de vider le buffer pour recharger des données pour une langue donnée. Si vous pensez avoir le besoin d'une telle fonctionnalité n'hésitez pas à me le faire savoir.
A noter le lien sur le Google Group de VEGAS de ce tutoriel :
http://groups.google.com/group/vegasos/web/vegas-localization-in-as3-and-as2 [Less]
Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Voici un petit tutoriel sur le moteur de localisation de VEGAS :)
Il me reste à copier ce tutoriel sur mon blog et à écrire la version
anglaise sur le Google Code de ASGard ;)
Je vous notifierai tout cela dans les commentaires de ce message :)
Comme toujours n'hésitez pas à me poser des questions ;)
Posted about 1 year ago by eKameleon
Voici un rapide petit tutoriel pour illustrer une petite différence (bug ?) entre la portée des variables en ActionScript 3 par rapport à la même portée des variables en AS2.
Je ne vais pas entrer ici dans un rappel complet sur
... [More]
l'utilisation du scope des variables en ECMAScript (JS ou AS) mais je me suis rendu compte ce soir d'un petit problème de portabilité entre un bout de code AS2 vers de l'AS3. Je me suis donc amusé avec un petit test pour isoler ce problème.
Exemple avec portée de variable simple en AS2.
var a:Number = 1 ;
var test:Function = function():Void
{
trace("> first : " a) ; // 1
var a:Number = 2 ;
trace("> last : " a) ; // 2
}
test() ;
// output
// > first : 1
// > last : 2
Analysons un peu l'exemple au dessus avant de passer à l'exemple en AS3
Dans le premier test, je regarde juste la portée de la variable "a" à l'intérieur de la fonction test. Lorsque j'appelle la fonction test(), la première instruction dans la fonction cherche à récupérer la valeur d'une variable qui porte comme nom "a" ... Cette variable n'existe pas en local dans la fonction (variable déclarée avec le mot clé var dans la fonction) et il n'existe non plus aucun paramètre dans la fonction qui porte comme nom "a". Du coup le script va chercher à l'extérieur de la fonction (à l'endroit où elle est déclarée) si il existe une variable qui s'appelle "a" et forcément il trouve une adresse mémoire avec ce nom et il renvoi la valeur : 1
Jusque là tout va bien
Ensuite je défini dans la fonction test une variable locale avec le mot clé var et du coup si j'appelle à nouveau une variable "a" la valeur trouvé par le script sera simplement celle de la variable locale trouvée : 2
A noter que si dans l'exemple précédent si j'ajoute un argument "a" dans la définition de la fonction et que je passe une valeur dans les paramètres de la fonction au moment de l'appeler j'obtiens :
var a:Number = 1 ;
var test:Function = function( a:Number ):Void
{
trace("> first : " a) ; // 3
var a:Number = 2 ;
trace("> last : " a) ; // 2
}
test(3) ;
// output
// > first : 3
// > last : 2
Dans l'exemple au dessus la portée de variable se limite à un valeur trouvée dans les paramètres de la fonction, la première valeur de "a" vaut 3, la valeur passée dans la fonction au moment de l'appeler. Pas de soucis donc à ce niveau là
Le même exemple en AS3 et un petit soucis ?
var a:Number = 1 ;
var test:Function = function():void
{
trace("> first : " a) ; // undefined
var a:Number = 2 ;
trace("> last : " a) ; // 2
}
test() ;
// output
// > first : undefined
// > last : 2
Contrairement à l'exemple précédent en AS2, ce code AS3 n'arrive pas à récupérer la valeur de la variable située à l'extérieur de la fonction.
Par contre si je modifie légèrement le code précédent :
var a:Number = 1 ;
var test:Function = function():void
{
trace("> first : " a) ; // 1
// var a:Number = 2 ;
trace("> last : " a) ; // 1
}
test() ;
// output
// > first : 1
// > last : 1
Si je désactive avec un commentaire la déclaration d'une variable locale avec le mot clé var dans la fonction, je peux donc accéder par portée enfin à la valeur de ma variable déclarée à l'extérieur de la fonction.
Conclusion
Au final, en AS3 il est impossible d'accéder à une variable par portée située à l'extérieur d'une fonction si cette variable est déclarée plus loin dans la fonction localement avec le mot clé "var". Il est vrai que ce type de cas de figure est très rare en si on utilise correctement les variables locales et avec une portée... mais je trouve tout de même beaucoup plus logique et intuitif la possibilité de récupérer la valeur de la variable externe à la fonction comme en AS2 à tout moment même si il existe un peu plus loin dans la fonction la déclaration d'une variable locale du même nom. Reste que ce que je trouve intuitif doit peut être suivre une logique qui me dépasse
Je me suis demandé si ce comportement est voulu par Adobe ou non en AS3 par rapport à l'AS2 ?
Il m'a suffit d'un petit test en Javascript 1.7 (avec JSDB), mais aussi en Javascript 1.5 avec Flash Media Server et son SSAS pour voir que le problème venait de l'AS1/AS2 et pas de l'AS3.
Voici le code javascript de test :
geshi javascript
var a = 1 ;
var test = function()
{
trace("> first : " a) ; // undefined
var a = 2 ;
trace("> last : " a) ; // 2
}
test() ;
trace("---") ;
var a = 1 ;
var test = function()
{
trace("> first : " a) ; // 1
//var a = 2 ;
trace("> last : " a) ; // 1
}
test() ;
Faudra vraiment que je vois comment réagi Tamarin ou la M2 de ES4 sur ce genre de manipulation du scope.
Dans tous les cas Adobe semble avoir corrigé un bug existant en AS1 et AS2 et il va falloir que je cherche si je trouve pas une discussion sur le sujet au niveau des mailing list ECMAScript car je trouve ce comportement vraiment étrange. [Less]
Posted about 1 year ago by eKameleon
Il n'y a pas de secret. Le code ne passe pas seulement par des interminables lignes de code mais surtout par d'interminables lignes de documentation (en général plus nombreuses). Un framework, une classe, un bout de code non documenté et c'est
... [More]
très rapidement l'anarchie.
Pour générer nos documentations en AS3 ou MXML, Adobe nous propose ASDoc une application en ligne de commande assez complexe mais qui a le mérite de générer une documentation HTML bien complète.
Je ne vais pas entrer dans mon article sur une explication super détaillée de toutes les options proposées par ASDoc ou encore sur la "meilleure manière" de générer sa documentation via une tache ANT ... Je préfère vous parler d'une fonctionnalité à mes yeux importante et pourtant non prévue dans ASDoc : la colorisation syntaxique du code contenu dans la documentation.
En effet, même si ASDoc propose via les balises code et listing une "solution" pour afficher une partie du texte contenu dans vos documentations avec un formatage "spécifique".. on peut pas dire que le résultat soit très explicite !
A côté de cela Google a sorti il y a un petit moment maintenant un petit module opensource écrit en JAVAScript qui permet de coloriser un code HTML efficacement via le script Google Code Prettify. L'intérêt de ce module réside dans le fait qu'il ne nécessite pas, comme GESHI (PHP) par exemple, d'un script serveur pour coloriser le code d'un texte HTML.
Google Code Prettify permet de coloriser un bon nombre de langages et fonctionne vraiment bien avec les langages basés sur une écriture C, Java, Python, Bash, SQL, HTML, XML, CSS et Javascript.
Pour faire simple Google Code Prettify permets de modifier dynamiquement dans une page HTML les balises pre et code possédant un attribut "class" avec la valeur "prettyprint" comme ceci :
<html>
<header>
<link href="prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="prettify.js"></script>
</header>
<body onload="prettyPrint()">
<p>
<pre class=prettyprint>
var s = "hello world" ;
var sum = function( n1 , n2 )
{
return n1 n2 ;
}
trace( 2 3 ) ;
</pre>
</p>
<p>The previous script return <code class="prettyprint">5</p></p>
</body>
</html>
Au final, nous avons d'un côté ASDoc un applicatif en ligne de commande qui permet de documenter nos classes via la notation JAVADOC et un texte au format HTML distribué officiellement par Adobe et de l'autre côté
Google Code Prettify qui permet de formater un texte HTML si il contient des scripts. L'idée est de pouvoir utiliser les 2 pour créer nos documentations AS3
Hacker le template de ASDoc pour utiliser Google Prettify
ASDoc est basé sur un template utilisant de nombreux fichiers xsl, js, html etc.
Le répertoire par défaut du template de ASDoc se trouve dans le répertoire sdk 3.0.0/asdoc/templates du Flex SDK 3. Pour ma part pour créer mon propre template pour ASDoc j'ai copié ce répertoire dans le repository SVN de mon framework pour éviter tout soucis. Vous pouvez bien entendu modifier directement les sources du template de ASDoc fourni dans le SDK de Flex 3 mais bon.... en général ce n'est pas trop conseillé
Détaillons maintenant la procédure pour transformer ASDoc :
1 - Télécharger Google Code Prettify
Pour cela il suffit de récupérer la dernière version disponible sur Google Code : Google Prettify sur Google Code.
Ensuite il suffit de placer les 2 fichiers prettify.js et prettify.css à la racine du répertoire template. Vous pouvez ensuite personnaliser comme vous le désirez les couleurs des mots clés dans votre code en éditant simplement la feuille de style contenue dans le fichier "prettify.css".
2 - Modifier le fichier asdoc.js du répertoire template de ASDoc.
Avec n'importe quel éditeur de texte (JSEclipse ou NotePad par exemple) vous cherchez la fonction configPage() dans le fichier asdoc.js et il suffit d'ajouter ensuite à la fin de la fonction l'instruction prettyPrint() ; :
function configPage()
{
// ... asdoc code here
prettyPrint() ;
}
Cette méthode est invoquée lors de l'appel de l'événement window.onLoad dans chacune des pages de la documentation.
3 - Modifier le fichier adoc-util.xsl.
Tout d'abord il faut faire une recherche dans le fichier pour trouver l'élément XSL : getStyleLink. Ce noeud XSL contient les définitions des feuilles de style utilisées dans les pages HTML de la documentation. Il suffit donc d'ajouter dans ce noeud le tag suivant :
<xsl:template name="getStyleLink">
....
<xsl:element name="link">
<xsl:attribute name="rel">stylesheet</xsl:attribute>
<xsl:attribute name="href">
<xsl:value-of select="$baseRef"/>prettify.css</xsl:attribute>
<xsl:attribute name="type">text/css</xsl:attribute>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
En cas de doute vous pouvez consulter le fichier modifier sur le SVN de VEGAS : asdoc_util.xsl modifié
Ensuite il faut faire une nouvelle recherche dans le fichier pour trouver l'élément XSL avec l'identifiant : getTitleScript. Ce noeud contient les appels des scripts Javascript externes nécessaires dans l'application. Nous rajoutons donc comme pour les balises de style le code suivant :
<script language="javascript" type="text/javascript">
<xsl:attribute name="src">
<xsl:value-of select="$baseRef"/>
<xsl:text>prettify.js</xsl:text>
</xsl:attribute>
</script>
Vous pouvez ajouter cet élément juste avant l'élément qui permet de gérer le chargement du fichier asdoc.js.
Conclusion en tout genre
Résultat des opérations... Voici quelques petits exemples en parcourant la documentation de la version AS3 de VEGAS mon framework opensource :
La classe andromeda.ioc.factory.ECMAObjectFactory
La classe asgard.net.remoting.RemotingService
La classe asgard.text.FontLoader
Bon pour le moment j'ai pas encore eu le temps de totalement personnaliser la charte graphique de la documentation de VEGAS. Mais la possibilité d'afficher du code avec la colorisation syntaxique qu'il faut, c'est tout de même une bonne chose
Pour utiliser Google Prettify dans votre Javadoc il faut donc changer très légèrement vos habitudes. Il faut à présent remplacer les balises <code> et <listing> de ASDoc avec respectivement les balises <code class="prettyprint"> et <pre class="prettyprint">, exemple :
package vegas.core
{
import system.ISerializable;
import system.Reflection;
import vegas.logging.ILogable;
import vegas.logging.ILogger;
import vegas.logging.Log;
/**
* CoreObject offers a default implementation of the IFormattable, IHashable and ISerializable interfaces.
* <p>
* <pre class="prettyprint">
* import vegas.core.CoreObject ;
*
* var core:CoreObject = new CoreObject() ;
* trace("> core : " core) ;
* trace("> hashcode : " core.hashCode()) ;
* trace("> toSource : " core.toSource()) ;
* </pre>
* </p>
* @author eKameleon
* @version 1.0.0.0
*/
public class CoreObject extends Object implements IFormattable, IHashable, ILogable, ISerializable
{
/**
* Creates a new <code class="prettyprint">CoreObject</code> instance.
*/
function CoreObject()
{
_logger = Log.getLogger( Reflection.getClassPath(this) ) ;
}
// etc...
}
}
Voici le résultat du code précédent : vegas.core.CoreObject
A noter pour ceux que cela intéresse que j'ai placé dans le SVN AS3 de VEGAS ma tache ANT qui me permet de générer ma documentation via ASDoc :
http://svn1.cvsdude.com/osflash/vegas/AS3/trunk/build/asdoc/
Pour finir... faut bien entendu avant de vous quitter que je vous parle des petits points noirs de ASDoc... ASDoc est vraiment très pratique pour créer de la documentation mais franchement je trouve que le choix de Adobe pour un template super compliqué rempli de tas de fichiers XSL n'est pas forcément des plus judicieux. Je trouve franchement très lourde la gestion des éléments du template par des fichiers XSL vraiment "trop fourni" !
Ensuite... ASDoc n'est vraiment pas stable... Il faut faire énormément attention en créant la documentation car de nombreux problèmes apparaissent lors de la compilation de la documentation. Par exemple :
Problème avec les @ dans la documentation.. exemple écrire un mail test@test.com dans un script entraîne des instabilités et des oublis dans la documentation.
Coller dans une boucle for le symbole < ... exemple for( var i:uint = 0 ; i<n. Ici la documentation va arrêter le parsing après le <. Il faut absolument aérer le code et ne pas coller le caractère <.
L'Utilisation de certains caractères UTF8 pour valeur des propriétés des classes (voir par exemple mon hack de la classe vegas.string.UnicodeChar avec ce code source pas très propre pour le coup ! J'ai du rentrer les valeurs de mes constantes dans des Array pour éviter les bugs de ASDoc :()
Pour écrire dans un script <?php .. il faut utiliser la notation html &...
Problème avec l'utilisation du caractère * dans les exemples et les bouts de code : ... style trace( "vegas.errors.*" ) ; ..
Il va falloir que j'aille faire un tour du côté de la bug liste de Flex pour voir si on peut leur faire remonter les erreurs (qu'ils doivent sûrement déjà connaître...)
Sinon malgré ces petits problèmes, le rendu HTML de ASDoc reste vraiment propre... et je préfère pour le moment la documentation générée par ASDoc par rapport à celle de NaturalDocs (malgré le fait que je préfère la gestion de template de NaturalDocs)
Pour toutes vos questions sur cet article vous pouvez utiliser les commentaires de ce blog mais je vous propose d'aller discuter sur le Google Groups de mon blog. [Less]
Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Après avoir un peu lutté j'ai pu mettre en ligne une première version
AS3 (ASDoc) de la documentation de VEGAS et ses extensions :
[link]
Bon du coup pour le moment j'ai supprimé complètement la version AS2
basée sur AS2API car elle provoquait des freeze sur mon serveur ...
Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Message rapide pour vous annoncer une version stable de l'exemple
eGallery AS3 de AST'r :)
Dans cet exemple qui reprend la logique de la version AS2, j'illustre
comment réaliser une petite galerie d'image simple via des
... [More]
données
externes (en local ou serveur).
Dans cet exemple j'ai basé l'application sur la fabrique IOC basée [Less]
Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Juste un petit message pour vous informer que j'ai mi à jour le
tutoriel sur l'installation de VEGAS via SVN sur le wiki du projet de
VEGAS de Google Code.
[link]
J'ai essayé de couvrir toutes les explications de bases pour installer
Posted about 1 year ago by ekam...@gmail.com (eKameleon)
Hello :)
Petit message rapide avant d'aller me coucher ^_^
Je viens rapidement de porter mon implémentation AS3 (un peu
différemment malgré tout) des interfaces pegas.draw.IFillStyle et
pegas.draw.ILineStyle...
Du coup
... [More]
après un peu de customisation de la classe AbstractPen et de
son interface IPen on peut utiliser maintenant les propriétés [Less]
Copyright © 2009 Geeknet, Inc., All Rights Reserved.