KrISS feed 8.7 - A simple and smart (or stupid) feed reader. By Tontof
  • Sunday 09 February 2014 - 01:00
    Les nom et permalien de ce post ont été générés automatiquement à l’aide de rakefile… Envisageant de raffiner l’architecture et le design de ce site personnel destiné à quelques futurs tests d’indiewebification. Bien d’accord avec vous, ce site bien que fonctionnel demeure vraiment très moche (et qui plus est, ennuyeux au possible !). Ne souhaitant pas tomber dans la facilité d’installer un magnifique thème pré-construit sans rien y comprendre, je me donne encore quelques mois pour étudier quelques fondamentaux CSS avant de m’aventurer sur les pentes escarpées du « look and feel ».
  • Tuesday 11 February 2014 - 19:50

    De nos jour, les raccourcis claviers sont de plus en plus utilisés dans des applications web. Si Google Doc était l'un de ceux qui ont popularisé cette pratique, elle n'est aujourd'hui plus seulement restreinte au traitement de texte.

    Nous allons voir aujourd'hui les mécanismes qui entrent en jeu pour capturer les raccourcis saisis par l'utilisateur, et comment les employer. Cet article peut sembler un peu long, mais il vise à expliquer le maximum de notions, qui sont trop souvent oubliées ou simplifiées dans les tutoriels sur le sujet.

    Je parle avant tout de raccourcis claviers, mais sachez que tout ceci peut vous être utile dans d'autres cadres, comme la validation de champs de formulaire au fil de la saisie, par exemple.

    1. Les évènements
    2. L'objet KeyboardEvent
    3. Exemple d'exécution
    4. Remplacer un raccourci navigateur
    5. Méthode de contournement pour Firefox
    6. Conclusion

    Les évènements

    Il existe, en Javascript, 3 évènements différents générés par l'utilisation d'une touche de votre clavier :

    1. keydown / onkeydown : comme son nom l'indique, il est déclenché lorsque la touche est enfoncée.
    2. keypress / onkeypress : on dirait un synonyme de keydown. Il est d'ailleurs déclenché juste après, toujours quand on enfonce la touche.
    3. keyup / onkeyup : c'est le fait de retirer son doigt de la touche qui le déclenche.
    Quelle est l'utilité d'avoir 2 évènements différents (keydown et keypress) pour la même chose, me direz-vous ?

    Comme l'explique ce blogueur, il faut avant tout distinguer les touches servant à écrire des caractères (lettres, chiffres, caractères spéciaux, etc...) des autres touches (Contrôle, Majuscule, Alt, Windows/Commande, etc...). Les évènements keydown et keyup expriment le fait d'enfoncer ou relâcher une touche de votre clavier, quelle que soit sa fonction. Par contre keypress exprime théoriquement le fait d'écrire un caractère.

    Je dis "théoriquement" car tous les navigateurs n'ont pas exactement le même comportement à ce propos. Tout ce qu'il faut retenir pour le moment, c'est que l'évènement keypress pourra être déclenché par l'appui sur la touche "A", mais pas par l'appui sur la touche "Contrôle".

    L'objet KeyboardEvent

    Habituellement, en Javascript, quand on réalise une fonction appelée sur un évènement, celle-ci prend en paramètre un objet de type Event. C'est la variable ev dans les exemples ci-dessous :

    <script>
    window.onload = function(ev) {
        ev.preventDefault();
    }
    
    document.getElementById('myId').addEventListener('click', function (ev) {
        console.log( ev.target.className );
    });
    </script>
    

    Dans le cadre d'évènement issus des touches clavier, cet objet sera de type KeyboardEvent. C'est lui qui indique quelle touche (ou combinaison de touches) a été enfoncée. Voici une liste de ses attributs qui pourront nous être utiles :

    • keyCode (entier) : code numérique représentant de façon unique chaque caractère. La table des codes peut différer d'un navigateur/système à un autre (tableau comparatif entre les navigateurs)
    • Attributs indiquant si d'autres touches étaient enfoncées avant que celle-ci le soit aussi :
      • altKey (booléen) : indique si la touche Alt était enfoncée ou non
      • ctrlKey (booléen) : indique si la touche Ctrl était enfoncée ou non
      • metaKey (booléen) : indique si la touche Meta (Windows sur Windows, Commande sur Mac) était enfoncée ou non
      • shiftKey (booléen) : indique si la touche Majuscule était enfoncée ou non

    Parmi les attributs non cités ci-dessus, on retrouve char, charCode et which, qui sont dépréciés, et doivent être remplacés par key, qui n'est pas actuellement implémenté (un comble !). En fait, même keyCode est déprécié, et sera remplacé par key au final (ils ont des fonctionnements très proches), mais en attendant, on continue à l'utiliser. Pour une liste exhaustive des attributs, RTFM.

    Exemple d'exécution

    Imaginons que vous souhaitez effectuer une combinaison de touches (prenons par exemple Ctrl+S, comme quand vous voulez sauvegarder une page). Dans la pratique, voici dans l'ordre les évènements qui ont lieu, ainsi que les valeurs des attributs de l'objet KeyboardEvent dans chaque cas (testé sur Firefox) :

    1. keydown (on vient d'appuyer sur "Contrôle")
      • keyCode = 17 (code correspondant à la touche "Contrôle")
      • altKey = false
      • ctrlKey = true
    2. keydown (on vient d'appuyer sur "S")
      • keyCode = 83 (code correspondant à la touche "S")
      • altKey = false
      • ctrlKey = true
    3. keypress (on vient d'appuyer sur "S", la touche "Contrôle" est toujours enfoncée)
      • keyCode = 83 (code correspondant à la touche "S")
      • altKey = false
      • ctrlKey = true

    On constate bien que keypress n'a pas lieu quand on appui sur "Contrôle". De même on constate que quand on appui sur "S", les évènements keydown et keypress se suivent et comportent des informations identiques.

    Mais du coup keydown nous suffit amplement, à quoi bon s'intéresser à keypress ?

    Vous avez parfaitement raison ! En théorie cet évènement est dépriécié (comme le reste de DOM L3. La norme HTML5 apporte, comme l'indique doc de Mozilla, un remplaçant dans l'évènement input).

    Hélas, tout ceci n'est bien que cela : de la théorie. Vous allez pouvoir vous en rendre compte dans le chapitre suivant.

    Remplacer un raccourci navigateur

    Reprenons notre exemple de raccourci : Ctrl+S. Si vous l'employez sur une page web dans votre navigateur, ce dernier vous proposera probablement d'enregistrer une sauvegarde de la page courante (c'est le cas de Firefox et Chrome, et sans doute d'autres).

    Imaginons que vous réalisez une application web de prise de note (au hasard, Jotter). Vous aurez besoin de laisser la possibilité à vos utilisateurs de sauvegarder ce qu'ils ont saisi vers le serveur de votre appli. Vous savez aussi que, sauf besoin très spécifique, ils n'auront pas besoin de sauvegarder le HTML de la page en cours vers leur ordinateur.

    Naturellement, vous décider de remplacer le fonctionnement par défaut de votre navigateur par celui de votre application. Voici le code de base pour le réaliser :

    document.addEventListener('keydown', function (e){
        if(e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) {
            e.preventDefault();
            //app-specific code goes here
        }
    });
    

    Décorticons ce code. On commence par vérifier si l'évènement est survenu sur la combinaison de touches Ctrl+S grâce aux attributs ctrlKey et keyCode. 'S'.charCodeAt(0) est une manière plus lisible d'indiquer le code de la lettre S (qui est 83 dans tous les navigateurs).

        if(e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) {
    

    Ensuite, on demande d'annuler l'effet par défaut associé à cette combinaison de touches :

            e.preventDefault();
    

    Il ne reste ensuite plus qu'à réaliser les actions spécifiques à notre application (comme par exemple faire une requête ajax pour enregistrer sur le serveur les données saisies par l'utilisateur). C'est ce que j'ai désigné par :

            //app-specific code
    

    Si vous utilisez ce code, vous constaterez que, en fonction du code spécifique que vous ajoutez, parfois Firefox proposera malgré tout à l'utilisateur de sauvegarder la page sur son ordinateur. Et là, vous vous dites :

    ... et vous avez parfaitement raison !

    Explication fumeuse : Firefox se base sur keypress pour gérer les raccourcis clavier qu'il a de définis (ce qui n'est pas forcément le cas des autres navigateurs, à vérifier). Jusqu'ici tout va bien. Il respecte en théorie la norme qui dit que si l'évènement par défaut de keydown est stoppé (via .preventDefault()), alors celui de keypress devrait l'être aussi.

    Et Firefox le fait, la plupart du temps. Mais il suffit que votre code "app-specific" contienne certains bouts de code (comme un bête alert()) pour que .preventDefault() ne suffise plus. En fait, même si vous utilisez l'un des deux bouts de code ci-dessous, rien n'y fera, et Firefox exécutera quand même le :

    document.addEventListener('keydown', function (e){
        if(e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) {
            e.preventDefault();
            e.stopPropagation();
            //app-specific code
        }
    });
    

    Ou :

    document.addEventListener('keydown', function (e){
        if(e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) {
            //app-specific code
            return false;
        }
    });
    

    Le pire est que dans ce cas précis, l'évènement keypress verra son Event.keyCode à 0 au lieu de 83 (pour S)...

    Méthode de contournement pour Firefox

    Du coup, la solution consiste à contrôler dès le keydown si on doit annuler l'évènement keypress, puisque ce dernier n'est même plus capable de savoir quelle touche a été enfoncée :

    //must be accessible from both keydown and keypress events
    var cancelKeypress = false;
    
    document.addEventListener('keydown', function (e){
        if(e.ctrlKey && e.keyCode == 'S'.charCodeAt(0)) {
            //do this prior to anything else
            cancelKeypress = true;
    
            //might still be useful for other browsers
            e.preventDefault();
    
            //app-specific code goes here
        }
    });
    
    //workaround for Firefox:
    document.addEventListener('keypress', function (e){
        //must probably be done prior to anything else
        if(cancelKeypress === true) {
            e.preventDefault();
            cancelKeypress = false;
        }
    });
    

    Je vous l'avais bien dit que ce satané keypress nous servirait à quelque chose.

    Conclusion

    Vous avez désormais une base vraiment solide pour gérer les évènements clavier en Javascript. Nous avons abordé les logiques générales, et le reste pourra généralement se trouver dans la doc.

    Nous avons malgré tout pu constater que certaines spécificités des différents navigateurs rendaient ce sujet un peu plus complexe que prévu. Si ces spécificités sont parfois documentées, vous aurez sans doute souvent à farfouiller les forums ou expérimenter par vous même pour trouver réponse à vos questions.

    J'ajouterai aussi que même si les raccourcis claviers dans une appli web, ça peut avoir la classe, n'oubliez pas que cela n'est pas toujours judicieux, et que si vous remplacez les comportements d'un navigateur par quelque chose de nouveau, cela peut déstabiliser vos utilisateurs, au risque de les rendre insatisfaits.

    Keep typing & rock on

  • Wednesday 12 February 2014 - 16:33
  • Tuesday 25 February 2014 - 01:00
    Just finished an upgrade of the default @jekyllrb blog theme. https://t.co/hpLZs2RS4R (or preview it: http://t.co/QAJmm9wS8Q) — Joel Glovier (@jglovier) 24 Février 2014 Cela fait quelques jours que je savoure avec grand intérêt les évolutions de Joel sur son repo jekyll-new, le nouveau template qui sera implémenté par défaut dans la version 2.0. à venir de Jekyll (motorisation puissante de génération de sites web). Très simple et épuré, ce template se montre au premier coup d’oeil carrément plus élégant et pro que la version « out-of-the-box » existante qui décorait ce site…
  • Monday 03 March 2014 - 12:44
    Je n'ai jamais trop aimé l'idée d'exprimer mes opinions politiques sur internet. Je tenais juste à partager ce lien qui m'a fait envisager le sujet sous un angle différent.

    via http://shaarli.h3b.us/?d9ivVA
    (PS : yeah, H3bus is back et son shaarli aussi :-) )
    (Permalink)
  • Tuesday 04 March 2014 - 15:04
    Ca y'est, moi aussi j'en ai marre : exit les flux RSS des Joies du Code et de BashFr...

    J'ai mis quelques jours avant de me rendre compte à quel point le désagrément occasionné (et le temps perdu) dépassait le plaisir apporté.
    (Permalink)
  • Wednesday 05 March 2014 - 14:34
    Je suis surpris de ne pas avoir vu ça plus tôt, tiens.
    Un bête <noscript> avec une balise ouvrante <a> et pas de balise fermante. Résultat : toute la page devient un lien vers la pub...

    Je viens de voir ça sur Les Echos (version mobile) : http://m.lesechos.fr/industrie-services/le-gouvernement-annonce-25-mesures-pour-encourager-l-usage-du-velo-0203350767071.htm

    Note : c'est un cas restreint, qui concerne le site mobile des Echos, et uniquement si on bloque TOUT le Javascript (dont celui du site) et que je n'ai constaté que sur Firefox. Mais dans le principe, je trouve ça tout de même un peu dérangeant...
    (Permalink)