Débugger Javascript - John COLIBRI. |
- résumé : un script Javascript qui affiche sur la page Web des message de mise au point
- mots clé : Javascript - débugger - log - journal - TEXTAREA
- logiciel utilisé : Windows XP, Delphi 6.0
- matériel utilisé : Pentium 1.400Mhz, 256 M de mémoire, 140 Giga disque dur
- champ d'application : Delphi 1 à 2005 sur Windows
- niveau : développeur Delphi
- plan :
1 - Introduction Pour effectuer des traitements Web du côté client (validation de saisie,
affichage de grille, navigation, analyse XML ...), nous pouvons utiliser soit des exécutables téléchargés (ActiveX, Java), soit des scripts clients (JavaScript, VBScript). Comme certains internautes (y compris moi) interdisent
le téléchargement sur leur machine d'exécutables ayant la possibilité d'effectuer n'importe quel traitement, les ActiveX sont souvent refusés. Restent donc les scripts. Nous avons opté pour JavaScript. Pas de gaîté de
coeur, oh non. Mais il n'y a pas d'autre moyen d'effectuer des traitements Client sans exécutable.
Javascript est interprété, et il n'y a pas de compilateur pour vérifier la
syntaxe. De plus le langage est "sans erreur": une faute de syntaxe, la plus minime fut-elle, interrompt l'interprétation sans aucun message. Même Basic savait afficher "Syntax Error".
Cet article présente ici un petit script que nous utilisons dans toutes nos aventures au pays JavaScript et qui nous permet simplement de produire des traces indentées de l'exécution des scripts. La copie, quasi conforme, de
display que nous utilisons en Delphi depuis pratiquement 10 ans.
2 - Principe 2.1 - L'affichage Pour afficher sur une page Web, nous allons utiliser un contrôle Memo (TEXTAREA
en HTML) auqel nous ajoutons les lignes du journal. Notre page par défaut a l'allure suivante: - la moitié de gauche comporte la zone de traitement "normale"
- la moitié de droite comporte le Memo avec deux boutons (ou ancres) pour
tester l'affichage et vider le Memo (clear):
2.2 - L'affichage Le script du journal (log) comporte deux fonctions:
- do_display(p_texte) qui affiche le message, en indentant au besoin et en défilant le texte du Memo
- do_clear_display() qui purge le Memo
Notons que nous avons utilisé do_display() plutôt que display() pour réduire les risques de collision avec un quelconque display() qui existerait dans d'autres scripts ou librairies Javascript système.
3 - Le Log Javascript 3.1 - Le script Voici le texte de notre page debug.html:
<HTML> <HEAD> |
<SCRIPT language="JavaScript"> var g_indentation=0;
function do_display(p_string) {
var spaces="";
if (p_string.substring(0, 1)=="<") {
g_indentation-= 2; }
for (l_index=0; l_index< g_indentation; l_index++) {
spaces+= " "; }
l_memo_ref= window.document.debug_form.debug_memo;
l_memo_ref.value += spaces+ p_string + "\n";
l_memo_ref.scrollTop = l_memo_ref.scrollHeight;
if (p_string.substring(0, 1)==">") {
g_indentation+= 2; } } // do_display
function do_clear_display() {
window.document.debug_form.debug_memo.value= ""; } // do_clear_display
</SCRIPT> | </HEAD> <BODY>
<TABLE border= 1 width=100%><TBODY><TR>
<TD width=40% valign=top> |
<SCRIPT> function display_ok()
{ do_display("ok");
} // display_ok // g_total= 3 -;
function has_error(p_value) {
do_display("> has_error");
if (p_value= 5) {
do_display("in_test_5");
} // l_total= 3 -;
do_display("< has_error"); } // display_ok
</SCRIPT> |
<A href="#" onClick="display_ok(); return false;">display_ok</A><BR>
<A href="#" onClick="has_error(3)">has_error</A><BR><BR>
</TD> <TD valign=top>
<!-- debug display -->
<TABLE border= 0><TBODY>
<TR><TD>
<A href="#" onClick="do_display('Hello'); return false;">test</A>
<A href="#" onClick="do_clear_display(); return false;">clear</A>
</TR></TD>
<TR><TD>
<FORM name="debug_form">
<TEXTAREA name="debug_memo" rows=10 cols=40></TEXTAREA>
</FORM>
</TR></TD>
</TR></TBODY></TABLE>
</TD>
</TR></TBODY></TABLE> </BODY>
</HTML> | |
Notez que: - le script du Log a été placé directement dans l'en-tête <HEAD> de la page
- nous accédons au Memo par
l_memo_ref = window.document.debug_form.debug_memo; | - et nous ajoutons du texte par
l_memo_ref.value = l_memo_ref.value+ "xxx"; | - l'instruction:
permet de défiler le Memo pour laisser la dernière ligne ajoutée visible
- la globale g_indentation nous permet de gérer l'indentation:
- la valeur initiale est 0
- si le texte à afficher comporte ">" en premier caractère, nous post-incrémentons l'indentation de 2
- si le texte à afficher comporte "<" en premier caractère, nous pré-décrémentons l'indentation de 2
La page contient deux exemples d'utilisation: - l'ancre "display_ok" affiche ok dans le Memo
- l'ancre "has_error" met en évidence une erreur:
- nous appelons has_error(3)
- nous testons
qui réussit alors que le test devrait échouer. La raison est que nous avons utilisé l'affectation C = au lieu du test ==
Notez aussi que l'affichage ne résoud pas tous les problèmes. Si nous insérons une erreur de syntaxe dans "has_error" (la partie en commentaire actuellement dans le .HTML):
ou, pire, des guillemets en nombre impair:
l'interprète Javascript interrompt tout traitement:
- la frappe pour appeler "has_error" ne présentera pas les textes du log (pas même le texte AVANT l'erreur)
- le click sur "display_ok" sera aussi inopérent
La seule solution est par conséquent un travail incrémental très prudent: - frappe de quelques lignes
- test
- frappe de quelques lignes
- test
- etc.
Et en cas d'absence de réponse:
- mise en commentaire /* */ de toutes les parties ajoutées, et sortie progressive des lignes ajoutées
- éventuellement retour à la dernière version qui marche, et ajout par couper / coller des nouveautés
3.2 - Mon bêtisier Javascript Parmi les erreur que je commets le plus souvent: - utilisation de = au lieu de == dans les tests
- erreurs de majuscules
var table= new array() ... innerHtml ... |
au lieu de var table= new Array() ... innerHTML ... |
- oubli des parenthèses du constructeur ou des appels de fonction
var table= new Array;
l_result= compute_total; | au lieu de
var table= new Array(); l_result= compute_total(); |
- à l'intérieur d'un constructeur, utilisation de VAR au lieu de THIS
function f_c_table()
{ var m_row_count= 0; } | au lieu de
function f_c_table() { this.m_row_count= 0;
} | (VAR est légal pour une variable utilisée localement, mais permet pas de déclarer un attribut de l'objet) - et parallèlement, oubli de THIS pour accéder à un attribut
function f_c_table() {
this.m_row_count= 0; function display_table() {
for (l_indice=0; l_indice< m_row_count; l_indice++) { ... }
} // display_table } // f_c_table | au lieu de
function f_c_table() { this.m_row_count= 0;
function display_table() {
for (l_indice=0; l_indice< this.m_row_count; l_indice++) { ... }
} // display_table } // f_c_table | - déclaration de variables ou de fonctions ayant le même nom
function f_c_table() { var l_value= 0;
... var l_value= "Delphi"; } |
(la seconde déclaration est légale, mais "masque" la première) - erreurs de guillemets
l_name= "alice'; l_name= 'alice"; l_name= "alice; | - erreur d'orthographe
function f_c_table() {
this.m_row_count = 0; ... this.m_row_coun += 1;
} // f_c_table | - erreur de frappe (l'astérisque qui traîne à la fin de la ligne)
Mentionnons que je ne fais du Javascript que depuis quelques semaines, et que je suis convaincu que je parviendrai sans effort à faire encore beaucoup
d'erreurs plus étranges et bizarres dans le futur.
4 - Améliorations Nous pourrions - envoyer les messages de log sur une autre page
- utiliser <DIV> au lieu de <TABLE> pour partitionner notre page
- ajouter les messages dans une zone <DIV> plutôt que d'utiliser un TEXTAREA
- envoyer les texte de l'affichage dans un fichier "log.js", au lieu de le
charger dans chaque page que nous débuggons
5 - Télécharger le code source Vous pouvez télécharger: Ce .ZIP qui comprend: - le .DPR, la forme principale, les formes annexes eventuelles
- les fichiers de paramètres (le schéma et le batch de création)
- dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonome)
Ces .ZIP, pour les projets en Delphi 6, contiennent des chemins RELATIFS. Par conséquent: - créez un répertoire n'importe où sur votre machine
- placez le .ZIP dans ce répertoire
- dézippez et les sous-répertoires nécessaires seront créés
- compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.
La notation utilisée est la notation alsacienne qui consiste à préfixer les identificateurs par la zone de compilation: K_onstant, T_ype, G_lobal,
L_ocal, P_arametre, F_unction, C_lasse. Elle est présentée plus en détail dans l'article La
Notation Alsacienne
Comme d'habitude: - nous vous remercions de nous signaler toute erreur, inexactitude ou
problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
- tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
- plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
- et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos
blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.
6 - L'auteur
John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le
conseil (composants, architecture, test) et la
formation. Son site contient des articles
avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et
UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client. |