Jeremy Selier

Ajouter Google Chrome Frame sur votre application AppEngine

Google Chrome Frame

Vous avez probablement entendu parler de Google Chrome Frame, une extension pour Internet Explorer permettant d'exploiter le moteur de rendu WebKit et le moteur d'exécution JavaScript V8 de Google Chrome à l'intérieur d'Internet Explorer. Je ne vais pas discuter de son utilité, chacun saura juger s'il est nécessaire ou pas de gérer cette extension sur son application ou site web.

Si vous ne connaissez pas Google Chrome Frame, vous pouvez aller jeter un œil sur la page du projet GCF sur Google Code et regarder la vidéo disponible.

Détection côté serveur

Pour détecter si le visiteur est sous Internet Explorer, il suffit de regarder au niveau du User-Agent qui est envoyé dans le header HTTP de chaque requête du navigateur. Sous AppEngine, je vous conseille de placer de check avec un décorateur que vous placerez sur chaque GET de chaque URL que vous souhaitez soumettre à Chrome Frame. Voici le code :

def supported_browser():
    def wrapper(handler_method):
        def check_browser(self, *args, **kwargs):
            if 'User-Agent' in self.request.headers:
                ua = self.request.headers['User-Agent']
                if 'MSIE' in ua:
                    if 'chromeframe' not in ua:
                        values = {}
                        path = os.path.join(os.path.dirname(__file__),  \
                            "templates/browser_not_supported.html")
                        return self.response.out.write(template.render(path, values))
            return handler_method(self, *args, **kwargs)
        return check_browser
    return wrapper

On effectue donc un premier check sur le User-Agent pour déterminer si le visiteur est sous Internet Explorer en vérifiant la présence de "MSIE" qui est présent dans le User-Agent d'Internet Explorer de toutes les versions existantes à ce jour. Nous pouvons ensuite vérifier la présence de "chromeframe" dans le User-Agent, si l'extension Chrome Frame est installée, elle rajoute automatiquement cette String dans le User-Agent du navigateur. Si nous ne la trouvons pas, nous renvoyons une page tampon qui indique à l'utilisateur que son navigateur n'est pas optimisé pour le site.

Page indiquant que le navigateur n'est pas supporté par le site

Détection côté client

Sur la page Google Code du projet, des exemples sont disponible pour vous aider à détecter la présence de Chrome Frame en JavaScript. Je vous remets ici l'exemple de base à mettre en place :

<body>
<script type="text/javascript" 
src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js">
</script>
 
<div id="placeholder"></div>

<script>
 CFInstall.check({
    node: "placeholder",
    destination: "http://www.waikiki.com"
  });
</script>
</body>

Gérer l'installation

Personnellement je n'ai pas encore gérer cet aspect sur mon site, je me suis contenté d'envoyer vers la page du projet Chrome Frame, mon site étant destiné à un public technique, je n'ai pas ressenti le besoin de mettre en place un installeur à partir de ma page. Néanmoins, c'est possible, voir le lien ci-dessus sur la détection.

Activer le plug-in

La partie la plus simple et la plus importante, après tout vous n'êtes pas obligé d'effectuer un check sur le navigateur du visiteur si vous souhaitez seulement que le visiteur profite de cette extension s'il l'a installé. Il suffit donc de placer dans le <head> des pages que vous souhaitez exécuter si possible avec Chrome Frame cette META :

<meta http-equiv="X-UA-Compatible" content="chrome=1">

Et c'est tout! Cette Meta ne sera interprété que si Chrome Frame est installé sur Internet Explorer, autrement elle sera ignorée. Et si Chrome Frame détecte cette balise, il bascule l'affichage d'Internet Explorer à Chrome Frame. A vous l'HTML5 (<video> et <canvas> pour le moment) et le JavaScript super rapide!

Ne pas vérifier le User-Agent

Il est, en général, conseillé (si votre application fonctionne sous Internet Explorer - même si les performances sont dégradées) d'offrir à l'utilisateur la possibilité de continuer malgré tout. On ajoute alors ce texte dans la page tampon :

<p class="tryanyway">Si vous voulez continuer à vos risques et périls, 
<a href="?nouacheck">allez-y</a>.</p>

Il faut ensuite gérer au niveau de son application le fait de ne plus checker le User-Agent si le visiteur à cliqué sur ce lien, on fait ça avec un cookie, tout simplement. Voici les trois lignes à rajouter :

#Check for ChromeFrame under IE if user has not clicked on 'continue anyway'
nouacheckcookie = get_cookie(self, 'nouacheck')
if nouacheckcookie != 'true':
    if self.request.query_string != 'nouacheck':

Et voici donc le code final du decorator :

def supported_browser():
    def wrapper(handler_method):
        def check_browser(self, *args, **kwargs):
            #Check for ChromeFrame under IE if user has not clicked on 'continue anyway'
            nouacheckcookie = get_cookie(self, 'nouacheck')
            if nouacheckcookie != 'true':
                if self.request.query_string != 'nouacheck':
                    if 'User-Agent' in self.request.headers:
                        ua = self.request.headers['User-Agent']
                        if 'MSIE' in ua:
                            if 'chromeframe' not in ua:
                                browser_language = find_language(self, views.AVAILABLE_LANGUAGES)
                                values = {}
                                path = os.path.join(os.path.dirname(__file__), \
                                    "templates/"+browser_language+"_browser_not_supported.html")
                                return self.response.out.write(template.render(path, values))
            return handler_method(self, *args, **kwargs)
        return check_browser
    return wrapper

Le code pour détecter le nouacheck que l'on place dans le initialize (c'est au choix à vrai dire) de notre propre class RequestHandler dont hériteront toutes nos vues :

class BaseHandler(webapp.RequestHandler):
    def initialize(self, request, response):
        webapp.RequestHandler.initialize(self, request, response)
        #Add cookie to not check browser if nouacheck parameter is in url
        if request.query_string == 'nouacheck':
            utils.create_cookie(self, 'nouacheck', 'true', 1)

Un exemple de decorator sur une vue :

class MainPageHandler(BaseHandler):
    @supported_browser()
    def get(self):
        […]

Et les fonctions utils pour les cookies :

def create_cookie(handler, cookie_name, cookie_value, days):
    today = datetime.datetime.today() + datetime.timedelta(days)
    expires_rfc822 = str(today.strftime("%a, %d %b %Y %H:%M:%S +0000"))
    cookie = cookie_name+'='+cookie_value+'; path=/; expires='+expires_rfc822+''
    handler.response.headers.add_header('Set-Cookie', str(cookie)) 
    return
 
 
def delete_cookie(handler, cookie_name):
    handler.response.headers.add_header('Set-Cookie', cookie_name+'=; path=/; expires=;')
    return
 
 
def get_cookie(handler, cookie_name):
    cookies = handler.request.cookies
    if cookie_name in cookies:
        return cookies[cookie_name]
    else:
        return ""
All posts >