27
Oct/09
0

Amélioration des événements génériques an javascript

La problématique concerne la façon dont le MVC est addressé en javascript dans notre application.

Lorsque l’on veut répondre à un événement, on code de la façon suivante :

  1. création du lien HTML avec l’attribut data-event indiquant l’événement utilisé
  2. création de la fonction javascript permettant de répondre à cet événement
  3. création du code d’association entre l’attribut et la fonction

Ces cas sont représentés ainsi :

Création du lien :

<a href="xxx" data-event="eventStart">event</a>

Fonction javascript :

$.extend({
  eventStart: function() {
    console.log("eventStart fired");
  }
});

Code d’association :

$(document).bind("eventStart", $.eventStart);

La fonction utilisée afin de se substituer au click n’est pas représentée ici, elle peut être retrouvée dans un ancien article

Le problème est que l’on se retrouve rapidement à écrire une floppée de lignes d’association qui posent problèmes :

  • les lignes sont triviales et apportent beaucoup de bruit pour rien
  • introduit une duplication des noms d’événements non maintenable

Le mieux est de pouvoir inférer automatiquement ces lignes d’association à partir du javascript créé.

Résolution

Pour cela, on va stocker les événements génériques dans un autre espace de nom. On modifie donc nos événements en les stockant dans la clé events :

$.extend({
  events: {
    eventStart: function() {
      console.log("eventStart fired");
    },
 
    init: function() {
      $.each(this, function(key, value) {
        if (key != "init")
          $(document).bind(key, value);
      });
    }
  }
});

Et on rajoute par la même occasion, une fonction d’introspection qui permet d’associer toute fonction dans l’espace events à l’événement correspondant au nom de la fonction !

Il suffit alors de rajouter un comportement global de type :

$(function() {
  $.events.init();
}

Et tout lien qui possède l’attribut data-event sera associé automatiquement à une fonction correspondante dans l’espace events.

La restriction est que tout événement ne doit pas comporter de caractères spéciaux. Nos événéments précédent comme login:start doivent être renommés en loginStart.

Maintenant, le workflow est le suivant :

  1. indiquer l’événement dans le lien à travers l’attribut data-event
  2. écrire la fonction ayant le même nom dans l’espace $.events

Simplissime, j’adore.

Extensions

Certains événements sont définis dans des fichiers séparés afin d’aider à la maintenance de l’applicatif.

Dans ce cas, il n’est pas possible d’utiliser la même notation, et il devient nécessaire d’augmenter la définition de la table de hachage de la façon suivante :

$.extend($.events, {
  moreEvent: function() {
    ...
  }
});
Filed under: javascript
26
Oct/09
0

Debug du mode rewrite sous nginx

Pour voir ce qui est fait au niveau du module rewrite de nginx, ne pas oublier de modifier la configuration de la manière suivante :

décommenter la trace de type notice :

error_log  logs/error.log  notice;

déclencher le mode rewrite au niveau du serveur HTTP :

http {
  rewrite_log on;

Les étapes de réécriture apparaissent dans le fichier de trace /etc/nginx/logs/error.log.

Filed under: Config, nginx
26
Oct/09
0

Internationalisation des vues

Moteur de transformation

L’application est bien évidemment internationalisée et donc disponible en plusieurs langues.

Le principe est le suivant :

  • On ne travaille que sur un seul modèle de vue
  • Tous les textes sont traduits dans un fichier de propriétés
  • Les vues sont uniquement statiques, pas de traduction à la volée

Le premier point est d’utiliser un mécanisme permettant de traduire les clés des fichiers modèles en traductions. Il est possible de définir son propre mécanisme de traduction assez simplement… cependant, ici, il semble plus intéressant de se reposer sur l’API fournie par la dernière version de Rails, qui est disponible en tant que gem et utilisable de façon autonome.

22
Oct/09
0

Bibliothèque javascript Pure ou mécanisme interne ?

Le site fait une utilisation intensive d’échange de données JSON. Ces données doivent ensuite être réintégrées au niveau d’une structure de page HTML.

Par exemple, en prenant la structure suivante :

<div>
  <div class="title">Template title</div>
  <div class="body">Template body</div>
</div>

Un fragment JSON reçut de ce type pourra être facilement intégré :

[{"title", "my new title"}, {"body", "a comment"}]

chaque clé sera utilisée comme filtre afin de déterminer l’élément HTML dont le corps sera remplacé. La clé est transformée en sélecteur jQuery de classe (« .title ») et le code HTML de l’élément est alors remplacé par la valeur de la clé.

Jusqu’à présent, il m’était évident que ces transformations devraient être réalisées par la bibliothèque pure. C’est d’ailleurs ce qui a été fait jusqu’à présent, comme indiqué dans les premiers articles.

Cependant, il est peut être intéressant d’explorer également une voie de fonctionnement plus simple.

Pure fonctionne sur un mécanisme de templates ou modèle de code HTML : la structure HTML utilisée est dupliquée et le résultat affiché n’est qu’une copie de la source. Ceci permet de créer des fragments de code qui peuvent être réutilisés.

Le problème est que si on fait un « rendu » de la vue complète (le tag body) en espérant que seuls les éléments indiqués seront impactés, ce n’est pas tout à fait le cas. Tout le code HTML du body sera remplacé, et donc tous les événements javascript associés de façon non obtrusive aux tags seront effacés !

Pure ne peut pas travailler sur les éléments finaux.

Je ne sais pas encore si ce schéma est pénalisant pour l’application ou non, car la gestion des différentes « vues » ou « pages » applicatives n’est pas encore réalisé.

En attendant, il est facile de proposer une version dégradée de ce fonctionnement qui réalise un remplacement et non un écrasement :

$.fn.extend({
  autoReplace: function(data) {
    $.each(data, function(key, value) {
      $(this).find("." + key).html(value);
    });
  }
});

Le remplacement sera effectif, sans détruire les événements associés au code affiché. Les limitations sont que seules les directives simples liées à la classe d’un attribut HTML sont gérées.

A voir avec les développements suivants, si une version simpliste de ce système est suffisant ou si l’on doit utiliser un mécanisme complet et complexe (car pure gère plusieurs bibliothèques javascript, une précompilation des modèles, etc.).

16
Oct/09
0

Modification des violations de vérification des données utilisateur

La liste des violations de données utilisateurs est structurée comme suit :

[{"login", "required"}, {"login", "min"}, {"pwd", "required"}]

Le problème est que la syntaxe JSON n’est pas correcte, et une des erreurs sur le login ne sera pas visible au niveau du javascript (du fait qu’il y a plusieurs clés identiques).

On modifie donc les validateurs pour qu’ils ne renvoient plus que la règle et non le tuple, par exemple le code suivant :

validator(Field, Value, required) ->
  case string:len(Value)==0 of
    true -> {Field, <<"required">>};
    false -> ok
  end.

devient :

validator(Value, required) ->
  case string:len(Value)==0 of
    true -> <<"required">>;
    false -> ok
  end.

Le paramètre Field n’est plus nécessaire.

C’est la méthode validate/3 qui sera chargée de produire le tuple final. On commence d’abord par écrire un test unitaire permettant de vérifier le comportement attendu :

test() ->
  ...
  [] = validate("login", [{"login", "a"}], [required]),
  [{"login", [<<"required">>,<<"min">>]}] = validate("login", [{"login", ""}], [required, {min_length, 6}]),
  ok.

On modifie alors la fonction pour satisfaire les tests :

validate(Field, Data, Constraints) ->
  Value = proplists:get_value(Field, Data),
  Errors = lists:map(fun(Constraint) -> validator(Value, Constraint) end, Constraints),
  Final = lists:filter(fun(Error) -> case Error of ok -> false; _ -> true end end, Errors),
  case Final == [] of
    true -> [];
    false -> [{Field, Final}]
  end.

Le reste du code est inchangé.

Filed under: Erlang
16
Oct/09
0

Validation de formulaires en Erlang

Problématique

L’envoi des données de formulaire se fait par Ajax également.

Il est nécessaire de pouvoir sérialiser le formulaire afin d’envoyer les données sur le réseau, ainsi que de brancher le mécanisme côté serveur pour récupérer et valider les données.

Côté client, la sérialisation d’un formulaire se fait tout simplement en utilisant les mécanismes jQuery ; rien de spécial ici, on commencera par sérialiser un formulaire particulier avant de passer à une généralisation.

Côté serveur, nous allons mettre en oeuvre la récupération des données et leur validation. Tout ce qui vient du client doit être considéré comme non sûr et potentiellement corrompu.

La validation serveur est donc un processus absolument primordial. La pré-validation cliente est accessoire et ne sera pas traitée pour le moment.

Cette validation cliente participe à l’amélioration de l’expérience utilisateur. Pour notre part, avec l’architecture particulière mise en place où seuls les éléments mis à jour transitent entre le client et le serveur, on espère que la validation serveur ne sera pas trop pénalisante et donc suffisante dans un premier temps.

6
Oct/09
0

Mise en oeuvre de l’authentification (3 - niveau navigateur)

On met en oeuvre la partie utilisateur/interface.

Tout d’abord, on rajoute un lien dans l’en-tête du site afin de diriger sur l’url /login.html (priv/templates/views/index.haml) :

  %body
    #header
      #ids
        Guest
        %a{ 'data-event' => "login:start", :href => "/login.html" } (login)

Ce lien possède un attribut particulier data-event. Cet attribut est correct selon les normes HTML 5, et peut être utilisé sans problème dès aujourdh’ui. Pour plus d’informations, vous pouvez lire cet article de John Resig.

Cet attribut personnalisé va nous permettre de définir des liens demandant un déclenchement d’événement lors d’un click. Cet événement est la valeur de l’attribut lui même. Le comportement générique sera de ne pas déclencher le click normal (navigateur) mais de le remplacer par le déclenchement de l’événement.

2
Oct/09
0

Vim et Rake

La structure de notre projet implique des phases de pré-processing permettant soit de compiler des sources en binaires, soit de transformer des modèles de vues en fichiers cibles.

Ces actions sont réalisées via le gestionnaire de tâches rake. Ces actions sont effectuées pour l’instant en ligne de commandes. Par exemple :

$ rake -T
rake build      # Build the sources
rake clean      # Clean workspace
rake compile    # Compile the sources
rake db:create  # Initialise a database
rake edoc       # Create documentation
rake front      # Preprocess views and styles
rake release    # Packaging
rake start      # Start application
rake test       # Unit tests
 
$ rake front
Creating style /d/apps/gns/priv/www/assets/styles/application.css
 
$

Nous allons intégrer ces commandes au sein de Vim afin de simplifier le processus (ne pas avoir à jongler entre les fenêtres) et l’automatiser (ne rien oublier afin de ne pas s’énerver parce que ça ne marche pas !).

2
Oct/09
0

Gestion générique des appels Ajax

Le fonctionnement au niveau du navigateur est revu, et on pose les briques de base pour une gestion générique des événements Ajax au niveau de l’interface.

Pour cela, jQuery offre de nombreux points de rattachement lorsqu’une requête Ajax est déclenchée.

Notre but sera de programmer des comportements génériques de la façon la plus personnalisable et en essayant de rester au plus près du style de programmation jQuery.