Chapitre 2. Préliminaires sur le langage

Table des matières

1. Aperçu sur la syntaxe et la sémantique
1.1. XML
1.2. JavaScript
1.3. Syntaxe par "point" ("dot")
1.4. Majuscules / Minuscules, sensibilité à la casse
1.5. DTD et schéma de LZX
2. Objets et Attributs
2.1. Objets
2.2. Attributs
3. Evénements et Méthodes
3.1. Evénements
3.2. Méthodes
4. Contraintes
4.1. Hiérarchies
4.2. Portée
5. Accès aux données, Manipulation et Liaison
5.1. Accès aux données
5.2. Manipulation des données
5.3. Liaison de données
6. Mélanger Balises et Script dans les programmes LZX
6.1. Comment mélanger balises et script
6.2. Quand utiliser les balises et quand utiliser du script
7. Compilation et Exécution

LZX est un langage orienté objet à base de balises, qui s'appuie sur la syntaxe du XML et de JavaScript pour créer la couche de présentation des clients internet riches. Ces applications sont compilées avec le compilateur OpenLaszlo. Elles peuvent être déployées en tant que fichiers indépendants, ou peuvent être mises à disposition par le serveur OpenLaszlo. Les spécifications du langage contiennent à la fois un ensemble de balises XML et un ensemble de bibliothèques (APIs) Javascript. 

Le langage LZX a été spécifié en utilisant des syntaxes et des conventions de nommage courantes pour que les développeurs web expérimentés puissent l'apprendre facilement et l'intégrer à leur environnement de développement. En même temps, LZX introduit de nouveaux concepts et possibilités; les interfaces graphiques des applications web deviennent plus fluides et interactives qu'avec n'importe quelle autre technologie. 

Un programme LZX en fonctionnement se place dans un objet graphique appelé une toile ('canvas'), qui est globalement une zone délimitée de l'écran. Sur la toile, des boîtes autonomes appelées vues ('view') intéragissent. Ces vues peuvent être placées les unes dans les autres, à la fois de façon logique et graphique, et possèdent des dizaines d'attributs programmables, dont la taille, la position, la couleur d'arrière plan, l'opacité, le fait d'être cliquable ou non, le fait de pouvoir être redimensionnée, et ainsi de suite. Les vues peuvent contenir des ressources telles qu'une image ou une vidéo, et peuvent aussi être liées dynamiquement à n'importe quel ensemble de données formatées en XML. Les attributs de n'importe quelle vue peuvent être définis comme étant fonction des attributs de n'importe quelles autres vues, et pratiquement n'importe quel attribut peut être animé - c'est à dire programmé pour avoir sa valeur qui varie dans le temps. 

Le système de vues de LZX est très semblable aux autres systèmes de vues, mais son implémentation de la liaison de données, des contraintes sur attributs et des animations le distinguent de toutes les autres technologies pour interfaces graphiques. 

Les programmes LZX contiennent généralement à la fois des structures déclaratives et procédurales, et le langage suit de nombreuses conventions de nommage des CSS (Cascading Style Sheets). Les programmes écrits avec LZX sont ainsi similaires, de façon générale, aux applications DHTML avec du code JavaScript embarqué. Les programmes LZX sont cependant conceptuellement différents des applications typiques DHTML/JavaScript qui sont interprétées et affichées, ou plutôt "rendues" par le navigateur. Les programmes LZX sont eux compilés sur le serveur et téléchargés sous forme de bytecode pour un moteur de rendu cible. 

Dans l'actuelle implémentation de la plateforme Laszlo, les programmes LZX sont compilés sur le serveur OpenLaszlo et téléchargés en tant que films Flash (fichiers .swf) pour être exécutés dans le lecteur Flash installé sous forme de plug-in dans le navigateur. Il est important de cependant noter que le lecteur Flash est utilisé seulement en tant que moteur de rendu/exécution du bytecode généré, et qu'il n'y a rien dans LZX qui ne le lie à Flash. En particulier, LZX n'utilise pas le modèle objet de Flash. (NdT : au moment de la traduction, Laszlo Systems permet désormais de générer également les applications LZX en Ajax et de s'affranchir ainsi du lecteur Flash). 

De façon similaire, parce que les programmes LZX sont compilés par le serveur OpenLaszlo, l'utilisation du JavaScript dans les programmes est légèrement différente de son utilisation dans les applications web traditionnelles dans lesquelles JavaScript est utilisé pour faire des choses telles que communiquer avec le navigateur ou générer des pages HTML. Ces fonctions sont globalement inadaptées dans les applications LZX. Ainsi, bien que l'utilisation du langage se fasse de façon traditionnelle, la façon de programmer est quant à elle nouvelle. 

Ce chapitre résume les aspects traditionnels et innovants de LZX. C'est un aperçu général, non un tutoriel; après l'avoir lu, vous serez plus à même de décider comment apprendre le langage. Suivant vos connaissances et votre expérience, vous déciderez peut-être d'approfondir XML ou les concepts de programmation orientée objet. Mais si vous trouvez ces concepts compréhensibles, vous choisirez peut-être de plonger directement dans le code, auquel cas nous vous conseillons de commencer par le tutoriel Les bases d'OpenLaszlo.

1. Aperçu sur la syntaxe et la sémantique

Dans LZX, les balises XML sont utilisées pour créer des objets JavaScript, et JavaScript est utilisé à l'intérieur des programmes LZX pour manipuler les objets créés à l'aide de balises. La plupart du temps, tout ce qui peut être fait avec une balise peut l'être avec JavaScript et inversement. Cependant, cette équivalence n'est pas universellement vraie, et en général, une technique est bien supérieure à l'autre dans une situation donnée. Apprendre LZX renvient donc à apprendre les balises et les APIs; maîtriser le langage consiste à développer une compréhension subtile des approches procédurales et déclaratives en sachant quand et comment les utiliser.

LZX suit rigoureusement les syntaxes du XML et du JavaScript. 

[Note] Note

Dans des versions passées, LZX ne tenait pas compte de la casse dans le JavaScript. A partir de la version 3.0 de OpenLaszlo, LZX est un langage sensible à la casse. Voir les explications plus bas pour de plus amples informations. 

Les chapitres qui suivent donnent une brève vision des deux types de syntaxe LZX. Voir plus bas pour une un développement de la façon dont XML et JavaScript fonctionnent ensemble dans les programmes LZX.

1.1. XML

XML, langage de balises extensible (eXtensible Markup Langage), est un standard du W3C pour décrire les données. Vous aurez besoin de bases sur les concepts de XML pour écrire des programmes en LZX pour deux raisons : d'abord, la plupart des fonctionnalités de LZX sont implémentées sous forme d'un ensemble de balises XML. Les programmes LZX sont eux-mêmes des documents XML valides; les programmes LZX qui ne sont pas en XML valide ne se compilent tout simplement pas. Ensuite, les programmes LZX ne fonctionnent qu'avec des données encapsulée en XML.

Si vous comprenez comment les balises et les attributs sont représentés en XML, êtes à l'aise avec les concepts de racine et de noeud, et savez comment l'imbrication de balises fonctionne, vous en savez probablement assez pour vous lancer dans LZX. Pour de plus amples informations sur XML et des liens vers une série de livres et tutoriels disponibles en ligne, rendez-vous sur le site du W3C.

Une autre distinction entre XML et JavaScript réside dans le fait qu'en XML, les noms des types sont en minuscule ("string", "number"), alors qu'en JavaScript ils ont leur première lettre en majuscule ("String", "Number"). En XML, on utilise les noms de types pour <attribute name="foo" type="string"/>; Ils sont en minuscule pour une compatibilité avec la description de la grammaire XML (XML Schema Description).

1.1.1. XML et HTML

Si vous avez de l'expérience HTML mais pas XML, vous trouverez beaucoup de ressemblances. Pour les personnes familières avec HTML, voici quelques notes sur les différences entre XML et HTML. Elles s'appliquent à tout XML; elles peuvent particulièrement attirer l'attention pour les balises de mise en forme, avec les balises (<p>, <i>, <br>) qui ont les mêmes nom et signification que les balises HTML :

  • La casse (majuscule/minuscule) est prise en compte. <b> est différent de <B>. (<b> est une balise LZX pour mettre du texte en gras dans une balise <text>. La balise <B> n'existe pas).

  • Les valeurs d'attributs doivent être entourées de guillemets, avec " ou '. <view width=100> est non valide en XML; utilisez <view width='100'> ou <view width="100"> à la place.

  • Les balises vides doivent être fermées. <br> est valide en HTML; en XML remplacez-le par <br></br> ou <br/>.

1.1.2. Espaces de nommage (namespaces)

Les applications Laszlo peuvent utiliser un espace de nommage :

  <canvas xlmns="http://www.laszlosystems.com/2003/05/lzx">...</canvas>

ou non :

  <canvas>...</canvas>

S'il n'y a pas d'espace de nommage défini, le compilateur prendra par défaut celui de LZX (http://www.laszlosystems.com/2003/05/lzx").

1.2. JavaScript

JavaScript est un langage initialement écrit par Brendan Eich de Netscape pour son intégration dans le navigateur Netscape 2.0. Ce fut tout de suite un succès avec son adoption par tous les autres navigateurs, et pour faire de cette valeur montante un standard, l'Association Européenne des Constructeurs Informatique (European Computer Manufacturer's Association - ECMA) entreprit de spécifier le langage en tant que ECMAScript et contrôle maintenant son évolution. Bien qu'il puisse y avoir quelques subtiles différences entre une implémentation de JavaScript et le langage spécifié par l'organisme de standardisation, de façon générale, les termes JavaScript et ECMAScript sont généralement interchangeables. Bien qu'il serait plus juste de dire que ECMAScirpt se réfère au langage pur alors que JavaScript signifie à la fois le langage et les bibliothèques associées disponibles dans la plupart des navigateurs, dans ce livre nous suivrons l'usage courant sans faire cette distinction, le contexte permettant de comprendre de quoi nous parlons. Le terme "script" se réfère à n'importe quel code (procédural) écrit en JavaScript. 

LZX implémente une partie de la spécification LZX ECMA-262 Edition 3.

Pour écrire du code LZX vous devrez être à l'aise avec les aspects suivants du langage JavaScript :

  • les structures de contrôle standard (for, while, etc.),

  • le modèle objet,

  • le faible typage des données,

  • la portée avec les règles de nommage dans les programmes.

Suivant votre expérience, vous trouverez certains aspects de LZX familiers ou étrangers. Par exemple, si vous avez de l'expérience Java mais pas JavaScript, vous devrez apprendre les grosses différences entre ces langages, et en particulier le typage des données, le modèle objet et la portée ou règle de nommage des variables.

Comme d'autres langages dits de script tels que Perl et Python, Javascript est un langage faiblement typé - vous pouvez déclarer une variable sans préciser son type. Cela permet un prototypage rapide et un code qu'on dit plus facile à lire, mais on risque de laisser passer des erreurs de type.

La programmation orientée objet avec JavaScript manque de rigueur par rapport à Java. Il n'y a pas de packages ou d'interface par exemple, et il n'est pas non plus possible de rendre finales des classes. Enfin, le comportement de variables locales et globales en JavaScript est parfois surprenant pour des développeurs Java.

Inversement, si vous êtes un développeurs JavaScript expérimenté, vous devrez peut-être "oublier" certaines pratiques, en particulier la disponibilité de certaines bibliothèques et fonctions, et aussi la prise en compte de la casse (majuscules/minuscules). Egalement, LZX possède un modèle complet de programmation orientée objet qui va plus loin que JavaScript. En effet, LZX a des classes et de l'héritage. 

Si vous n'avez ni d'expérience Java ni JavaScript, vous aurez peut-être besoin de parcourir au préalable un tutoriel JavaScript comme ceux disponibles sur w3schools.com avant de plonger plus avant dans LZX.

1.3. Syntaxe par "point" ("dot")

LZX utilise la syntaxe à base de "point" pour indiquer la relation entre les objets et leurs membres. Considérez l'expression suivante :

this.that

Interprété en JavaScript, this se réfère à un objet, et that se réfère à une propriété de cet objet, une propriété pouvant être une méthode. Maintenant, considérez le fragment de code LZX suivant :

<view name="beatles"> 
  <view name="george"/> 
</view>

dans ce cas, il peut être pratique de désigner la vue intérieure "george" comme

beatles.george

george étant un fils de beatles .

Comme ce sera décrit plus loin, LZX propose différentes façons de désigner des attributs ou des méthodes d'objets ou de classes. Par exemple, les fragments de code suivants (créant une vue appelée myview et définissant sa couleur d'arrière plan à rouge) sont équivalents :

JavaScript:

myview = new LzView;
myview.setAttribute (bgcolor, red);

Balise XML :

<view name="myview" bgcolor="red"/>

Dans les deux cas, la couleur d'arrière plan de myview pourrait être référencée par le code myview.bgcolor . La convention de syntaxe par "point" fournit ainsi une façon pratique de référencer des objets sans se soucier de comment ils ont été créés - c'est à dire d'une façon déclarative par balise ou par code procédural.

1.4. Majuscules / Minuscules, sensibilité à la casse

La sensibilité à la casse avec LZX dépend de la cible pour laquelle vous compilez. Avec la version 3.1 vous pouvez compiler en swf6, swf7, ou swf8. Les applications compilées en swf6 ne sont pas sensibles à la casse. Vous ne pouvez pas utiliser la casse seulement pour distinguer les identifiants. Par exemple, si vous appelez une variable locale date, vous ne pourrez appeler le constructeur de la classe JavaScript Date en écrivant new Date().

swf7 est la cible par défaut; les applications compilées en swf7 et swf8 sont entièrement sensibles à la casse. Cela signifie que quand vous utilisez une variable, elle doit s'écrire avec la même casse que quand elle a été déclarée. 

De ce fait, les applications qui fonctionnent avec swf6 peuvent ne pas fonctionner avec swf7 et vice versa.

Sans même le problème de la version cible, avoir des variables qui ne diffèrent que par leur casse est source de confusion. C'est pourquoi c'est une bonne pratique que d'éviter d'utiliser des noms qui s'écrivent de la même façon mais diffèrent seulement par leur utilisation des majuscules et minuscules. 

1.5. DTD et Schéma de LZX

Un schéma XML définit l'ensemble des balises XML disponibles et peut être utilisé pour configurer un éditeur. La DTD est également disponible pour les curieux, bien que vous n'ayez pas besoin de la connaître pour programmer. 

Le schéma LZX est utilisé par le compilateur OpenLaszlo pour s'assurer que les programmes LZX sont corrects. Par exemple, le schéma précise quels sont les attributs qui peuvent être inclus dans une balise ouvrante <view>. Si un programme contient une balise <view> qui inclut an attribut non défini dans le schéma, il lancera un avertissement à la compilation.

LZX permet de définir vos propres balises. Les balises définies par l'utilisateur ne viennent pas se placer dans le schéma disponible dans votre éditeur, bien qu'elles soient utilisées dans le schéma interne utilisé par le compilateur pour tester la validité du programme.

2. Objets et attributs

LZX utilise les concepts standards de la programmation orientée objet tels que l'héritage, l'encapsulation et le polymorphisme. En général, une balise dans un programme OpenLaszlo correspond à un objet ou instance d'une classe du même nom. Par exemple, la balise <view> correspond à un objet LzView.

En première approximation, il est donc possible de décrire LZX comme un langage déclaratif à base de règles pour manipuler des objets visuels (JavaScript) appelés vues (views), les règles étant exprimées sous forme de contraintes sur les valeurs des attributs de ces objets.

Les paragraphes qui suivent résument certains des concepts clé de l'orienté objet avec le langage LZX. Ces idées sont examinées plus en détails plus loin dans le guide, particulièrement au Chapitre 30, Etendre des classes.

2.1. Objets

Un objet est un type de données qui contient des sous-données désignées par un nom. Suivant le contexte, une sous-donnée s'appelle une propriété ou un attribut de cet objet. Par exemple, chaque vue (view) a 49 attributs tels que la hauteur, la largeur, la position horizontale, la position verticale et ainsi de suite. Les valeurs sont généralement données aux attributs des objets au moment de leur création; les attributs qui ne reçoivent pas de valeur prennent la valeur par défaut. 

Vous pouvez créer d'autres types d'objets LZX en utilisant la balise <class>. Chaque nouvelle classe que vous créez doit recevoir un nom et le nom de la classe qu'elle "étend". Les objets créés héritent alors de toutes propriétés de la classe que vous avez étendue, plus les nouvelles propriétés que vous avez définies. Prenez l'exemple simple suivant : 

<class name="myview" extends="view"/>

Dans ce cas, vous avez défini un nouveau type d'objet appelé myview qui a toutes les propriétés de view. Dans l'Appendix A, Comprendre l'Instanciation vous trouverez des explications détaillées sur comment les objets sont définis dans votre code et comment le compilateur les construit durant l'exécution.

2.2. Attributs

En LZX, le mot "attribut" a deux significations liées mais tout de même différentes, l'une syntaxique et l'autre sémantique. En XML, syntaxicalement parlant, un attribut est une valeur désignée par un nom, attaché à un élément et spécifié dans la balise ouvrante de cet élément. Ainsi, dans la balise XML

<boss demeanor="friendly"/>

demeanor est un attribut de la balise boss . Cette définition de l'attribut s'applique dans le contexte d'une structure XML. Remarquez que la valeur de l'attribut est entourée de guillemets.

Puisque les balises LZX correspondent à des classe LZX, le terme "attribut" s'enrichit d'une valeur sémantique supplémentaire qui est la propriété d'un objet JavaScript. Ainsi, la balise LZX

<view height="20" width="30"/>

induit la création d'un objet vue (view) avec les valeurs spécifiées pour les attributs height et width.

La balise <attribute> peut être utilisée pour définir les attributs JavaScript d'objets. Par exemple,

 
<view name="myview"> 
  <attribute height="20"/> 
  <attribute width="30"/> 
</view>  

est équivalent en LZX, à la version précédente. Ainsi, height est un attribut de la vue, au sens sémantique du terme, bien qu'il ne le soit pas au sens XML puisqu'il n'est pas contenu dans la balise ouvrante. height est également un attribut, au sens XML cette fois, de la première balise <attribute>. Sa valeur peut être référencée dans du script par myview.height.

Vous pouvez aussi utiliser la balise <attribute> pour ajouter d'autres attributs aux classes que vous créez. Par exemple :

<class name="froboz" extends="view"> 
  <attribute name="whatnot" value="17"> 
</class>

définit un nouveau type d'objet vue, froboz, qui a 50 attributs : les 49 qui sont hérités de la balise vue (view), plus le nouvel attribut whatnot.

Nous avons vu que les attributs peuvent être positionnés, c'est à dire qu'on peut leur affecter des valeurs dans les balises LZX. Il est également possible de définir la valeur d'attributs dans du script en utilisant la méthode setAttribute(). En plus, les valeurs d'attributs peuvent être lues ou "récupérées" dans du script (mais pas dans des balises) en utilisant la méthode getAttribute(). (Les méthodes seront expliquées plus bas).

Supposons que nous ayons une vue appelée johnny. Cette vue peut avoir été créée en utilisant une balise ou du script; comment la vue a été créée n'a aucune importance.

Le code JavaScript pour définir la hauteur de cette vue à 100 pixels serait :

johnny.setAttribute("height", 100);

et pour lire la valeur de la hauteur :

johnny.getAttribute("height");

A chaque fois qu'un attribut est positionné, c'est à dire à chaque fois que la valeur d'un attribut change, un objet appelé event est généré. La section suivante présente ce que sont les événements (events) et comment ils fonctionnent dans les programmes LZX.

3. Evénements et Méthodes

3.1. Evénements

Les évenements (events) sont le mécanisme par lequel les objets communiquent ensemble quand quelque chose change. Par exemple, un événement peut être généré quand un bouton de souris est activé, ou quand des données arrivent d'un serveur, ou quand une vue a été construite.

Dans les programmes LZX, les événements ne sont pas diffusés, mais ils sont plutôt communiqués dans un modèle point-à-point en utilisant des delegates (délégués) qui sont des pointeurs vers des fonctions référencées en fonction des événements qui surviennent. Cette implémentation augmente la flexibilité et réduit l'excés de complications dans l'utilisation des événements. Cependant, dans le présent chapitre, nous allons laisser sous silence les délégués ('delegates') et parler des événements d'une manière légèrement moins rigoureuse, en disant par exemple quand tel ou tel événement arrive, mais laissant de côté pour l'instant comment cela arrive.

Les vues ('view') ont approximativement deux douzaines d'événements prédéfinis, comme on peut le voir dans le Manuel de Référence LZX pour l'entrée <view>. Beaucoup de ces événements sont en rapport avec des actions utilisateurs, tels que onblur, onclick, onkeydown, ce qui devrait être familier aux programmeurs JavaScript. D'autres types d'événements, comme onheight et onopacity, sont liés aux attributs de visibilité des vues. Enfin, les événements oninit et onconstruct sont liés à la création des instances des objets vues. De façon similaire, d'autres objets LZX définis par le système, tels que les blocs de données ('Datasets') (voir plus bas), ont des événéments associés.

Les événements et attributs vont souvent ensemble et en fait, le comportement par défaut de la méthode setAttribute est de définir la propriété puis d'appeler la méthode appelée "on" + le nom de la propriété. Par exemple, quand une vue change sa position horizontale x, elle envoie l'événement onx avec la nouvelle valeur de sa propriété x. Cela signifie qu'en plus des événements définis par le système, il y a un événement pour chaque attribut que vous définissez. 

Quand un événement se produit, le contrôle est transféré à son gestionnaire d'événement ('event-handler') (si on en a définit un). Les événements peuvent être envoyés avec un seul argument qui contient généralement une information sur la propriété qui a changé. 

Plus loin dans ce guide, nous verrons comment les événements sont implémentés en LZX, et comment l'architecture des événements est liée au design des programmes. En particulier, le Chapitre 27, Délégués décrit la relation entre les événements et les délégués.

3.2. Méthodes

En LZX, une méthode est une fonction JavaScript associée à un type d'objet. Les méthodes doivent soit avoir un nom particulier, soit être associées à un type d'événement particulier. 

Si la méthode a un attribut event, le script sera exécuté quand la vue référencée recevra l'événement de ce nom. (NdT, avec la sortie de la version 3.2, Laszlo Systems a introduit les nouvelles balises event et handler dans le langage et cette façon de définir les méthodes associées aux événements et devenue dépréciée. Pour plus d'informations, rendez-vous sur le wiki du site OpenLaszlo)

Par exemple,

<view> 
  <method event="onclick"> 
    <!-- du code JavaScript ---> 
  </method> 
</view>

définit un fonction qui est exécutée quand on clique sur la vue.

En JavaScript, les fonctions sont invoquées en utilisant l'opérateur (). Ainsi,

<view name="dog">   
  <method name="bark"> 
    <!-- du code JavaScript ---> 
  </method> 
</view>

définit une fonction qui est exécutée quand on invoque son nom de la façon suivante :

dog.bark();

En JavaScript, le mot-clé this est utilisé pour référencer l'objet qui a permis d'invoquer la fonction. Considérons le code suivant :

 
<view> 
  <method name="bark"> 
    <!-- du code JavaScript ---> 
  </method> 
  <method name="handler" event="onclick"> 
    this.bark()  
  </method> 
<view>

Quand on clique sur la vue, l'événement onclick est déclenché, ce qui lance l'exécution de la méthode appelée handler() qui a son tour invoque la méthode nommée bark(). Les gestionnaires d'événements ('Event handlers') sont souvent définis dans les balises ouvrantes, comme dans :

<view onclick="clickHandler()"> 
  <method name="clickHandler"> 
    <!-- du code JavaScript --> 
  </method> 
</view> 

Il y a trois grandes catégories de méthodes :

  • "On init" : méthodes invoquées quand l'objet parent est créé,

  • "On event" : méthodes invoquées quand leur objet parent reçoit un événement particulier,

  • méthodes avec nom explicitement invoquées par d'autres méthodes.

Remarquez que vous pouvez définir des méthodes en utilisant la syntaxe JavaScript traditionnelle, mais qu'avec LZX, on préfère utiliser la balise <method>.

Notez également qu'avec LZX, contrairement à beaucoup de systèmes orientés objet, vous pouvez surcharger une méthode dans une instance d'un objet. Ce sujet est décrit au Chapitre 30, Etendre des classes.

4. Contraintes

En LZX, une contrainte est un attribut dont la valeur est fonction de l'attribut d'autres valeurs. La syntaxe pour écrire une contrainte est la suivante :

$when{expression}

où :

  • $ est le caractère indiquant que c'est une contrainte

  • when est une directive de compilation optionnelle : immediately(immediatement), once(une seule fois) ou always(toujours). $always{expression} peut être abrégé en ${expression}

  • { et } sont les caractères qui délimitent l'expression à évaluer

  • expression est une expression JavaScript

Comme nous l'avons vu plus haut, quand la valeur d'un attribut change, son événement on est déclenché. Parce qu'une contrainte est un attribut dont la valeur dépend des valeurs d'un ou plusieurs attributs, la valeur de la contrainte est recalculée quand elle reçoit l'événement on des attributs dont elle dépend.

Considérons :

<view name="someView" 
      width="${someAttribute + someOtherAttribute}" 
 />

La valeur de someView.width est recalculée quand l'événement onsomeAttribute ou onsomeOtherAttribute est déclenché.

Dans l'exemple suivant :

<view name="beatles" width="${this.paul.width + 28}"> 
  <view name="paul" onclick="clickhandler()" > 
    <!-- méthode de gestion des clics de souris pour augmenter la largeur de paul suivant l'endroit où a cliqué l'utilisateur --> 
  </view> 
</view>

la largeur de beatles va augmenter ou réduire en fonction de la largeur de paul; l'expression this.paul.width + 28 est une contrainte.

Ceci est bien sûr un exemple trivial, mais il permet de comprendre qu'en déclarant la structure de vos objets en LZX, vous déclarez aussi les règles avec lesquelles ils sont liés entre eux. Les contraintes sont un des concepts fondamentaux de la programmation avec LZX, et apprendre à "penser LZX" revient surtout à apprendre à modéliser convenablement le comportement du système en terme de contraintes de ses différentes parties. Le Chapitre 24, Contraintes couvre en détails ce sujet.

4.1. Hiérarchies

Une application LZX est une hiérarchie d'objets, généralement des objets visuels, contenus dans un objet unique appelé Canvas. Rappelez-vous que les programmes LZX sont des documents XML dont canvas est la racine. Le programme LZX le plus simple est donc :

<canvas/>

Ce programme se compile et s'exécute, mais n'a aucune sortie. Comme le plus simple des objets visuels est la vue ('view'), un programme LZX minimal ressemble à ceci :

<canvas>
  <view>
    <text> Hello World!</text> 
  </view> 
</canvas>

Ce code définit clairement la hiérarchie de trois objets. Nous pouvons rendre plus visible leur relation visuelle en donnant au canvas et à la vue une couleur de fond.

Dans cet exemple simple, la hiérarchie lexicale dans le code correspond à la hiérarchie visuelle dans le canvas. En fait, l'objet <text> est l'instance d'une classe dérivée de <view>. Typiquement, les programmes LZX répètent cette séquence à une plus grande échelle : la toile contient des vues qui contiennent d'autres vues et ainsi de suite. Les classes sont utilisées pour reproduire des groupements de vues; des composants comme des boutons, des fenêtres, des champs de saisie ou des sélecteurs de valeurs sont quelques exemples de classes construites à partir de vues. 

LZX permet un grand nombre de façon de simplifier les relations entre vues. Par exemple, il y a plusieurs possibilités de mises en page ('layouts') pour gérer le placement des vues les unes par rapport aux autres. Elles sont décrites au Chapitre 16, Mise en page et Design.

Cependant, la relation entre la hiérarchie textuelle du code et la hiérarchie visuelle dans la toile n'est pas toujours aussi directe que dans l'exemple ci-dessus. En particulier, la puissante sémantique des liaisons de données de LZX permet à une simple balise <view> de générer la création d'un nombre aléatoire d'instances de l'objet view. Dans de tels cas, il est très important de décrire précisément les relations complexes entre objets. Le Chapitre 23, Views couvre en détail ce sujet.

4.2. Portée

Avec LZX, les concepts de portée locale ou globale sont les mêmes qu'avec JavaScript. Ceci dit, il faut noter que les règles en JavaScript peuvent surprendre un programmeur Java.

En JavaScript, toutes les variables sont globales, sauf si elles sont précédées du mot-clé var.

Ainsi

a= 7; // definit une variable globale a

et

var a = 7 // definit une variable locale a

Cette syntaxe implique par exemple que lors de l'assignation d'une variable dans une fonction, on peut modifier l'instance d'une variable globale. Ainsi :

for (a = 0; a <n; a++);

crée une variable globale appelée a, ou change la valeur de cette valeur si elle existe déjà. Ce que le programmeur voulait en fait écrire était :

for (var a = 0; a <n; a++);

En LZX, l'attribut name est local et l'attribut id est global. Ainsi

<canvas> 
  <view name="john" id="grandfather"> 
    <view name="john" id="father"> 
      <view name="john" id="son"/> 
    </view> 
  </view> 
</canvas>

est valide. La vue la plus basse peut être référencée Canvas.john.john.john ou simplement son.

Comme nous allons le voir, les fonctions créées en utilisant la balise <script> peuvent être appelées de n'importe où dans le programme. 

5. Accès aux données, Manipulation et Liaison

LZX est conçu pour écrire des applications commandées par des données dans lesquelles les valeurs des sources de données définissent l'apparence et les actions du programme. Cela est rendu possible grâce à des balises et des bibliothèques (APIs) qui permettent d'accéder aux données via http, de manipuler les données XML en mémoire puis, et c'est à noter, de lier la hiérarchie de données à la hiérarchie de vues. 

Les paragraphes suivants résument les éléments clé de l'architecture orientée données de LZX.

Référez-vous au V, Données et Liaison de données pour approfondir ce sujet.

5.1. Accès aux données

Les programmes LZX manipulent des données formatées en XML qui peuvent être :

  • embarquées dans le code du programme,

  • lues à partir d'une source quand le programme est compilé,

  • lues à partir d'une source quand le programme est en cours d'exécution.

Les sources XML sont formatées sous forme d'objets appelés 'datasets'. La balise <dataset> possède des attributs qui vous permettent par exemple de contrôler la mise en cache sur le client ou le serveur, d'inclure ou d'exclure des entêtes http, de gérer une file d'attente, et ainsi de suite. Les objets créés avec la balise <dataset> sont de type LzDatasets. Les méthodes de l'objet LzDatasets vous permettent par exemple de récupérer ou mettre à jour des données, des paramètres et ainsi de suite.

5.2.  Manipulation des données

LZX utilise des pointeurs de données (Datapointers), des objets qui représentent des pointeurs sur des noeuds de sources de données (datasets), pour se positionner et manipuler les données. Les pointeurs de données utilisent une partie de la norme XPath, une spécification standard du W3C pour décrire des chemins dans des documents XML, ou dans le cas de LZX, dans des sources de données. XPath utilise une notation similaire au système de fichiers Unix pour référencer des noeuds dans une source de données. Les pointeurs de données peuvent être repositionnés à la fois en utilisant des appels procéduraux tels que selectNext() ou en définissant un chemin XPath avec setXPath().

Grâce à son système très sophistiqué de reconnaissance des chaînes, la notation XPath est extrêment concise et puissante. Une simple expression XPath peut représenter un nombre aléatoire d'éléments XML. En utilisant des méthodes telles que addNode(), setNodeName(), setXpath(), et selectParent(), vous pouvez construire et manipuler des structures XML.

5.3. Liaison de données

LZX offre un moyen unique pour combiner un nombre alétoire de hiérarchies de données dans n'importe quelle hiérarchie d'affichage; cette fonctionnalité est appelée liaison de données. Elle est implémentée de telle façon que le contexte de données d'un noeud fils dans la hiérarchie d'affichage soit implicitement le même que celui de son père. Il est même possible de demander au système de créer un nombre quelconque d'élements dans une hiérarchie d'affichage pour représenter chaque élément des données sélectionnées. 

On réalise cela en liant des vues à des pointeurs de données. Un datapath est un type particulier de pointeur de données qui réalise explicitement le lien entre la hiérarchie de données et la hiérarchie d'affichage. Ainsi :

<view name="bob" datapath="testdata:/*">

où where testdata se réfère à une source de données définie plus tôt dans le programme.

C'est normal pour l'instant que cela paraisse un peu abstrait. Nous nous en tiendrons à cette courte description ici, une plus ample explication étant donnée au V, Données et Liaison de données; vous pouvez aussi étudier les exemples sur http://www.laszlosystems.com/demos pour bien comprendre ce qui peut être fait quand les applications sont vraiment commandées par les données.

Le point clé à comprendre est que si certains langages et technologies ont implémenté des algorithmes de liaison qui peuvent sembler similaires en première lecture, ce système de liaison est nouveau en ce qu'il permet la création d'objets qui gardent une connexion active avec les entités de la source de données.

6. Mélanger Balises et Script dans les programmes LZX

Comme nous l'avons déjà dit, presque tous les programmes LZX non triviaux contiennent à la fois des balises (XML) et du script. Les balises sont utilisées de façon déclarative, elles permettent de déclarer des objets et leurs attributs. Le script est utilisé de façon procédurale, pour définir explicitement une série d'étapes. Bien que ces deux façons de faire puissent être imbriquées avec LZX - par exemple, du script peut être placé dans des balises - chaque syntaxe est responsable de son intégrité locale. 

Par exemple, à l'intérieur de code déclaratif LZX, les commentaires apparaissent comme ceci :

<!-- commentaire XML -->

alors que dans du code JavaScript, ils apparaissent comme ceci :

// commentaire JavaScript

Ainsi, LZX est comme un alliage de deux métaux qui ne se combineraient pas chimiquement. 

Comme les parties déclaratives et procédurales d'un programme peuvent être ainsi mélangées, ce peut être un peu hardu au début de les reconnaître à l'intérieur d'un programme. Cependant, avec l'expérience, on finit par saisir la logique qui se cache derrière LZX et par ne plus faire attention aux changements de syntaxe. Les paragraphes qui suivent expliquent comment et pourquoi l'une ou l'autre des formes dans LZX. Référez-vous à la documentation de votre IDE ou éditeur de texte pour apprendre comment le faire utiliser la DTD ou le schéma de LZX afin qu'il identifie visuellement les parties du programme qui utilisent l'une ou l'autre des syntaxes. 

6.1. Comment mélanger balises et script

Commençons par voir ce qui est syntaxiquement correct et ce qui a une signification.

6.1.1. Ce qui est correct

Souvenez-vous que tous les programmes LZX sont des fichiers XML corrects. Cela implique que toutes les parties du programme, y compris le JavaScript embarqué, doivent se conformer aux règles du XML. Du coup, quand JavaScript utilise des caractères qui ont un sens en XML, comme le caractère inférieur <, vous devez vous assurer que ce caractère ne perturbe pas le parseur XML. Vous pouvez le faire de deux façons :

  • en remplaçant explicitement les caractères délimitateurs par une entité de référence. (L'entité de référence pour le caractère inférieur est &lt;).

  • en utilisant le constructeur XML CDATA pour définir un bloc de caractères bruts.

C'est l'ensemble des règles qui permettent de s'assurer que le XML n'interfère pas avec le JavaScript.

6.1.2. Ce qui a une signification

Bien que le mélange de deux ensembles de règles de langage puisse produire une certaine confusion, il est relativement simple de reconnaître comment les programmes LZX sont structurés, et savoir où mettre quel type de code. Il y n'a que quelques situations dans lesquelles du script puisse apparaître dans des programmes LZX. Après avoir appris à reconnaître ces situations, vous saurez quelle syntaxe utiliser. JavaScript est utilisé :

  • entre des balises ouvrante et fermante <script> et </script>,

  • entre des balises ouvrante et fermante <method> et </method>,

  • entre des guillemets, sur la partie droite d'une affectation à l'intérieur de certaines balises, comme pour oninit="script expression".

6.2. Quand utiliser les balises et quand utiliser du script

Comme nous l'avons vu précédemment, la plupart de choses que vous pouvez faire avec LZX peuvent l'être soit avec des balises XML soit avec les bibliothèques JavaScript, et maîtriser LZX revient à développer une subtile compréhension de comment et quand utiliser chaque méthode. Vous trouverez en général, que les balises sont plus appropriées pour les traitements qui peuvent être fait au moment de la compilation - comme organiser la mise en page de la toile - et que le script est plus adapté à ce qui a trait au fonctionnement, comme prendre en compte des actions utilisateurs. Mais pour pouvoir utiliser cette information, encore faut-il comprendre ce qui est fait au moment de la compilation et ce qui est fait lors de l'exécution, sachant que cela peut-être adapté en grande partie au problème que vous essayez de résoudre. 

En d'autres termes, il n'y a pas de règles simples qui définissent quand utiliser des balises ou quand utiliser du script. Mais il y a malgré tout des règles de bonne pratique qui s'appliquent à tous les programmes LZX bien conçus. 

Souvenez-vous que LZX est avant tout un langage pour manipuler des objets graphiques appelés vues (views). Donc la question de savoir quand utiliser des balises ou du script se pose généralement dans le cadre de la creation de vues et la manipulation de leurs attributs. Le script peut être utilisé à d'autres fins, comme pour des fonctions globales, mais dans ce cas, la nécessité d'écrire du code procédural (c'est à dire du script) est sans ambiguïté. La partie subtile est liée à la manipulation des vues et de leurs attributs.

Par exemple, une simple contrainte de deux mots peut exprimer une relation entre des vues qui aurait demandé trente lignes de code. La plupart du temps, les contraintes sont la meilleure solution, mais pas toujours. 

Bien qu'il n'y ait rien d'absolu, il y a des principes généraux qui décrivent la philosophie de développement avec LZX :

  • Utiliser des balises quand c'est la seule solution.

  • Utiliser JavaScript quand c'est la seule solution.

  • Si quelque chose peut-être fait soit à l'aide de balises soit à l'aide de script, utilisez les balises (à moins qu'il n'y ait de bonnes raisons de ne pas le faire).

Chacune de ces options est décrite brièvement ci-dessous.

6.2.1. Utiliser des balises quand c'est la seule solution

Il y a quelques balises qui réalisent des fonctions qui ne peuvent pas être appelées par du script. Par exemple, le noeud racine (et sa balise fermante) de tout programme LZX est <canvas>. Tout programme LZX commence donc par <canvas> et finit par </canvas>; il n'y a aucune structure alternative à base de script. De la même façon, il n'y a pas de script équivalent pour les balises <splash>, <method>, <attribute>, <resource>, <font>, et quelques autres balises encore. Egalement, avec certaines balises il y a quelques attributs qui ne peuvent être mis à jour que dans la balise elle-même.

6.2.2. Utiliser JavaScript quand c'est la seule solution

Il y a quelques bibliothèques JavaScript qui permettent d'exécuter des fonctions non accessibles aux balises. Par exemple, LzDelegate, LzEvent, LzParam et d'autres bibliothèques similaires ne sont pas accessibles aux balises. De la même façon, il y a quelques attributs d'objets qui peuvent seulement être référencés par du script, même si les objets ont été créés en utilisant des balises. Par exemple :

<view name="franklin">

Il y a un attribut, franklin.subviews, qui n'est accessible que depuis du script; il n'est pas possible d'accéder ou de modifier cet attribut avec une balise.

6.2.3. Si quelque chose peut-être fait soit à l'aide de balises soit à l'aide de script, utilisez les balises

Dans la grande majorité des cas où il est possible de faire quelque chose en utilisant soit des balises soit du script, il vaut généralement mieux utiliser les balises. Par exemple, vous pouvez créer une nouvelle vue appelée "sam" en utilisant des balises

<view name="sam">

ou du script

sam = new LzView();

Quand vous utilisez la syntaxe des balises vous pouvez assez naturellement créer une hiérarchie de vues imbriquées, définir des attributs comme des contraintes, et organiser votre code pour vous aider à conceptualiser l'organisation des vues dans le canvas. Obtenir ce résultat en pur JavaScript serait terriblement difficile et reviendrait à se priver des avantages du langage. Apprendre à penser LZX implique d'apprendre à penser en terme de vues qui fonctionnent de façon autonome en fonction des contraintes fixées à leur création. 

6.2.4. A moins qu'il n'y ait de bonnes raisons de ne pas le faire

Parfois, il vaut mieux écrire du code précédural que déclaratif. Cela peut devenir nécessaire, par exemple, pour optimiser les performances : de multiples systèmes à base de contraintes peuvent être gourmands en CPU. D'autres fois, du code procédural peut rendre le comportement de votre programme plus facile à comprendre : des systèmes complexes à bases de contraintes peuvent parfois devenir très difficiles à comprendre. 

7. Compilation et Execution

Les programmes LZX sont compilés par le compilateur OpenLaszlo, téléchargés sous forme de byte-code, et exécutés sur le poste client. Lors de l'écriture de vos programmes, vous pouvez choisir de faire des compromis entre les gains de performance par compilation, le temps de chargement et de lancement, et les performances de fonctionnement.

Comme dans d'autres langages de scripts comme Perl et Python, les programmes LZX s'exécutent de façon pratiquement linéaire. C'est à dire que si vous écrivez :

<view name="outside"> 
  <view name="inside"/> 
</view>

alors inside sera construit avant outside. Cependant, vous aurez souvent besoin de contrôler l'ordre dans lequel les objets sont construits ou initialisés. LZX vous donne un contrôle fin sur l'initialisation et l'instanciation des vues. 

La balise <splash> vous permet d'utiliser la toile pour l'affichage d'informations pendant que le programme s'initialise.