jquery – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 La protection CSRF de Django et les requêtes Ajax http://sametmax.com/la-protection-csrf-de-django-et-les-requetes-ajax/ http://sametmax.com/la-protection-csrf-de-django-et-les-requetes-ajax/#comments Tue, 10 Jun 2014 04:18:36 +0000 http://sametmax.com/?p=10438 attaques CSRF est dans le top 10 des erreurs les plus chiantes en Django, main dans la main avec les fichiers statiques qui ne marchent pas, les URL qui ne matchent pas et les CBV qui nheuuuu, juste pas.]]> La protection contre les attaques CSRF est dans le top 10 des erreurs les plus chiantes en Django, main dans la main avec les fichiers statiques qui ne marchent pas, les URL qui ne matchent pas et les CBV qui nheuuuu, juste pas.

Une fois qu’on a compris le principe, ça va pour la prog normal, mais un jour on a besoin de faire un POST en Ajax, et on se retrouve avec une erreur invisible. Après avoir dégainé Firebug, on comprend qu’on a une 403 forbidden, et votre cerveau finit (la durée galérienne est plus ou moins longue selon les profiles, les heures de sommeil et les phases de la lune) par réaliser qu’on n’a pas envoyé le token CSRF. Merde.

C’est là que généralement les gens sortent du @csrf_exempt, ou carrément, en finissent avec cette solution radicale :

MIDDLEWARE_CLASSES = (
    'django.middleware.gzip.GZipMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

Mais c’est quand même dommage d’en arriver là alors qu’on peut le faire proprement.

D’abord, le token est sauvegardé dans un cookie. Il faut donc le récupérer.

// ue petite fonction pour récupérer la valeur d'un cookie,
// puisque bien entendu, comme toutes les APIS javascripts,
// les choses qu'on fait le plus souvent ne sont pas incluses
// en natif. Oui je suis aigri.
function getCookie(name) {
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                return decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
}

Sinon, pour les fainéants, il y a y a un plugin jquery qui permet de faire $.cookie('nom').

Ensuite, on attache cette valeur en header avec toutes les requêtes POST. Comme ça, plus besoin de l'inclure manuellement, on peut faire ses requêtes sans y penser.

Avec jQuery :

$.ajaxSetup({
    // fonction appelée avant d'envoyer une requête AJAX
    beforeSend: function(xhr, settings) {
         // on ajoute le header que si la requête est pour le site en cours
         // (URL relative) et est de type POST
         if (!/^https?:.*/.test(settings.url)  && settings.type == "POST") {
             // attachement du token dans le header
             xhr.setRequestHeader("X-CSRFToken",  getCookie('csrftoken'));
         }
     }
});

Avec AngularJs :

// interception de la configuration du provider HTTP
// qui possède un mécanisme déjà tout prêt pour ça
votre_app.config(function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
});

Attention, si l'app n'est pas servie par Django (template statique avec uniquement des appels Ajax), il faut faire au moins un GET avant de faire son premier POST afin d'obtenir le cookie.

]]>
http://sametmax.com/la-protection-csrf-de-django-et-les-requetes-ajax/feed/ 19 10438
Deferred, Future et Promise : le pourquoi, le comment, et quand est-ce qu’on mange http://sametmax.com/deferred-future-et-promise-le-pourquoi-le-comment-et-quand-est-ce-quon-mange/ http://sametmax.com/deferred-future-et-promise-le-pourquoi-le-comment-et-quand-est-ce-quon-mange/#comments Wed, 04 Jun 2014 13:19:22 +0000 http://sametmax.com/?p=10418 Si vous avez plongé dans le monde de la programmation asynchrone non bloquante, vous avez du vous heurter aux callbacks. Si ce n’est pas le cas, aller lire l’article, et faites vos armes sur jQuery, je vais m’en servir en exemple.

Signalement de rigueur que l’article est long :

Un callback, ça va.

Deux callbacks, pour un seul appel, ça commence à être chiant, mais c’est compréhensible.

Quand les callbacks appellent eux aussi des callbacks, ça donne des codes imbitables :

$(function(){
  $.post('/auth/token', function(token){
    saveToken(token);
    $.get('/sessions/last', function(session){
      if (session.device != currentDevice){
        $.get('/session/ ' + session.id + '/context', function(context){
          loadContext(function(){
            startApp(function(){
              initUi()
            })
          })}
        )}
      else {
        startApp(function(){
          initUi()
        })
      }}
    )
  })
});

Il y a pire que de lire ce code : le modifier ! Retirez un bloc, pour voir. Oh, et histoire de vous faire partager l’expérience complète, j’ai volontairement déplacé l’indentation d’une parenthèse et de deux brackets.

Or les codes asynchrones ont besoin de callback afin d’enchainer certaines opérations dans le bon ordre, sinon on ne peut pas récupérer le résultat d’une fonction et l’utiliser dans une autre, puisqu’on ne sait pas quand l’opération se termine.

Dans notre exemple, $.post et $.get font des requêtes POST et GET, et comme on ne sait pas quand le serveur va répondre, il faut mettre un callback pour gérer la réponse quand elle arrive. C’est plus performant que de bloquer jusqu’à ce que la première requête soit terminée car pendant ce temps, notre programme peut faire autre chose. Mais c’est aussi super relou à écrire et comprendre.

Entrent en jeu les promesses (promises). Ou les deferred. Ou les futures.

Typiquement, on retrouve des deferreds dans Twisted, des promises pour l’AJAX avec jQuery, des futures pour asyncio… Mais il y en a un peu partout de nos jours, et une lib peut utiliser plusieurs de ces concepts.

En fait c’est la même chose, un nom différent donné au même concept, par des gens qui l’ont réinventé dans leur coin. Les puristes vous diront qu’il y a des différences dans l’implémentation, ou alors que la promesse est l’interface tandis que le deferred est l’objet retourné, bla, bla, bla.

Fuck it, on va considérer que c’est tout pareil.

Les promesses sont une des manières de rendre un code asynchrone plus facile à gérer. On dit : ce groupe de fonctions doit s’exécuter dans un ordre car elles sont dépendantes les unes des autres.

Il y a d’autres moyens de gérer le problème de l’asynchrone: des événements, des queues, etc. L’avantage des promesses c’est que c’est assez simple, et ça marche là où on utilisait des callbacks avant, donc on a pu les rajouter aux libs qui étaient blindées de callbacks.

Le principe

La promesse est un moyen de dire que certaines fonctions, bien que non bloquantes et asynchrones, sont liées entre elles, et doivent s’exécuter les unes à la suite des autres. Cela permet de donner un ordre d’exécution à un groupe de fonctions, et surtout, que chaque fonction puisse accéder au résultat de la fonction précédente. Tout ceci sans bloquer le reste du système asynchrone.

En résumé, cela donne un gout de programmation synchrone, à quelque chose qui ne l’est pas.

Cela se passe ainsi :

  • La fonction asynchrone retourne un objet immédiatement : la promesse.
  • On ne passe pas de callback à la fonction. On rajoute un callback à la promesse.
  • Le callback prend en paramètre le résultat de la fonction asynchrone.
  • Le callback retourne le résultat de son traitement.
  • On peut rajouter autant de callbacks qu’on veut à la promesse, chacun devant accepter le résultat du callback précédent et retourner son propre résultat.
  • Si un des callbacks retourne une promesse, elle est fusionnée avec la promesse initiale, et c’est son résultat que le prochain callback va récupérer

Voilà un exemple :

// $.get est asynchrone. On a pas le résultat tout de suite, mais en attendant
// on a une promesse tout de suite.
var $promesse = $.get('/truc/machin');

// premier callback. Il sera appelé quand $.get aura récupéré son
// résultat
$promesse.then(function(resultat){
  // faire un truc avec le résultat
  // puis on retourne le nouveau résultat
  return nouveau_resultat;
});

// deuxième callback. Il sera appelé quand le premier callback
// aura retourné son résultat.
$promesse.then(function(nouveau_resultat){
  // faire un truc
});

Notez bien que c’est TRES différent de ça (en Python):

resultat = request.get('/truc/marchin')

def function(resultat):
  # faire un truc
  return nouveau_resultat
nouveau_resultat = function(resultat)

def autre_function(nouveau_resultat):
  # faire un truc
autre_function(nouveau_resultat)

En Python, le code est bloquant par défaut. Ça va marcher, mais pendant que le code attend la réponse du serveur, votre ordinateur est en pause et ne travaille pas.

Un plus beau code

On se retrouve avec un code asynchrone, mais qui s’exécute dans l’ordre de lecture. Et comme on peut chainer les then() et donc ne pas réécrire $promesse à chaque fois, on obtient quelque chose de beaucoup plus lisible :

$.get('/truc/machin')
.then(function(resultat){
  // faire un truc
  return nouveau_resultat;
})
.then(function(nouveau_resultat){
  // faire un truc
});

Si on reprend notre premier exemple, ça donne ça :

$(function(){

// create new token
$.post('/auth/token')

// then save token and get last session
.then(function(token){
  saveToken(token);
  return $.get('/sessions/last');
})

// then init session
.then(function(session){
  if (session.device != currentDevice){
    
    $.get('/session/ ' + session.id + '/context')
    .then(function(context){
      loadContext(function(){
        startApp(function(){
          initUi()
        })
      })
    })

  }
  else {
    startApp(function(){
      initUi()
    })
  }}
})

});

Tout ça s’exécute de manière non bloquante (d’autres fonctions ailleurs dans le programme peuvent s’exécuter pendant qu’on attend la réponse du serveur), mais dans l’ordre de lecture, donc on comprend bien ce qui se passe. Si on veut retirer un bloc, c’est beaucoup plus facile.

Comment ça marche à l’intérieur ?

Histoire d’avoir une idée de comment une promise marche, on va faire une implémentation, simpliste et naïve, mais compréhensible, d’une promesse en Python. Pour rendre l’API un peu sympa,je vais utiliser les décorateurs.

class Promise:

    # La promesse contient une liste de callbacks, donc une liste de fonctions.
    # Pas le résultat des fonctions, mais bien les fonctions elles mêmes,
    # puisque les fonctions sont manipulables en Python.
    def __init__(self):
        self.callbacks = []

    # Point d'entrée pour ajouter un callback à la promesse
    def then(self, callback):
        self.callbacks.append(callback)

    # Cette méthode est celle qui sera appelée par le code asynchrone
    # quand il reçoit son résultat.
    def resolve(self, resultat):

        # Ici, on obtient le résultat du code asycnhrone, donc on boucle
        # sur les callbacks pour les appeler
        while self.callbacks:
            # On retire le premier callback de la liste, et on l'appelle
            # avec le résultat
            resultat = self.callbacks.pop(0)(resultat)

            # Si le resultat est une promesse, on dit à cette nouvelle promesse
            # de nous rappeler quand elle a reçu ses résultats à elle avant
            # d'aller le reste de nos callbacks à nous : on fusionne les deux
            # promesses :
            # Promesse 1
            #  - callback1
            #  - callback2
            #  - Promesse 2
            #      * callback 1
            #      * callback 2
            #  - callback 3
            if isinstance(resultat, Promise):
                resultat.then(self.resolve)
                break

Maintenant, créons un code asynchrone:

from threading import Timer

def func1(v1):
    # On dit complètement artificiellement d'afficher le résultat
    # de la fonction dans 3 secondes, sans bloquer histoire d'avoir
    # un peu de nonbloquitude dans notre code et justifier l'asynchrone.
    def callback1():
        print(v1)
    t = Timer(3, callback1)
    t.start()

def func2(v2):
    # Le même, mais pour 2 secondes
    def callback2():
        print(v2)
    t = Timer(2, callback2)
    t.start()

# Deux fonctions normales
def func3(v3):
    print(v3)

def func4(v4):
    print(v4)

# Et si on les enchaines...
print('Je commence')
func1(1)
print('Juste après')
func2(2)
func3(3)
func4(4)

# ... le résultat est bien désordonné :

## Je commence
## Juste après
## 3
## 4
## 2
## 1

Parfois c’est ce que l’on veut, que les choses s’exécutent dans le désordre, sans bloquer.

Mais quand on a des fonctions qui dépendent les unes des autres, au milieu d’un code asynchrone, on veut qu’elles se transmettent le résultat les unes aux autres au bon moment. Pour cela, utilisons notre promesse :

from threading import Timer


# La mise en place de promesses suppose que le code 
# écrit en fasse explicitement usage. Notre code est
# définitivement lié à cette manière de faire.

def func1(v1):
    # Notre fonction doit créer la promesse et la retourner
    p = Promise()
    def callback1():
        print(v1)
        # Dans le callback, elle doit dire quand la promesse est tenue
        p.resolve(v1)
    t = Timer(3, callback1)
    t.start()
    return p

# On lance la première fonction.
print('Je commence')
promise = func1(1)
print('Juste après')

# On ajoute des callbacks à notre promesse.

@promise.then
def func2(v2):
    p = Promise()
    def callback2():
        # Pour justifier l’enchainement des fonctions, on fait en sorte que
        # chaque fonction attend le résultat de la précédente, et
        # l'incrémente de 1.
        print(v2 + 1)
        p.resolve(v2 + 1)
    t = Timer(2, callback2)
    t.start()
    # Ce callback retourne lui-même une promesse, qui sera fusionnée
    return p

# Ces callbacks ne retournent pas de promesses, et seront chainés
# normalement
@promise.then
def func3(v3):
    print(v3 + 1)
    return v3 + 1

@promise.then
def func4(v4):
    print(v4 + 1)

# Nos fonctions s'exécutent dans le bon ordre, mais bien de manière
# asynchrone par rapport au reste du programme.

## Je commence
## Juste après
## 1
## 2
## 3
## 4

Notez bien :

  • Le résultat “1” n’apparait que trois secondes après “Juste après”. Les fonctions sont donc bien non bloquantes.
  • Le resultat “2” apparait deux secondes après “1”: c’est aussi asynchrone, MAIS, n’est lancé que quand la première fonction a terminé son travail.
  • La deuxième fonction retourne une promesse, qui est fusionnée: tous ses callbacks vont s’exécuter en file avant que func3 soit lancé.

Évidement, n’utilisez pas cette implémentation de promise à la maison, c’est pédagogique. Ça ne gère pas les erreurs, ni le cas où le callback est enregistré après l’arrivée du résultat, et tout un tas d’autres cas tordus.

Syntaxe alternative

En Python, beaucoup de frameworks ont une approche plus agréable pour gérer les promesses à grand coup de yield. Twisted fait ça avec son @inlineCallback, asyncio avec @coroutine. C’est juste du sucre syntaxique pour vous rendre la vie plus facile.

Il s’agit de transformer une fonction en générateur, et à chaque fois qu’on appelle yield sur une promesse, elle est fusionnée avec la précédente. Ça donne presque l’impression d’écrire un code bloquant normal :

# un appel de fonction asyncrone typique de twisted
@inlineCallback
def une_fonction(data):
  data = yield func1(data)
  data = yield func2(data)
  data = yield func3(data)

une_fonction(truc)

Les fonctions 1, 2 et 3 vont ainsi être appelées de manière asynchrone par rapport au reste du programme, mais bien s’enchainer les unes à la suite des autres.

Ouai, tout ce bordel parce que l’asynchrone, c’est dur, donc on essaye de le faire ressembler à du code synchrone, qui lui est facile.

]]>
http://sametmax.com/deferred-future-et-promise-le-pourquoi-le-comment-et-quand-est-ce-quon-mange/feed/ 19 10418
Faire cohabiter plusieurs versions de jQuery http://sametmax.com/faire-cohabiter-plusieurs-versions-de-jquery/ http://sametmax.com/faire-cohabiter-plusieurs-versions-de-jquery/#comments Sun, 12 May 2013 13:08:25 +0000 http://sametmax.com/?p=3946 noConflict() (c'est beau l'open source quand même), elle permet également d'utiliser en même temps une version plus récente ou plus ancienne de son code, facilitant les migrations.]]> jQuery est très bien foutu, non content de permettre d’utiliser des libs concurrentes utilisant la même API avec noConflict() (c’est beau l’open source quand même), elle permet également d’utiliser en même temps une version plus récente ou plus ancienne de son code, facilitant les migrations.

Pour utiliser noConflict à bon escient, il faut simplement faire très attention à l’ordre d’inclusion de ses scripts…

D’abord, loader les deux versions de jQuery :


Ensuite utilise noConflict() pour sauvegarder une référence à cette version :

Et on charge la deuxième fournée :


On sauvegarde aussi cette version dans une variable :

Et du coup on peut utiliser les deux en parallèle. Au lieu d’appeler $, les appelle par leur p’tit nom :

autreVersionDejQuery('a').click(truc);

Et comme d’hab, vous pouvez utiliser la technique de la fonction anonyme immédiatement appelée pour créer un alias local et réutiliser $.

(function($) {
    $('img').hover(bidule);
})(version1dejQuery);

D’ailleurs, je pense que ça ne marche que si les plugins inclus utilisent cette technique, ce qui est normalement une convention dans le monde de jQuery.

]]>
http://sametmax.com/faire-cohabiter-plusieurs-versions-de-jquery/feed/ 3 3946
Utilisez des variables globales avec JSLint http://sametmax.com/utilisez-des-variables-globales-avec-jslint/ http://sametmax.com/utilisez-des-variables-globales-avec-jslint/#comments Wed, 17 Apr 2013 16:13:05 +0000 http://sametmax.com/?p=5508 super plugin Sublime Text).]]> Petite astuce si vous utilisez JSlint (par exemple via le super plugin Sublime Text).

Il va vous mettre en avant toutes les variables globales ou non déclarées précédement. C’est génial la plupart du temps, mais c’est un peu chiant pour des variables qui sont volontairement globales et mises à dispo par d’autres scripts comme les frameworks et libs.

Par exemple, il va vous déclarer que jQuery est une variable globale ou non déclarée. Pour éviter ça, mettez ce commentaire tout en haut du fichier :

/*global jQuery:true, $:true */

JSLint va le prendre en compte et ignorer ces variables.

On peut lister autant de variables qu’on le souhaite.

]]>
http://sametmax.com/utilisez-des-variables-globales-avec-jslint/feed/ 1 5508
Mettez vos sites Web et apps en plein écran avec l’API HTML 5 fullscreen http://sametmax.com/utiliser-lapi-html5-fullscreen-pour-mettre-votre-site-app-en-plein-ecran/ http://sametmax.com/utiliser-lapi-html5-fullscreen-pour-mettre-votre-site-app-en-plein-ecran/#comments Sun, 30 Dec 2012 04:40:49 +0000 http://sametmax.com/?p=3916 requestFullscreen(), qui va vous permettre ... d'appuyer sur F11 à la place de l'utilisateur.]]> Il est loin le temps où le JS était un sous langage utilisé uniquement par des deumeurés en mal de <blink>. Maintenant c’est un sous langage utilisé par des gens très sérieux. PHP l’a bien prouvé, on peut être parfaitement utile en ayant une syntaxe daubée, et Javascript se pare donc de tout un tas de trucs surpuissants en ces temps de HTML5, CSS3 et Rambo8.

Fini donc le temps où votre site restait prisonnier de son canvas en 800×600, maintenant votre dernière application de calcul de budget de croquettes pour hérisson peut enfin s’exprimer dans toute la hauteur et la largeur d’un écran Retanal grâce à requestFullscreen(), qui va vous permettre … d’appuyer sur F11 à la place de l’utilisateur.

Mais il aura à faire un clic de confirmation quand même. Car il aura un gros prompt bien alarmant avant. Le progrès je vous dis !

Le code, en 2 / 2

Parce que bien entendu c’est incompatible avec les tondeuses à gazons et que selon les marques de votre pétrolettes, le prefix ne sera pas le même, on va commencer par vérifier le support du bouzin.

function supportFullScreen(){
    var doc = document.documentElement;
    return ('requestFullscreen' in doc) || ('mozRequestFullScreen' in doc && document.mozFullScreenEnabled) || ('webkitRequestFullScreen' in doc);
}

Puis on va demander à l’utilisateur si on a le droit, s’il-te-plait-pitié-déconne-pas-putain, de mettre votre site en plein écran. Car figurez vous qu’il y a un sérieux risque de phishing, comme en voici la démonstration rigolote.

function requestFullScreen(elem){
    if (elem.requestFullscreen) {
        elem.requestFullscreen();
    } else if (elem.mozRequestFullScreen) {
        elem.mozRequestFullScreen();
    } else if (elem.webkitRequestFullScreen) {
        elem.webkitRequestFullScreen();
    }
}

Ca s’utilise ainsi:

requestFullScreen(document.body)

A ce moment là l’écran de le navigateur passe en plein écran avec un gros panel d’avertissement genre “le certificat du site est invalide”, mais en gris. Et si l’utilisateur lit le message avant de se ruer sur le bouton “annuler” par réflexe, il s’apercevra qu’on lui explique ce qui se passe pour pas qu’il finisse de mourir de sa crise cardiaque.

Vous pouvez utiliser n’importe quel autre élément que body, et donc mettre en plein écran de tout petit widgets. Attention cependant, il va prendre la taille de tout l’écran, déclenchant tout un tas d’events de changement de taille, de display, changeant les overflows et gagnant un style par défaut qui sera différent selon le navigateur. Le W3C a un deal avec les browser vendors pour s’assurer que les devs Web ne soient jamais prêt d’être au chômage.

Passons.

Le problème quand on demande, c’est qu’on peut se voir répondre “non”. Donc en prime, il vaut mieux se concocter un fallback si jamais mémé s’affole devant la menace de voir ses onglets avalés par le viewport. Ici, je vous pond ça en jQuery, parceque la gestion des events à la main, c’est juste relou.

function onFullScreenEvent(callback){
    $(document).live("fullscreenchange mozfullscreenchange webkitfullscreenchange", function(){
        callback(document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen);
    });
}

Bon, normalement on utilise ‘on()’ maintenant chez les gens branchés, mais j’arrive à le faire marche une fois sur deux. Donc ça s’utilise comme ça:

onFullScreenEvent(function(isFullscreen){
    faire un truc selon que l'on est en fullscreen ou pas, comme pousser mémé dans les orties
});

Clusions ensemble entre cons

Et voilà, vous avez une application fullscreenable. Il ne vous reste plus rien à faire. A part rajouter un bouton pour le permettre à l’utilisateur de mettre en fullscreen. Puis un autre pour sortir du fullscreen. Puis de gérer la transition des états de votre app. Les différences de rendu selon la taille des éléments et du style par défaut appliqué par le navigateur. Et bien entendu le plus dur: faire comprendre tout ce bordel à votre utilisateur final.

Plus rien à faire je vous dis: on vous a mâché le travail.

Si vous avez pas le temps, vous pouvez aussi mettre alert('appuyez sur F11 pour passer en plein écran'). Mais bon, j’écrirais des articles sur quoi moi après ?

]]>
http://sametmax.com/utiliser-lapi-html5-fullscreen-pour-mettre-votre-site-app-en-plein-ecran/feed/ 3 3916
Echaper du HTML en Python ou avec jQuery http://sametmax.com/echaper-le-html/ Wed, 28 Nov 2012 15:02:56 +0000 http://sametmax.com/?p=3395 La question bateau du jour: mais comment transforme-t-on des tags HTML en entités HTML pour sécuriser les inputs utilisateurs qui seront affichées sur le site ?

En Python

On peut utiliser le module sax, qui a la base sert à échaper les caractères pour du XML. On va juste étendre sa table de caractères pour rajouter le simple et le double quote.

from xml.sax.saxutils import escape, unescape

a_echapper = {'"': """, "'": "'"}
a_reconstituer = dict((value, key) for key, value in a_echapper.iteritems())

def echape_html(text, a_echapper=a_echapper):
    return escape(text, a_echapper)

def reconstitue_html(text, a_reconstituer=a_reconstituer):
    return unescape(text, a_reconstituer)

Avec jQuery

En pur JS, ce sera galère. Mais avec jQuery, c’est :

$('
').text(text_a_echaper).html();

Je ne sais pas comment on peut faire facilement l’opération inverse par contre.

]]>
3395
Le meilleur de l’actu IT fr, le temps d’un café: le multiboards http://sametmax.com/le-meilleur-de-lactu-it-le-temps-dun-cafe-le-multiboards/ http://sametmax.com/le-meilleur-de-lactu-it-le-temps-dun-cafe-le-multiboards/#comments Tue, 14 Aug 2012 19:49:10 +0000 http://sametmax.com/?p=1697 Dans son tuto sur bottle, Max vous disait qu’il avait concocté un exemple de ce qu’on peut faire rapidement avec cette lib.

Ainsi est né multiboards.net.

C’est très simple: il déteste les flux RSS, et veut juste rapidement avoir toutes les infos intéressantes sur l’actu informatique en buvant son kawa le matin, sans se fouler.

Le multiboards répond simplissimement à ce besoin en offrant sur une page qui s’auto refresh :

  • les actus des meilleurs blogs (sélectionnés par le dictateur Max) IT;
  • les actus des meilleurs sites généralistes IT;
  • les offres d’emplois IT en France, principalement Python;
  • des actus plus générales de Google news;
  • tout ça enrobé de conneries pour le lulz venant de imgur, bashfr et vdm;
  • et une radio intégrée dans le menu en haut qui vous diffuse de la zik si vous êtes d’humeur à cliquer dessus.
Capture d'écran du multiboards

Des articles, des news, de bêtises, en un coup d'oeil

C’est du bottle, donc du Python, et massivement du jQuery, avec un petit peut de Redis mais alors vraiment pour la couleur. Car en fait, quasiment tout se passe côté client et ne tape quasiment pas notre serveur. Très KISS.

Il n’y aura pas de version qu’on peut customiser par user, qui demande une registration ou quoique ce soit. Le multiboard, c’est ça, et juste ça.

Maintenant chers amis, il va falloir tous spammer de commentaires ce post pour motiver l’auteur afin qu’il mette le code source sous licence libre. Parceque c’est une feignasse, le Max, je vous le rappelle, et que ça voudrait dire qu’il devrait écrire une doc et nettoyer le random.randint() qu’il a mis pour le compteur de visiteurs.

Ah oui, on a rajouté le lien dans le menu.

 

]]>
http://sametmax.com/le-meilleur-de-lactu-it-le-temps-dun-cafe-le-multiboards/feed/ 25 1697
jQuery Visual Password: créer hash un visuel d’un password en cours de frappe http://sametmax.com/jquery-visual-password-creer-hash-un-visuel-dun-password-en-cours-de-frappe/ http://sametmax.com/jquery-visual-password-creer-hash-un-visuel-dun-password-en-cours-de-frappe/#comments Sat, 05 May 2012 01:40:57 +0000 http://sametmax.com/?p=547 Comment s’assurer que l’on a pas fait une faute de frappe quand la page de login se bloque après trois essais infructeux ? Comme être certains que le password choisi à la création d’un compte est bien ce lui que l’on veut ?

jQuery Visual Password est un plugin jQuery qui répond à cette question sans avoir à mettre le mot de passe en clair : il créé une image unique depuis le mot de passe, puis l’affiche. L’image se met à jour au fil de la frappe.

Impossible de se tromper, l’image change radicalement si on change le moindre caractère. Et pour cause, ça utilise VizHash.js :-)

Essayez :

On me sussure à l’oreille que ça peut être pratique pour les mails aussi, car c’est plus facile de voir si une image est changée que de chercher une faute de frappe.

On pourrait imaginer la même chose pour un champ d’adresse bitcoin, ou une signature PGP, un clé SSH, un hash de commit Git, etc.

]]>
http://sametmax.com/jquery-visual-password-creer-hash-un-visuel-dun-password-en-cours-de-frappe/feed/ 3 547