Tag: ajax

Prototype, Ajax, aide à la saisie et touche ENTREE

Posted by – December 17, 2007

Introduction

Le billet suivant souhaite démontrer l’utilisation des événements javascript, notamment avec Prototype, sur un cas d’utilisation d’apparence simple : l’utilisation de la touche ENTREE sans déclencher le post du formulaire, mais uniquement une requête Ajax.

L’exemple se base sur du code ASP.NET et Prototype.

Contexte

Imaginons dans un formulaire la possibilité de rechercher une ou des personnes (par le début du nom par exemple), sous forme d’aide à la saisie, par un appel Ajax qui retourne une liste correspondante à la recherche :

L’utilisateur a le choix : cliquer sur Rechercher ou …valider sa saisie par la touche ENTREE. Dans ce dernier cas, si on ne fait rien, le formulaire entier sera envoyé, ce que l’on ne souhaite pas : on veut envoyer une requête Ajax au serveur, pour avoir une liste de personnes, en sélectionner une puis continuer la saisie du formulaire

Evènements & Prototype

Avec Prototype, nous allons utiliser l’évènement key_press sur le champ de saisie : déclencher une méthode lors de la pression de la touche ENTREE, celle-ci désactivera tous les autres évènements (notamment la validation du formulaire), et exécutera notre fonction Ajax.

Dans la mesure du possible, le javascript se voudra non intrusif (recherche Google) : au lieu de mettre les appels de fonctions sur chaque attribut d’évènement (par exemple onkeypress=”mafonction()” pour un input text, ou un onclick=”mafonction()” sur un href), on les mettra en fin de formulaire et on les chargera tout en une fois. Cela a le mérite de pouvoir le désactiver très facilement, et dans la méthode de développement, de se concentrer sur le formulaire, pour ensuite (une fois que cela fonctionne), s’attaquer à l’ajout du javascript sur le code fonctionnel.

Extrait de code

L’extrait suivant est composé de code ASP.NET, et de code Javascript (Prototype).

<fieldset style="border: 1px solid grey;">
<asp:TextBox runat="server" ID="TxtLibelle"></asp:TextBox>
<asp:HyperLink ID="LinkRecherche" runat="server" Text="Rechercher" NavigateUrl="javascript:void(0);" CssClass="normal"/>

<div id="dSearchresult" style="position: absolute; background-color:White;" class="start">
<div id="dClosed" style="width:100%; text-align:right; margin-bottom: 5px;"><a id="lnkFermer" class="normal"><img src="/images/pict_close.gif" title="fermer" alt="fermer"/></a></div>
<div id="dValues"></div>
<div id="dLoading">
<img src="/images/spinner_bleu.gif" alt="Loading"/>
<span class="normal">Recherche en cours...</span>
</div>
</div>
</fieldset>

<script type="text/javascript">
function recherche()
{
new Ajax.Request('recherche.ashx'
{ method: 'get', parameters:
{searchString:$F('<%=TxtLibelle.ClientID %>'),
action: 'findIndividu'},
onComplete:onSearchComplete
});
}

function initialize () {
Event.observe ('<%=LinkRecherche.ClientID%>','click',recherche);

Event.observe ('<%=TtxtLibelle.ClientID%>','keypress',
function(evt){
if(evt.keyCode==Event.KEY_RETURN)
{
Event.stop(evt);
recherche();
}
}
);
} // initialisation des évènements après que la page est chargée

Event.observe(window, 'load', initialize, false);

</script>

Conclusion

Ce petit exemple montre simplement l’usage du javascript à l’aide de Prototype, qui, généralement est boudé par les développeurs1. Avec l’avènement d’Ajax, le JS est revenu au gout du jour, même si quelques bonnes pratiques sont conseillées pour sa mise en place :

  • utilisation de frameworks/libraires : Prototype, jQuery, …ou d’avatars tel que Prototip
  • que le code soit non intrusif
  • installer Firebug pour le débuggage

1 avouons que la maintenance se révéle souvent hasardeuse

Prototype et Scriptaculous compressés

Posted by – December 3, 2007

Prototype et la librairie Scriptaculous pèsent à elles-seules au bas mot 150 ko : 100 ko pour Prototype et le reste selon l’usage de Scriptaculous (effets, contrôles, …). Aussi, il reste toujours intéressant d’optimiser1 un peu le chargement d’une page en prenant une attention particulière sur les éléments suivants : cache (serveur, client, pages, portions de page), viewstate, images, CSS, et javascript.

Pour le dernier point2, le groupe Prototype Core offre une version compressée des 2 librairies, réduisant ainsi leur utilisation à 80 ko, c’est à dire 50 % de leur poids initial.

A l’heure actuelle, nous utilisons la version protopacked_v2.16b.zip3, celle-ci couvre les versions 1.5.1.1 (packer) de Prototype et 1.7.1 b3 (packer) de Scriptaculous. Une version sous forme d’un seul fichier pour les dernières versions est disponible (non testée pour ma part) : protoaculous1.6.packed.js

Publicité : un livre vient de sortir (en anglais) sur les toutes nouvelles versions des librairies (1.6.0 & 1.8.0), écrit par un français (Christophe Porteneuve), plus d’informations ici.

1 promis, dès que le temps me le permet, j’écris un article sur l’optimisation du développement Web, le temps, toujours le temps qui manque ;)

2 on pourrait aussi bien utiliser un module de compression par exemple, qui compresserait à la volée les JS. Dans notre cas, ce module est déjà utilisé, mais la version de l’époque ne permettait pas la compression des JS, mais uniquement du flux d’une page aspx.

3 tourne maintenant sur notre plateforme depuis quelques mois sans encombre

UTF-8 : linux, windows, mac, everything, everywhere

Posted by – October 9, 2007

Hier, un ami m’a demandé un coup de pouce pour déboguer un problème d’appel Ajax qui ne fonctionnait pas sous IE (alors que sur la page de démo cela marchait, et sur FF également, damned !) : champ de saisie, propositions de mots, autrement dit de l’autocomplétion.

Voyant les caractères renvoyés par la requête Ajax, c’est à dire des ”?” ou tout autre caractère ésotérique, ni une ni deux, l’origine fut trouvée : l’ISO-8859-1. A défaut, l’usage de la fonction utf8_encode a été la parade pour convertir la donnée à la volée.

La majorité des librairies Ajax (Prototype par exemple) ont un encodage par défaut à UTF-8 (et c’est bien !).

Une parade c’est bien, prendre l’habitude d’utiliser l’UTF c’est mieux. C’est la norme actuelle et future, fini les codespages à n’en plus finir. Tout logiciel sérieux devrait le gérer, on trouve encore trop souvent l’usage de l’encodage ISO-8859-1 (ou 8859-15 pour les windowsistes). Autant que faire se peut (un lourd existant peut l’empêcher par ex.), l’usage de l’UTF devrait être naturel.

Quelques trucs et astuces afin d’obtenir sur la majeure partie de la chaine de production une compatibilité UTF-8 :

  • pour le Web, cela passe par un document enregistré en utf-8, et un charset à utf-8 :
 <meta http-equiv="Content-type" content="text/html; charset=utf-8" />  
  • sous Apache, la directive AddDefaultCharset utf-8 peut s’avérer utile
  • un équivalent en ASP.NET pour forcer l’encodage de sortie, ou d’entrée, dans la section du web.config, la directive globalization :
 <globalization requestEncoding="utf-8" responseEncoding="utf-8"/>  
  • accès SSH : fixer sous puTTY l’UTF-8 (Windows / translation)
  • Debian : installer les locales qui vont bien et les positionner à UTF-8 (un excellent article pour Unix) :
 $ locale : affiche les locales pour le terminal $ dpkg-reconfigure locales : pour installer et fixer la locale par défaut $ export LC_ALL=fr_FR.UTF-8 pour fixer manuellement  
  • vim : un :set fileencoding vous indiquera si vous enregistrez en UTF, ou vous permettra de fixer l’encodage du fichier.
  • iconv sera votre compagnon pour la convertion de fichiers ISO-8859-1 en UTF-8
  • mysql >= 4.1 gère l’UTF en natif. Un “SET NAMES utf-8” indique l’encodage d’échange entre le client et le serveur. MySQL 5.0 charsets et collations (MySQL 4.1)
  • SQL Server : ntype (nvarchar, ntext, …) est ton ami

Quelques ressources que j’ai pu glaner sur le Net.

Ami PHPiste, Rubyiste, Javaiste, .NETiste, Perliste, kayakiste (euh non), à bon entendeur…

Lightbox extension : copier/coller d’un texte

Posted by – April 29, 2007

Objectif (pourtant simple…)

A partir d’un formulaire, le but est de remplir 2 champs par un “Copier/Coller” à partir d’une modal. Dans notre cas, selon un intitulé (de poste), on propose à l’utilisateur des choix de libellés qui s’en rapprochent. Celui-ci clique alors sur celui qui lui convient, puis a la possibilité de copier les missions/profil de la fiche qu’il a choisie : le but étant de faciliter la recopie de texte.

Formulaire initial avec les 2 champs à remplir automatiquement :

Champs initiaux à remplir

Suite à la saisie d’un libelle (de poste), l’utilisateur peut choisir parmi un ensemble de proposition, lors du clic, une modal s’ouvre avec la fiche afférente au poste :

Sélection d’un libellé

Sur la fiche de poste, l’utilisateur peut cliquer sur copier, ce qui a pour effet de fermer la modal et de recopier les 2 champs Missions/Profil dans les 2 champs du formulaire initial.

Modal de la fiche poste

Champs recopiés

Défaut

Lors de la recopie, on copie les innerHTML des 2 éléments <p> vers les 2 textarea (elt.value). Le contenu peut contenir du HTML qu’il faut enlever pour la textarea destinatrice. Egalement les <br/> contenus dans les innerHTML sont à remplacer par des \
(sinon cela serait illisible).

Constat : IE parait rendre <BR _extension=”true”> au lieu des <br/> contenus dans innerHTML de l’élément.

Explications

J’ai étendu la classe Lightbox (perfectible d’ailleurs au niveau de sa conception1) afin de permettre notamment une copie d’un contenu (d’un bloc <p> avec du contenu issu d’une précédente saisie, avec du HTML) vers une <textarea> (ou un <input type=”text”>), ce qui oblige à remplacer les <br/> par des retours chariots (\
) pour une meilleure visibilité.

Lightbox permet d’étendre assez facilement les comportements, en appliquant des handlers (utilisation de l’attribut rel=”fonction” aux éléments <a> marqués par une classe lbAction), j’ai donc utilisé cette possibilité pour simuler un copier/coller.

Le code se traduit par :


var modal = Class.create();
modal.prototype = Object.extend(lightbox.prototype, {
initialize: function(ctrl) {
this.content = ctrl.href;
this.hrefid = ctrl.id;
Event.observe(ctrl, 'click', this.activate.bindAsEventListener(this), false);
ctrl.onclick = function(){return false;};
},
copy: function() {
var d = document.getElementsByClassName('dCopyContent');
var s = $('lbContent').getElementsByClassName('sCopyContent');
for(i = 0; i < s.length; i++) {
Try.these (
function()
{
//sous IE : <BR _extended=""true"">
d[i].value = s[i].innerHTML.replace(/<(br).*?\\/?>/gi,'\ ');
// fct prototype bien sympa : stripTags
d[i].value = d[i].value.stripTags();
}
)
}
this.deactivate();
},
loadInfo: function() {
var myhrefid = this.hrefid;
var valueParams = Try.these(
function() {
return $F('paramname'+myhrefid)+'='+$F('paramvalue'+myhrefid);
},
function() { return ''; });
var myAjax = new Ajax.Request(
this.content,
{ method: 'post',
parameters: valueParams,
onComplete: this.processInfo.bindAsEventListener(this)} );
}
}
);

et le code (X)HTML (exemple) :


<div id="lightbox" class="done" style="display: block;">
<div id="lbContent">
<div style="height: 500px;"><span style="margin: 0pt 10px 0pt 0pt; float: right; background-color: white;">
<a rel="copy" class="lbAction lienInterne" href="#">Copier</a> <a rel="deactivate" class="lbAction" href="#"><img style="border-style: none; width: 20px; height: 20px; vertical-align: middle;" src="/images/pict_close.gif"/></a></span><br/>

<div style="overflow: auto; height: 350px; background-color: White;" id="container">
<div style="background-color: White;" id="fichemodele">
<div id="headeroffre">
<span class="intituleposte">Conseiller(e) en entreprise</span>
</div>
<div id="fiche">
<fieldset style="width: 470px;">
<h2 class="titreParagraphe">Missions</h2>
<p class="normal sCopyContent">- Assurer les visites et contacts avec les entreprises et les conseiller dans le domaine d’hygiène, sécurité ; gestion de production<br/>- Mettre au point et valider les cahiers des charges, réaliser des études & diagnostics et/ou mettre en contact avec un spécialiste<br/>- Etablir des rapports, suivi, préconisations<br/>- Mettre sur pied des actions collectives (Plasturgia, Journée Régionale de la Prévention, SMS…)<br/>- Organiser des réunions à thèmes (sécurité, BTP…)<br/>- Instruire, monter, réaliser des dossiers d’aides financières<br/></p>
<h2 class="titreParagraphe">Profil</h2>
<p class="normal sCopyContent">- H/F 30 ans et +<br/>- Formation ingénieur avec connaissances générales en organisation de production, qualité, sécurité, hygiène, gestion<br/>- Expérience du milieu industriel indispensable<br/>- Maîtrise des outils bureautiques<br/>- Rigueur, organisation, sens de l’animation, sens relationnel<br/>- Très grande disponibilité<br/>- Permis B et véhicule exigés</p>
</fieldset>
</div></div>
</div>
</div>
</div>
</div>

Dans la méthode copy, bien que les tags utilisés soient <br/>, IE me ramenait :

 <BR _extended="true"> 

lors de la lecture du contenu elt-p.innerHTML. Aussi j’ai été obligé de rajouter ce cas dans la Regexp de substitution, qui au lieu de

s[i].innerHTML.replace(/<(br)\\/?>/gi,'\
');

devient

s[i].innerHTML.replace(/<(br).*?\\/?>/gi,'\
');

Tout ça pour dire que j’ai perdu pas mal d’heures avant de m’apercevoir qu’IE modifiait le contenu du innerHTML, la substitution fonctionnant bien sous FF…bref ;)

Si quelqu’un a une explication rationnelle, je suis preneur.

1 Le principal reproche étant que l’auteur ait intégré la fonction initialize() et son appel dans le même fichier lightbox.js, cela aurait été plus judicieux de l’incorporer dans un autre, cela pour assouplir la possibilité d’extensibilité de la classe.

Scriptaculous , auto-remplissage & ASP.NET

Posted by – January 11, 2007

Scriptaculous est une librairie de composants développée à l’aide de Prototype, un framework Javascript qui facilite bien la vie du développement JS. Ces 2 librairies sont intégrées à Ruby on Rails, ce qui leur confère une pérennité assurée !

Premier test d’intégration d’un champ rempli automatiquement dans une page aspx : concluant !

L’objectif pour un projet (en ASP.NET), était de rendre plus ergonomique l’aide à la saisie concernant la sélection d’un intitulé. Pour cela, l’auto-remplissage sous forme d’un liste de choix est un bon moyen pour l’utilisateur de retrouver ce qu’il souhaite. Cette aide se déclenche au bout du 4ème caractère saisi.

J’ai utilisé Ajax.Autocompleter, méthode qui permet, de façon simple, d’appeler un script chargé de ramener une liste d’éléments, sous forme d’une liste <ul> <li>choix1</li> <li>choix2</li> </ul>

Le composant est utilisé dans une page aspx, et appelle un handler, page ayant une extension .ashx, chargée d’interroger la base de données puis de ramener les propositions.

1ère étape

Inclure les bibliothèques dans l’entête head de la page :

<head> <script type="text/javascript" src="/inc/script.aculo.us/prototype.js"</script> <script type="text/javascript" src="/inc/script.aculo.us/scriptaculous.js"</script> </head>

2ème étape

Positionner les éléments (div, controle textbox, …) pour l’utilisation du composant :

1. <asp:textbox id=TBIntitule Runat="server" Columns="80" />
2. <span id="spinner" style="display: none"><img src="/images/spinner_orange.gif" alt="Recherche..." /></span>
3. <div id="autocomplete_choices" class="autocomplete"></div>
4. <script type="text/javascript">
//<![CDATA[
new Ajax.Autocompleter("<%=TBIntitule.ClientID %>", "autocomplete_choices",
'<%=Page.ResolveUrl("~/Recherche/search.ashx") %>',
{method: 'post', paramName: "searchvalue",
minChars: 3, indicator: 'spinner', frequency: 0.4});
//]]>
</script>

Explications :

  1. le champ de saisie (sera transformé en <input type=text ...id='TBIntitule'/>
  2. le bloc d’affichage de l’image d’attente (spinner) lors du déclenchement de la recherche (voir d’autres exemples d’images animées utilisées pour ce type de recherche)
  3. le bloc où sera affichée la liste des propositions, sous forme <ul><li></li><li></li></ul>
  4. le code script.aculo.us qui gère la mécanique d’appel Ajax et de retour des réponses à afficher, dans l’ordre des paramètres : le (DOM) id du champ de recherche, l’id de la div d’affichage, le script de recherche (ici un handler ashx, un web service, ou un aspx reste possible), les options du composant (méthode GET ou POST, paramètre passé au script, déclenchement au bout du minChars caractère, l’id du bloc spinner, et la fréquence de déclenchement 0.4 s).

3ème étape

Ecriture du script pour notre exemple.

J’ai opté pour une solution simple : écriture d’un petit handler ashx pour répondre à la requête Ajax. L’avantage de ce type de script est qu’il est simple à mettre en oeuvre, et surtout peu coûteux en ressources (vs. un aspx ou un web service SOAP).

Source de la page search.ashx en C# :

public class search : IHttpHandler, System.Web.SessionState.IRequiresSessionState  
{
private string _search(string strSearch)
{
IClassificationManager mgr = ClassificationMgr;
IIntitulePoste[] intitules = mgr.GetIntitulesPostesByString(strSearch, 4);
StringBuilder myreponse = new StringBuilder();

myreponse.Append("<ul>");

for (int i = 0; i < intitules.Length; i++)
myreponse.AppendFormat("<li>{0}</li>", ((IIntitulePoste)intitules[i]).Libelle);

myreponse.Append("</ul>");

return myreponse.ToString();
}

public new void ProcessRequest(HttpContext context)
{
string strSearch = context.Request.Form["searchvalue"];

if (! String.IsNullOrEmpty(strSearch) )
context.Response.Write(_search(strSearch));
else
context.Response.Write("<ul></ul>");
}

public new bool IsReusable
{
get { return true; }
}
}

System.Web.SessionState.IRequiresSessionState : si la classe implémente cette interface alors une ouverture de session sera demandée, dans le cas d’un intranet/extranet, évite que le .ashx soit public (dans le cas où une session est soumise à une authentification).

4ème étape : affinage des résultats avec du style

Le résultat étant formé de <ul><li></li></ul>, il faut y appliquer un style afin de rendre plus utilisable la liste (sans les points . , mettre une couleur sur le choix courant, …). Le résultat est rendu dans <div id="autocomplete_choices" class="autocomplete"/>, appliquons un style à cette class :


div.autocomplete { position:absolute; width: 200px; background-color:white; border:1px solid #888; margin:0px; padding:0px; z-index: 1000 }
div.autocomplete ul { list-style-type:none; margin:0px; padding:0px; }
div.autocomplete ul li.selected { background-color: #ffb;}
div.autocomplete ul li { list-style-type:none; display:block; margin:0; cursor:pointer; }

Ce premier exemple, permet de voir très rapidement l’avantage et l’apport d’Ajax dans le Web 2.0, pour un meilleur service à l’utilisateur !

A vos claviers !

Votre charpente tient-elle la route ?

Posted by – December 15, 2006

La vague Web 2.0 déferle sur la toile, et apporte pour l’utilisateur une réelle valeur ajoutée à l’utilisation des applications Web .

Parmi les technologies utilisées, nous retrouvons Ajax, 1ère brique fondatrice du phénomène Web 2.0.

D’après 01net, Ajax dope l’ergonomie des applications Web . Afin d’arriver à cet état de fait, les développeurs doivent se doter d’outils, notamment de frameworks Javascript. Ces frameworks doivent être capables de gérer toute la tuyauterie sous-jacente à Ajax (compatibilité des navigateurs, appels, rendus, …), et donc in fine de simplifier son développement, sa maintenance, et sa capacité à évoluer.

Parmi les frameworks existants, on pourra citer :

  • Atlas : le framework de Microsoft, qui sera bientôt intégré à l’IDE Visual Studio.
  • Prototype : la librairie de bas niveau utilisée par bon nombre de librairies.
  • Script.aculos.us : une librairie Javascript développée comme une sur-couche à Prototype : auto-remplissage, effets, drag & drop, …
  • Rico : Basée aussi sur Prototype, apporte un ensemble assez riche de composants : drag & drop, effets, …

…il en existe une bonne cinquantaine, à vous de faire le bon choix selon vos besoins, et la qualité du module.

Personnellement, je m’orienterai vers Prototype, framework très lié au développement de Ruby on Rails (donc en théorie pérenne), tout en étant utilisable sans celui-ci.

Nouveau bouquin : “Bien développer pour le Web 2.0, bonnes pratiques Ajax”

Posted by – December 11, 2006

Achat de “Bien développer pour le Web 2.0” après avoir vu plusieurs bonnes critiques de ce livre et parce que je connais le blog de l’auteur , qui m’a plu.

L’intérêt pour moi est de revoir mes classiques (XHTML & co), et surtout un rappel des bonnes pratiques dans le domaine, après quelques années de pratique, on a tendance à oublier les bases ou d’être passé à côté des nouveautés ;)

Le 2ème objectif est de toucher à Ajax, et plus particulièrement à Prototype et Scriptaculous, frameworks très séduisants au demeurant.