KrISS feed 8.7 - A simple and smart (or stupid) feed reader. By Tontof
  • Wednesday 04 September 2013 - 11:00

    Voilà un titre accrocheur (qui rime et tout ! J'ai même réussi à éviter de citer le slogan de notre bon président !).

    Je me suis bien amusé avec Blogotext, mais voilà : j'avais envie de renouveau, et Pluxml me faisait de l'oeil depuis un petit moment.

    Le nouveau portail

    Je sais que la réorganisation d'un site web n'est pas toujours vue d'un très bon oeil (liens URLs cassés, visiteur habituel un peu perdu, etc...). Mais c'est aussi ça avoir son propre hébergement : la liberté de publier ce que l'on veut quand on le veut, et de tout chambouler quand ça nous chante. Et je refuse que quiconque me retire ce droit ! 8-)

    Par contre, je vous présente mes sincères excuses pour le thème. J'ai cédé à la vague de mode "épuré", et suis parti du thème de base de Pluxml, qui est assez light. Je vous ai tout de même pondu une charte de couleurs maison inspirée du thème de colo syntaxique "Earthsong" que j'utilisais déjà pour le code. J'espère que Bronco ne rouspètera pas pour la disparition du thème acidulé. ;-)

    Migration Blogotext ⇒ Pluxml

    Pour migrer de Blogotext à Pluxml mes articles et commentaires, je me suis réalisé un petit script à l'arrache. Pour ceux que ça intéresse, le je voici :

    » blogotext2pluxml.zip «

    Il n'est pas parfait (j'ai dû corriger quelques articles après coup...), donc utilisez à vos risques & périls.:$

    Shaarli

    J'en ai profité pour enfin rendre public mon shaarli, et pour l'intégrer le plus possible au reste du site. Pour cela, je me suis inspiré de l'intégration qu'Arthur a réalisé. Ouais, je ne suis rien qu'un sale copieur (merci pour le code et les réponses à mes questions, au passage :-) ).

    Faut dire que le principe est sympa (bien qu'un peu cheapos) :

    Je ne poste pas beaucoup de liens, mais je l'utiliserai pour les petites annonces (du genre "nouvelle version de tel ou tel script/CMS").

  • Tuesday 10 September 2013 - 16:05

    Hier, Bronco nous faisait découvrir Kint, un outil pour PHP de deboguage et d'affichage de variables assez poussé.

    Je n'avais pas vraiment envie d'installer tout une librairie dans mes projets pour remplacer ma fonction de debug, mais cela m'a donné quelques idées d'améliorations.

    EasyDump revoit donc complètement l'affichage de variable qu'on fait habituellement avec notre cher var_dump.

    Fonctionnalités

    Avantages et fonctionnalités :

    • <pre> : l'affichage est automatiquement encadré d'un <pre> pour que vous n'ayez pas à le faire.
    • Affichage compact : réduit sensiblement l'espace pris comparé à var_dump
    • Mise en forme : un peu de couleurs pour y retrouver ses petits (cette version s'inspire de mon très cher Earthsong, encore !)
    • Htmlentities : les variables qui contiennent du code html/xml ne seront pas interprétées, mais bien affichées textuellement
    • Noms courts : des noms de variables très courts sont disponibles pour faciliter la saisie (inspirés là encore de Kint dans sa version lite)
    • Multi dump : Comme pour var_dump et Kint, vous pouvez passer plusieurs variables en même temps à EasyDump.

    Axes d'amélioration :

    • Nom des variables : contrairement à Kint (mais comme var_dump), EasyDump n'est pas capable d'afficher le nom des variables que vous lui transmettez. C'est très compliqué à faire, mais serait bien utile lorsqu'on enchaine les dumps...
    • Paramétrer les couleurs : pour que chacun puisse personnaliser le bousin en fonction des besoins/envies.
    • Type "objects" : Les variables de type "objects" sont actuellement affichées via un var_dump, et je ne sais pas trop comment faire autrement.

    Utilisation

    1. Téléchargez le code ici (ou sur Github pour la dernière version) et placez le dans le dossier de votre projet.
    2. Importez le fichier d'EasyDump :
      require_once( 'easydump.php');
      

      Puis appelez simplement les fonctions d'affichage :

      $var1 = "toto";
      $var2 = array(
          'titi' => 'tonton',
          'tata' => 'toutou',
      );
      EasyDump::debug($var1, $var2, 756);
      
      //immediatly stop the script after the dump:
      EasyDump::debugExit($var1, $var2, 756);
      
    3. Pour simplifier la saisie, des noms de variables très courts sont possibles (si vous n'utilisez pas déjà ces noms dans votre code) :
      d($var1, $var2, 756);    //same as EasyDump::debug()
      de($var1, $var2, 756);   //same as EasyDump::debugExit()
      

    Et voilà le résultat :

    Et maintenant ?

    J'améliorerai au fil du temps en fonction de vos remarques et mes besoins. Peut-être même que je mettrai ça sur Github, un de ces 4...

    Keep dumping & rock on, baby!

    Edit 11/09/2013 à 14h : petite correction sur l'affichage des booléens (affichage de "true" et "false" au lieu de "1" ou rien du tout). Le lien de téléchargement a été mis à jour.

    Edit 16/09/2013 à 15h : prise en compte des ressources (opendir, fopen et autres...) et améliorations mineures. Publication sur Github.

  • Wednesday 13 November 2013 - 17:20

    J'ai terminé il y a peu le roman "Digital Fortress", de Dan Brown, et je ne résiste pas à l'envie de vous en parler.

    Pour Rappel, Dan Brown est l'auteur à succès qui nous a apporté Da Vinci Code et Anges et Démons. Digital Fotress est son tout premier roman, sorti en 1998, et parlant... des cryptographes de la NSA.

    Et c'est fou comme son oeuvre est criante de vérité. Alors bien sûr, il ne faut pas oublier qu'il s'agit d'une oeuvre de fiction. Mais les parallèles avec l'affaire Snowden sont assez faciles à faire. D'autant plus que, comme je le disais, cette oeuvre date de 1998, période à laquelle la NSA n'avait pas encore l'excuse du 11 Septembre 2001.

    L'histoire

    Je vais vous spoiler un peu le livre : l'héroïne, Susan Fletcher, bosse pour la section Crypto de la NSA, sous la direction de Trevor Strathmore. Vers le début, le livre évoque leurs déboires avec l'EFF (définition) et les implications éthiques de leur antagonisme (ça commence plutôt bien), puis le scandale causé par Strathmore quelques années auparavant lorsqu'il avait glissé une backdoor dans un algo de cryptage destiné au grand public, mais révélé par un cryptographe de génie (que la NSA a fini par engager).

    D'autres méthodes douteuses (et fictives ? :D) de la NSA y sont évoquées, et même employées au cours du récit, à commencer par le mensonge (justification de l'emploi d'outils de surveillance de masse en grossissant les chiffres du terrorisme), les assassinats ou les arrestations injustifiées des opposants pacifistes, etc....

    Au moment où se déroule le récit, ces trois personnages travaillent sur TRANSLATR, un super-ordinateur gigantesque tournant 24h/24 et 7j/7 pour brute-forcer (définition) des fichiers cryptés en tous genres. Il passe généralement entre 1/2 seconde et 11 minutes sur chaque fichier.

    La méthode de collecte des fichiers craqués par TRANSLATR n'est pas précisée, même si une organisation complexe découpée en services est décrite, laissant facilement imaginer un PRISM pas loin.

    Un génie du nom d'Ensei Tankado, ancien de leur service mais qui les avait quittés pour des raisons morales (Edward Snowden, c'est toi ?), sort un nouvel algorithme soi-disant incraquable, et ne le révèle qu'à un nombre limité de personnes, dans le but de faire du chantage à la NSA : "révélez l'existence de votre TRANSLATR ou bien je file mon algo à tout le monde et vous ne pourrez plus jamais lire les conversations privées des gens". Il fournit le code source de son algo publiquement, mais sous forme cryptée (via ledit algo), et menace de fournir la clé sous 24h la clé permettant d'accéder au code source.

    Evidemment, TRANSLATR se casse les dents sur le fichier, et commence alors une course contre la montre pour mettre la main sur la clé.

    Conclusion

    Je ne vous en raconte pas plus pour ne pas trop vous spoiler. Je vous conseille la lecture de ce roman, qui réserve de nombreuses surprises comme Dan Brown en a le secret, dont quelques révélations qu'on peut qualifier aisément "d'actualité".

    Et je félicite l'auteur pour avoir su retranscrire l'un des nombreux univers de l'informatique sans raconter n'importe quoi, et tout en sachant le rendre accessible à tous. Chapeau, ce n'était pas une mince affaire... et le plus fou, c'est que rien de ce qu'il aborde n'a vieilli, à l'exception peut-être des valeurs (volume de stockage et vitesse de téléchargement)

    Oh, et dernière remarque : le livre évoque le fait qu'en 1998, seuls 3% des américains sont au courant de l'existence de la NSA. Je me demande si ce chiffre est véridique...

  • Friday 15 November 2013 - 12:40

    • Si vous rêvez de gérer vos notes en ligne
    • Si vous voulez un outil simple, léger et agréable
    • Si vous voulez héberger votre propre équivalent à KeepNote / EverNote

    Alors Jotter est fait pour vous !

    Jotter [ˈdʒɒtə]

    UK, noun: a small book with blank pages for recording notes.

    Jotter est un petit gestionnaire de notes en ligne à héberger sur votre serveur. Il est réalisé en PHP et ne nécessite pas de base de données.

    Principales fonctionnalités :

    • Editeur WYSIWYG moderne pour plus de confort, avec raccourcis claviers pour la sauvegarde et la mise en forme
    • Organistion des notes sous forme d'arborescence dans un bloc-note
    • Gestion de plusieurs blocs-notes
    • Gestion multi-utilisateur
    • Pas de base de données : tout est stocké sous forme de fichiers plats (JSON et Markdown)

    Téléchargement et informations

    Le projet est disponible sur sa page GitHub. Edit : et une démo est disponible à cette adresse.

    Vous y trouverez les dernières mises à jours, un guide d'installation, les fonctionnalités prévues pour les versions futures, les informations de license, etc...

    Comme toujours, je vous invite à me transmettre toute remarque ou question à propos de Jotter, par mail ou via GitHub. Par contre, petit aveu : j'ai voulu faire léger, et j'ai parfois mis de côté la qualité du code. Ce n'est pas le plus beau code que vous verrez de moi... ^^'

    Keep calm & take notes

    Edit 2013-11-22 : une première mise-à-jour avec des correctifs et améliorations ergonomiques est disponible sur Github. Aperçu :

    La suite devrait se passer là-base aussi :-)

  • Monday 16 December 2013 - 16:30

    Je viens de me réaliser un petit script de "batch download" en PHP (téléchargement par lot, en bon français) et me disais qu'il pourrait être intéressant de vous le partager avec quelques petites explications.

    L'histoire

    Comme vous le savez peut-être déjà, le site Wallbase.cc (merveilleux site de wallpapers, sans pub, très agréable à naviguer et très bien fourni) est en train de mourir depuis quelques mois, du fait de la disparition de son administrateur.

    De plus, depuis peu quelqu'un (par le biais d'un bot ?) est en train de supprimer tous les fonds d'écran du site, et les modérateurs galèrent à freiner ce problème. Ils conseillent donc de télécharger les wallpapers qu'on a mis en favoris avant que ceux-ci ne disparaissent.

    C'est donc ce que j'ai fait, aidé d'un script Greasemonkey pour récupérer plus rapidement les liens de téléchargement. Ensuite, j'aurais pu donner un petit coup de DownThemAll! et le tour était joué. Mais j'ai préféré scripter ça et envoyer direct sur mon propre serveur.

    Edit 2013-12-17 : j'ai même l'impression que c'est pire que cela. Le forum ne semble plus accessibles (certains fichiers manquants ?). Mais si c'est effectivement une attaque, elle me semble plutôt étrange...

    Le principe

    En réalité, tout repose sur une fonction PHP bien simple nommée copy(). Celle-ci permet, comme vous vous en doutez, de copier un fichier d'un emplacement à un autre, et ce même depuis une URL (du moins depuis PHP 4.3).

    Ainsi, pour copier une image d'un autre serveur vers le votre, il suffit de faire :

    $result = copy(
        'http://www.example.com/image.jpg', /* other server */
        '/var/www/my-images/image.jpg'      /* your server */
    );
    

    Le reste de mon script n'est en fait qu'un ensemble de commodités :

    • multiples URLs : saisie dans un textarea des URLs de tous les fichiers à récupérer (une URL par ligne)
    • Erreurs : affichage d'un log des réussites et échecs de téléchargement
    • Téléchargement groupé : compression de tous les fichiers dans un ZIP pour pouvoir les télécharger en une fois

    Vous pouvez vous-même choisir le nom du zip généré. Si vous demandez à regénérer un zip du même nom, l'ancien sera écrasé. Ainsi, si vous avez besoin d'en créer plusieurs en vue de les récupérer plus tard, c'est possible.

    Configuration requise

    • PHP 4.3 ou supérieur (à vérifier, PHP 5 conseillé)
    • Droits d'écriture sur le dossier où vous placerez le script. A noter que des sous-dossier et des fichiers zips seront créés et supprimés, il est donc préférable de donner au script son propre dossier.

    Le code complet :

    Edit : J'ai créé un Gist correspondant, où je pourrai faire d'éventuelles révisions, et où vous pourrez me faire vos remarques.

    <!doctype html>
    <!--
    PHP Batch Download Script
    
    @author Yosko <www.yosko.net>
    @copyright none: free and opensource
    @link https://www.yosko.net/article32/snippet-05-php-telechargement-de-fichiers-par-lots
    -->
    <html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <title>Batch Downloader</title>
        <style>
    textarea {
        width: 100%;
        min-height: 10em;
    }
        </style>
    </head>
    <body>
        <h1>Batch Downloader</h1>
    <?php
    
    //config
    error_reporting(E_ALL | E_STRICT);
    ini_set('display_errors','On');
    set_time_limit ( 180 ); //facultative: to avoid timeout
    ob_flush(); flush();
    
    //recursive rmdir from php.net
    function delTree($dir) {
        $files = array_diff(scandir($dir), array('.','..'));
        foreach ($files as $file) {
            (is_dir($dir.'/'.$file)) ? delTree($dir.'/'.$file) : unlink($dir.'/'.$file);
        }
        return rmdir($dir);
    }
    
    $errors = array();
    $urlString = '';
    
    //a list of URLs to download was given
    if(isset($_POST['urls'])
        && isset($_POST['directory'])
        && strpos($_POST['directory'], '..') === false
        && strpos($_POST['directory'], '/') === false
    ) {
    ?>
        <ul>
    <?php
        
        $urls = explode(PHP_EOL, $_POST['urls']);
        $directory = trim($_POST['directory']);
        if(empty($directory)) { $directory = 'files'; }
        $zipFile = $directory.'.zip';
        
        //temporary directory to put the files into
        if(!file_exists($directory)) {
            mkdir($directory);
        }
        //temporary archive file for download
        if(file_exists($zipFile)) {
            unlink($zipFile);
        }
        
        //try and download each file
        foreach($urls as $url) {
            $url = trim($url);
            $filename = basename($url);
            $success = copy($url, $directory.DIRECTORY_SEPARATOR.$filename);
            if($success) {
                echo '<li>'.$filename.' : OK</li>';
            } else {
                $errors[] = $url;
                echo '<li>'.$filename.' : KO (source = <a href="'.$url.'">'.$url.'</a>)</li>';
            }
            ob_flush(); flush();
        }
        
        //zip files
        $zip = new ZipArchive();
        if ($zip->open($zipFile, ZIPARCHIVE::CREATE) === true) {
            foreach (glob($directory.'/*') as $file) {
                $zip->addFile($file);
            }
            $zip->close();
        }
        
        //delete directory
        delTree($directory);
    
    ?>
        </ul>
        <p>
            <?php echo count($urls); ?> file(s),
            <?php echo count($urls) - count($errors); ?> successe(s),
            <?php echo count($errors); ?> error(s)
        </p>
        <p>Download <a href="<?php echo $zipFile; ?>"><?php echo $zipFile; ?></a></p>
        <p>Errors :</p>
        <ul>
    <?php foreach($errors as $error) { ?>
            <li><?php echo $errors; ?></li>
    <?php } // end loop on errors ?>
        </ul>
    <?php } // end form post ?>
        <form method="POST" target="">
            <input type="text" name="directory" placeholder="Destination file...">.zip
            <textarea name="urls" placeholder="Put each URL on a different line">
    <?php
    foreach($errors as $error) {
        echo $error.PHP_EOL;
    }
    ?></textarea>
            <input type="submit" name="submitURLs" value="Download">
        </form>
    </body>
    </html>
    

    Conclusion

    Certes, le code est encore un peu grossier ("rough around the edges", j'ai envie de dire). Mais à défaut de la vie, il m'aura au moins sauvé mes favoris Wallbase.cc. Comme toujours, si vous avez des critiques ou questions, je suis à votre écoute :)

    Keep calm & download!

  • Tuesday 17 December 2013 - 14:00

    On a le sentiment de célébrité lorsqu'on s'étonne d'être cité par des personnes qu'on estime célèbres elles-mêmes, qu'on respecte, voire qu'on vénère. Mais finalement, la célébrité, n'est-ce pas s'étonner d'être cité par des personnes qu'on ne connait justement pas ?

    Tout ça pour dire qu'après de nombreux autres, j'ai eu le droit moi aussi à mon effet sebsauvage, et plusieurs fois même.

    L'histoire

    Pour ceux qui dormiraient dans une grotte depuis plus de deux ans (je ne vois que ça, parce que parmi mes lecteurs, qui ne lit pas sebsauvage ?), l'effet sebsauvage est l'effet que sebsauvage a sur les visites d'un site autre que le sien rien qu'en partageant un lien vers ledit site via son shaarli.

    Y'avait pas mal de monde à être passé par là :

    Mais le plus important, ce que l'effet sebsauvage n'est pas la cause uniquement de Seb. En fait il n'est que l'élément déclencheur. Ce sont les nombreux visiteurs, ces gens connus ou inconnus, qui viennent grossir les logs de connexion de nos serveurs chéris.

    Et moi, et moi, et moi ?

    J'en avais rêvé. Eh bien j'ai eu non pas un effet, non pas deux effets, non pas trois effets, non pas quatre effets, non pas cinq effets, non pas six effets, mais bel et bien sept effets sebsauvage ! Note 1

    Sans plus attendre :

    Comme dirait Alban, Achievement Unlocked :

    Achievement Unlocked - Explosez vos stats en vous faisant citer par Seb

    A noter que les deux plus petits sont en fait des coups de pouce de Bronco et Timo :)

    Shaarli, Nawel et ouverture

    Attention : cette section de l'article est bourrée de petits coeurs et de sentiments niais et dégoulinants. Lisez-la à vos risques et périls.

    Du coup, merci à toi, Seb, et merci à tous les autres blogueurs ou shaarlieurs gravitant dans la même blogosphère et ayant éprouvé un quelconque intérêt à mes propos. Pour vous, je m'engage à persister dans mon travail et mes écrits pour vous apporter encore et toujours plus de choses qui éveilleront votre curiosité.

    D'ailleurs, j'en profite pour vous exprimer tout le plaisir que j'ai à profiter de cette blogosphère, et à y participer, parce qu'elle est pour moi un monde de passion et d'ouverture. Ouverture au sens "open-source", mais aussi au sens où tout un chacun peu y lire et y écrire librement.

    Oh et merci à mon bienfaiteur (qui se reconnaitra) pour son cadeau de Nawel des shaarlieurs.

    Keep blogging & stay free!

    • Note 1 : le premier à reconnaitre cette obscure référence gagnera un petit cadeau. Non non, je ne déconne pas. Faut juste être prêt à me donner votre adresse postale, et je vous envoie une récompense. J'exclus juste mes potes IRL, parce que je sais qu'ils la connaissent tous, donc c'est pas drôle :p
  • 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

  • Friday 16 December 2016 - 16:24

    Ce billet est une réaction au billet de Zythom suivant : https://zythom.blogspot.fr/2016/12/la-honte.html

    Zythom,

    Peut-être liras-tu déjà beaucoup de réactions aujourd'hui, peut-être n'auras-tu pas l'occasion de me lire, je ne sais pas. En tout cas ce billet t'es adressé. Peut-être n'as-tu eu qu'une mauvaise passe un peu courte, aussi, et rien de ce que je dirai ne te parleras vraiment. Peut-être que, comme tu le dis, c'est juste une "petite déprime d'homme". Mais juste au cas où...

    Mais au cas où, je souhaitais te raconter ce que je connais, ce que j'ai personnellement traversé. Nos histoires sont sans doute très différentes, et pourtant... Peut-être y verras-tu un écho, quelque chose qui te rassurera un peu. Et peut-être y trouveras-tu quelque chose d'utile. Et peut-être n'en as-tu pas besoin, et est-ce là juste mon occasion à moi de faire comme toi, de transmettre ce que j'ai vécu et ce que j'ai trouvé, pour que ça puisse servir à quelqu'un un jour.

    J'ai passé dix années à ne plus savoir ce que c'était que le bonheur. J'ai passé dix ans à mentir à mon entourage quand on me demandait si j'étais heureux, même aux plus proches. Même à ma femme.

    Je voulais retrouver le chemin seul vers une vie qui me convenait, mais je ne savais pas comment faire, je ne voulais pas dépendre des autres, et je ne trouvais pas la force de faire ce qu'il fallait. Et ironiquement, j'étais plus dépendant que jamais d'eux.

    Et j'avais honte.

    J'avais honte d'aller mal, moi qui avait tout pour être heureux, moi qui était marié à une femme aimante et présente, qui me soutenait, moi qui avait une famille à l'écoute et relativement proche, qui avait des amis très proches, présents et attentifs, moi qui avait une situation stable, des études supérieures réussies sans grande difficulté dans cette période, puis un métier passionnant, bien que parfois prenant, et une situation financière relativement enviable. J'avais honte de ne pas être la réussite que tout le monde voyait. J'avais honte de renvoyer cette image fausse, aussi.

    J'avais honte de frôler la dépression, sans vouloir admettre que j'avais déjà plus qu'un pied dedans. J'avais honte de frôler le burnout aussi depuis un an à cause du travail, mais même ça, je ne voulais pas reconnaitre à quel point j'en étais proche.

    Je ne vais pas rentrer dans des détails personnel, mais j'ai touché le fond en Juillet après quelques chocs importants. Le genre de claque dans la tronche qui te donne exactement ce qu'il faut pour repartir. Je ne le revivrais pour rien au monde, mais je reconnais au moins que ça m'a apporté ce qu'il fallait, et bien plus encore, même si c'était peut-être juste avec 10 ans de retard...

    Mais voilà, la remontée de la pente, c'est une étape compliquée aussi. Les envies d'en finir, j'en ai eu quelques unes, mais pendant toutes ces années "difficile", les choses étaient diffuses, et ces pensées m'avaient un peu laissé tranquille.

    Et cet été, j'avais l'entourage nécessaire pour me soutenir, avec enfin la mise à nue de mes problèmes à certains mes proches, prêts à beaucoup donner pour que je puisse m'en sortir. Et ça marchait déjà pas mal, dans l'ensemble.

    Mais voilà, dans cette remontée, les envies ont trouvé à quelques occasion le moyen de remonter à la surface, tout comme les pleurs, les vagues de mélancolie. Peut-être est-ce parce que dans les phases de changement, on remue les choses, et même si l'essentiel qui en ressort est plutôt positif, les vagues ont toutes des creux.

    Et n'ayons pas peur des mots : beaucoup des suicides ont lieux dans une période où la personne n'était plus au fond du trou, mais bien en train de remonter la pente...

    Alors après un moment de grande mélancolie, un matin de Septembre dans la voiture (j'étais passager, hein...), j'ai fais comme toi : je suis allé regarder les symptômes de la dépression sur internet, j'ai regardé une description de ce qu'était la mélancolie. Et ça a frappé un peu trop près de moi pour que je ne me sente pas touché.

    Je m'étais déjà posé la question : devrais-je consulter ? Devrais-je aller voir un psy ? Mais non, la réponse était toujours la même : je suis sur la bonne pente, donc pas besoin. J'avance. Je me reconstruis. Pour le meilleur. Le pire aussi ? Non non, il est passé. Ca ? Ce n'est qu'un "coup de mou", il n'est que passager. Il n'y a rien à craindre...

    Ce matin-là dans la voiture, j'ai repensé à un livre que j'avais lu récemment, qui concernait la manipulation, mais qui allait bien au-delà, qui parlait de dépression, de reproduire involontairement de schémas dans l'éducation des enfants. Puis j'ai pensé à cet enfant que nous essayons d'avoir avec ma femme. Et j'ai pensé à mon état.

    Quel père allais-je être ? Comment pourrais-je me regarder dans la glace si je ne fais pas tout ce qui est en mon pouvoir pour être en bonne santé mentale lors que j'aurai un enfant à élever ? Est-ce que je ne risquais pas de faire souffrir avant l'heure un être pour lequel je souhaite tout le bonheur du monde, si je n'étais moi-même pas complètement stable ?

    Alors j'ai pris la décision d'aller voir un psy. Je ne voulais pas le faire pour moi, alors je l'ai fait pour un hypothétique enfant. Parce que j'avais honte d'admettre que j'en avais besoin. J'aurais pu aller demander conseil à mon médecin traitant, mais j'ai choisis d'en parler à chacune des personnes qui étaient déjà là pour me soutenir. M'engager auprès d'eux était ma manière de ne pas faire machine arrière ensuite. Et j'en ai parlé surtout à ceux que je connaissais qui avaient déjà consulté. J'ai récupéré ainsi le numéro de la psy d'une amie.

    Et ensuite, j'ai mis une bonne semaine avant d'oser l'appeler. On m'a dit que c'était bien, que certains mettent plusieurs semaines avant d'y arriver, voir plus encore.

    Qu'est-ce qu'allait m'apporter une inconnue, là où mes proches, tous de bons communicants, sincères, attentionnés, ne suffisaient pas ? Je ne saurais l'expliquer, mais ce que je sais, c'est que je l'ai trouvé tout de même. J'ai pu exprimer ce qui s'était petit à petit accumulé, j'ai pu retrouver confiance en moi, j'ai pu retrouver la force d'assumer mon état.

    Je ne regrette pas ma décision. Moi, aujourd'hui, je n'ai plus honte d'avoir décidé d'aller voir un psy. Je refuse toujours de considérer que je suis "malade" parce que c'est pas une manière agréable de voir les choses, ni vraiment simple à assumer. Mais j'assume de dire que j'ai besoin de faire ça. J'ai même osé le dire à mes parents. Ces parents auxquels je n'ai jamais osé parler de mes croyances ou de ma sexualité. Et voilà que je leur dit que je consulte un psy. Et qu'ils ne me jugent pas, mais me soutiennent même.

    Peut-être cela ne te parles-t-il pas du tout. Peut-être n'as-tu pas autant touché le fond que moi. Peut-être n'en as-tu pas du tout besoin. Ou encore peut-être n'as-tu pas les moyens de l'envisager, que ce soit pour des raisons d'argent, pour des raisons de temps, ou des raisons plus personnelles.

    Mais voilà, à toute personne qui a vu le fond d'un peu trop près, et qui s'estime être "en train de remonter la pente" : ne perdez pas de vu que consulter quand on va mal, ce n'est pas une raison d'avoir honte, que c'est normal de vouloir faire "tout ce qu'il faut" pour aller mieux, que ce soit pour vous ou pour votre entourage, et qu'il n'y a pas nécessairement que quand on touche le fond que ça mérite d'être envisagé.

    Zythom, merci pour ton partage, qui m'aura donné à moi aussi le coup de pouce nécessaire pour m'exprimer un peu à mon tour. J'aime ta conclusion, simple. "Je ne suis ni un héros, ni un zéro. Je fais de mon mieux. Et parfois, ce n'est pas terrible.". J'ajouterais juste qu'on n'est pas tenu à faire plus que cela.

    Pour moi, 2016 aura été une année douloureuse, mais elle aura aussi été riche, forte et belle. Je te souhaites de le voir ainsi aussi. :)

    Yosko