IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez .NET Discussion :

[HTML5] TP pour développeur migrant sur HTML5


Sujet :

Contribuez .NET

  1. #1
    Invité
    Invité(e)
    Par défaut [HTML5] TP pour développeur migrant sur HTML5
    Introduction

    Suite a mon article expliquant que HTML5 allait devenir le Golden Language pour faire du B2C, il me fallait réagir et vous proposer un post sur le sujet!

    Ce billet est a destination des développeurs .NET/XAML souhaitant passer sur tout ce qui gravite autour de HTML5.

    Le but sera de concevoir une sorte de “home” a la Windows 8, avec des tuiles pour afficher les derniers billets d’un flux RSS, avec version pour mobile/tablette ainsi qu’une version offline et Windows 8.

    Mais pour bien commencer, je vous recommande de regarder cette vidéo pour avoir une vue d’ensemble de ces langages:

    Rendez vous des Experts - Découverte de HTML5

    Fonctionnalité et design

    Le but de cette application va être de créer un site d’agrégation:


    • Un design métro, avec un fond avec photo aléatoire
    • Une compatibilité IE10/Mozilla/Chrome/Tablette iPad et Android
    • La possibilité d’ajouter la page en favoris, favicon and co
    • Deux box, l’une présentant les flux RSS de mes deux blogs
    • L’autre étant des liens vers projets et autres
    • Le tout dans des tuiles animées en CSS3
    • Version offline et stockage des articles hors ligne
    • Utilisation d’un maximum de features HTML5
    • Version spéciale compilée Windows 8 (sera l’objet d’un autre poste)
    • Version optimisée pour téléphone avec Media Queries et KendoUI
    • Utilisation d’un max de Framework du moment comme LESS/Knockout.js and co
    • Consommation de toutes les données sur un service Node.js


    Développement

    Création de la structure de la page en HTML5

    La première chose que je vais réaliser, est la structure de la page. HTML5 apporte son lot de nouvelles balises comme <header>, <nav> et bien d’autres mais cela ce comporte comme des divs.

    Ma page HTML5 va ressembler à cela:



    La structure reste simple: un header, un footer et au milieu un contenu représenté par une bullet liste.

    Le header prendra cette forme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    <header id="headertop">    
       <div id="backgroundtitle">        
          <img src="Assets/images/logo.png" />    
       </div>  
     
     
       <div id="title">        
          <img src="Assets/images/logo2.png" /><label>  Home</label></div> 
     
       <div id="loginbox">        
          <div id="username"></div>    
       </div>       
    </header>
    Le footer, tout aussi simple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    <footer id="bottomfooter">    
       <div id="plusmenu">        
          <img src="Assets/images/heart.png" /></div>
    </footer>
    Et au milieu, une bullet liste, avec pour chaque petites tuiles une <div>:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    <div id="box3">                        
       <nav class="navitems , secondnavitems">                            
       <header class="headerclass">Projects</header>                            
       <ul>                                
          <li>                                    
             <div class="box">                                        
                <div class="image"><img src="" alt="" /></div>                                                          <div class="nomapp">Blog</div>                            
    </div>                                
         </li>
    //etc...
    Organisation de la page avec CSS3

    Avant de commencer, je vous conseil vivement de travailler avec LESS. LESS est un framework JS ou un compilateur CSS permettant d’améliorer le langage. Il est désormais possible de déclarer des variables, faire des conditions, de l’héritage… Pour l’exploiter plusieurs solutions: soit en JavaScript, qui se chargera au runtime de “compiler” le CSS. Soit en utilisant un outil qui le fera avant la publication du site. Si vous êtes sous Visual Studio, une extension existe: Dotless mais j’ai un petit faible pour http://crunchapp.net/.



    Le CSS3 apporte son lot de nouveautés très appréciables.

    J’ai eu l’occasion d’en utiliser quelques unes:

    Importation de font

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @principalfont: Segoe UI;
    @font-face
    {	
       font-family:@principalfont;	
       src: url('../Font/SEGOEUI.TTF');
    }
    Personnalisation d’une scrollbar

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    ::-webkit-scrollbar {    
       width: 12px;    
       background-color:Gray;
    }
     
    ::-webkit-scrollbar-track {    
       -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);    
       border-radius: 10px;
    }
     
    ::-webkit-scrollbar-thumb {   
       border-radius: 10px;    
       -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
    }
    Utilisation des animations

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    .anim {
          -webkit-animation: monanim 80s infinite;
          -moz-animation: monanim 80s infinite;
          -ms-animation: monanim 80s infinite;
          -o-animation: monanim 80s infinite;
          animation: monanim 80s infinite;
        }
    Sélection de contrôles et états

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #username:hover
    {
        opacity: 1;
    }
     
    .navitems > ul > li:nth-child(3n) > div
    {
        background-color:   #db532b;   
    }
    Utilisation de Box pour aligner les éléments

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    #site
    {
        display: box; /* not supported by IE9, use table if we want IE support */
        box-orient:horizontal;
        box-pack:left;
        box-align:top;
     
        /* Firefox */
        display:-moz-box;
        -moz-box-orient:horizontal;
        -moz-box-pack:left;
        -moz-box-align:top;
     
        /* Safari and Chrome */
        display:-webkit-box;
        -webkit-box-orient:horizontal;
        -webkit-box-pack:left;
        -webkit-box-align:top;
     
        /* futur IE10, that's sucks */
        display: -ms-box;
    }
    Transformations 3D pour simuler un effet tilt:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    .tilt {
        -webkit-transition: -webkit-transform 0.1s linear;
        -webkit-transform: rotate3d(20, 100, 0, -20deg);
        -moz-transition: -moz-transform 0.1s linear;
        -moz-transform: rotate3d(20, 100, 0, -20deg);
        -o-transition: -o-transform 0.1s linear;
        -o-transform: rotate3d(20, 100, 0, -20deg);
        -ms-transition: -ms-transform 0.1s linear;
        -ms-transform: rotate3d(20, 100, 0, -20deg);
        transition: transform 0.1s linear;
        transform: rotate3d(20, 100, 0, -20deg);
    }
    Résultat avec le CSS:



    Quelques codes JavaScript ont du être ajoutés pour mettre en forme certaines choses, par exemple pour coller la barre de défilement par rapport a la div <content>:

    Avant , après

    A ce stade, l’intégralité du code se trouve ici:

    http://julien.dollon.net/html5/beta/

    Vous pouvez le tester exclusivement avec Mozilla/Chrome/IE11 car mon composant Box n’est supporté que par les derniers navigateurs.

    Capter le scroll de la souris et le clavier

    J’ai voulu que le scroll de la souris provoque non pas le défilement en vertical de la page, mais en horizontal.

    Pour cela il a fallut capter MouseWheel de la souris, trouver le sens, annuler la propagation de l’évènement pour annuler le défilement de la fenêtre et simuler le défilement de manière horizontal sur la div principale.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var iScroll = 0;
    var lastScroll = 0;
     
    $('#content').bind('mousewheel', function(event, delta) {
     
        $(this).scrollLeft(100 * -delta + (100 * iScroll));
     
        //Si a la fin
        if (!($(this).scrollLeft() == lastScroll)) {
            iScroll += -delta;
        }
        lastScroll = $(this).scrollLeft();
     
        event.stopPropagation();
    });
    Il peut être aussi intéressant de capter les évènements du clavier pour reproduire la même action. Forcement comme dab’ chaque navigateurs implémentent les évènements comme ils le veulent…

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $(document).bind('keydown', function (event) {
     
        event = event || window.event;
        var key = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
        switch (key) {
            case 37: // left arrow key
                ScrollAnimated(5);
                break;
            case 39: // right arrow key
                ScrollAnimated(-5);
                break;
        }
        event.stopPropagation();
    });
    Proposer un bouton “fullscreen”

    Voici un petit script pour mettre le site en fullscreen.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    function InitFullScreenButton() {
        $("#pluscentre").click(function () {
            //Chrome/Safari
            if (document.body.webkitRequestFullScreen != null)
                document.body.webkitRequestFullScreen();
            //Mozilla
            else if (document.body.mozRequestFullScreen != null)
                document.body.mozRequestFullScreen();
            //Opera
            else if (document.body.oRequestFullScreen != null)
                document.body.oRequestFullScreen();
            //IE11
            else if (document.body.msRequestFullScreen != null)
                document.body.msRequestFullScreen();
            else if (document.body.requestFullscreen != null)
                document.body.requestFullscreen();
            else
                alert("Your bullshit browser doesn't support the fullscreen features");
        });
    Création d’une tuile avec Adobe Edge

    Pour la tuile, il existe deux solutions.

    Dans un premier temps, je vais utiliser Edge en Preview de Adobe afin de vous montrer les capacités de ce logiciel. Edge est une sorte de Expression Blend version HTML5/JavaScript (jQuery pour être plus précis).

    L’avantage de cet outil est qu’il ressemble fortement a Blend. L’inconvénient est que les animations ne sont pas faites pour être éditées par la suite, c’est pourquoi, dans une second temps, je préfère opte pour une tuile faite main.



    Apres avoir lancé Edge, je crée un nouveau projet et je commence par dessiner un petit rectangle représentant ma tuile:






    Je configure mon rectangle (qui est en réalité une div) grâce au panneau de gauche.

    Changement de curseur par une main.

    Positionnement en haut a gauche.

    Mise en place du “Clip” pour que tout ce qui déborde de la div ne s’affiche pas.

    Changement de la couleur de fond.

    J’insère ensuite un texte et une image avec cette hiérarchie:



    Puis j’anime la div appelée secondRect en enregistrant son positionnement en Y. Pour cela, il faut faire un clique droit sur secondRect->Add Key Frame->Translate(Y).

    Puis grâce au storyboard viewer du bas, j’anime le tout.



    Il faut ensuite mettre un peu d’easing animation pour rendre le tout plus naturel.



    Ainsi qu’un trigger pour capter la fin de l’animation et la relancer.





    Création de la tuile “a la main”

    Pour cela, j’utilise les animations CSS3, c’est a dire un KeyFrame definissant une translation sur une division.

    En HTML, la tuile est représentée comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    <div class="box">
       <div class="imageXL"><img src="assets/images/windows.png" alt="" /></div>
       <div class="nomappXL">Kinect</div>
    </div>
    L’objectif étant d’avoir ceci (3 états, la durée de l’animation variant suivant la tuile):



    L’animation CSS3 est définie de cette manière:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @keyframes tuileTranslation {
        0% 
        {
            transform: translateY(0em);
        }
        25% 
        {
            transform: translateY(-3.75em);
        }
        75% 
        {
            transform: translateY(-7.5em);
        }
        100%
        {
            transform: translateY(0em);
        }
    }
    La div “mère” est clipped avant de ne pas voir l’image déborder lors de la translation:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    .box > .image
    {
        width:80px; 
        height:80px;
        margin: auto;
        clip:rect(15px, auto, auto, auto);
    }
    Et le JavaScript s’occupe d’initialiser l’image de la div pour la mettre en “background” (plus facilement manipulable pour moi). Il lance aussi l’animation CSS3 avec un temps “aléatoire”:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    $(".imageXL").each(function () {
        /* animation for tiles with random duration */
        var randomnumber = Math.floor(Math.random() * 6) + 1;
        $(this).css('animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-moz-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-webkit-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-ms-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .css('-o-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
               .next(".nomappXL")
                    .css('animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-moz-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-webkit-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-ms-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite')
                    .css('-o-animation', 'tuileTranslation ' + (10 + randomnumber).toString() + 's infinite');
     
     
        /* initilization of the background of the div depending of the image in it */
        $(this).find("img:first").css("visibility", "hidden");
        var imageUrl = $(this).find("img:first").attr("src");
        $(this).css('background-image', 'url(' + imageUrl + ')');
    });
    Mise en place d’un fond METRO

    Le but est d’afficher de manière random, un léger fond en mouvement.

    Nous allons utiliser les animations et transformations CSS compatibles avec les derniers browser du marche (sauf IE9 –> voir IE10).

    Mise en place du code HTML:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <body onload="MaMethod();">
        <div id="container">
            <div id="fond">
                <img src="D3B_2156q.jpg" id="img" alt=""/>
            </div>
            <div id="site">
               <!-- Site ici -->
            </div>
        </div>
    </body>
    La div “fond” représente l’image à afficher, le reste du site étant place dans “site”.

    Body va appeler une fonction JavaScript permettant d’attribuer au chargement de la page, une classe CSS à “fond” qui déclenchera l’animation.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    <script>
        function MaMethod() {
            var div = document.getElementById("fond");
            div.setAttribute("class", "anim");
        }
    </script>
    La partie CSS reste simple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    body 
    {
        padding: 0;
        margin: 0;
        background-color: black;
        overflow-y: hidden;
    }
     
    #fond > img {
        opacity: 0.5;
        position: fixed;
    }
    .anim {
          animation: monanim 60s infinite;
        }
     
    @keyframes monanim {
        0% {
               transform: translateY(0em);
               transform: translateX(0em);
        }
        25%{
               transform: translate(-15em,-5em);
        }
        75% {
               transform: translate(-15em, -10em);
        }
        100% 
        {
               transform: translate(0em, 0em);
        }
    }
     
    #site 
    {
        background-color: transparent;
        width: 2000px;
        height: 700px;
        opacity: 0.5;
    }
    Le résultat:

    http://julien.dollon.net/html5/fond/index.htm



    Création du service Node.js

    Introduction

    Il y a dix ans, quand j’ai comence le JavaScript, la première chose qu’on m’a appris: Le JS tourne cote client.

    Et bien plus maintenant! Node.js est l’un des nombreux Framework permettant de faire des services avec JavaScript.

    Je conseil l’editeur en ligne si vous voulez tester/debuguer du node.js: http://c9.io/



    Les avantages d’utiliser Node.js sont:


    • Si vous avez du code JS a porter cote serveur, c’est très simple
      • Ici pas notre cas
    • Si vous êtes un pro du JS/dev web et que vous ne connaissez pas bien un langage d’Homme () comme Java ou C#, node.js vous sauve la vie
    • Si vous voulez faire un service léger et rapide, restfull, avec CouchDB ou autre, un truc code a l’arrache from scratch c’est pas mal.
    Les désavantages:


    • C’est du JavaScript. Autant cote client je comprends l’utilisation d’un langage dynamique est intéressant, mais la cote serveur c’est risque des erreurs dans tous les sens
    • L’API est clairement instable, et en plus manque d’optimisation (du style réutilise pas le thread courant pour re-exécuter un service etc…)
    • Manque de librairies, comment accéder a mon SQL Server? A mon API S3 ou Azure? etc… Les APIs dispos sont très maigres
    Création du service

    Le service doit être capable de retourner:


    • La dernière vidéo du compte Soumow de youtube
    • Les 5 derniers articles de mes blogs perso et pro
    • Mes 6 contacts réseaux sociaux
    • Mes 5 derniers projets
    Le tout en JSON avec un service RESTFULL.

    Je pourrais utiliser un routeur de requête type Journey, mais j’ai voulu me débrouiller de A a Z.

    Je commence donc par initialiser mon fichier JavaScript:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var http = require("http");
    var url = require("url");
    var querystring = require("querystring");
     
    var handle = { };
    handle["/"] = rootCall;
    handle["/lastarticles"] = lastArticles;
    handle["/lastprojects"] = lastProjects;
    handle["/lastvideo"] = lastVideo;
    handle["/socialnetworks"] = socialnetworks;
    Mon objet handle contient des pointeurs de fonctions vers les méthodes a appeler.

    Je démarre ensuite un serveur sur le port 8888 et je route le tout (merci au livre sur Node.js).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function route(handle, pathname, request, response) {
        console.log("About to route a request for " + pathname);
        if (typeof handle[pathname] === 'function') {
            handle[pathname](request, response);
        } else {
            console.log("No request handler found for " + pathname);
            writeFast(response, "Error, no method found");
        }
    }
     
    http.createServer(function (request, response) {
        //
        var pathname = url.parse(request.url).pathname;
        console.log("Request for " + pathname + " received.");
        route(handle, pathname, request, response);
    }).listen(8888);
    Résultat, quand j’appelle l’url /socialnetworks, la fonction socialnetworks est appelée.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function socialnetworks(request, response) {
        response.writeHead(200, { "Content-Type": "text/json" });
        var socials = new Array();
        socials.push(new DataContractElement("Facebook", "fb.png", "", "https://www.facebook.com/julien.dollon"));
        socials.push(new DataContractElement("Twitter", "twitter.png", "", "https://twitter.com/#!/juliendollon"));
        socials.push(new DataContractElement("Google+", "google.png", "", "https://plus.google.com/110722800174049431616/posts"));
        socials.push(new DataContractElement("Linkedin", "linkedin.png", "", "http://www.linkedin.com/profile/view?id=7903132&trk=tab_pro"));
        socials.push(new DataContractElement("Resume", "", "", "http://julien.dollon.net/dollon_en.pdf"));
        socials.push(new DataContractElement("MVP Profil", "", "", "http://www.microsoft.com/france/communautes/annuaire/acteurs.aspx?auteur=Dollon"));
     
        response.write(JSON.stringify(socials));
        response.end();
    }
    De même pour les autres fonctions du service.

    Pour le téléchargement des divers flux rss j’ai utilise la librairie Future qui permet de faire des ForeachAsync et des .Then() plutôt pratique.

    La méthode permettant de retrouver la dernière video YouTube nécessite de faire une requête GET a l’API Youtube.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    var options = { host: "gdata.youtube.com"
            , path: "/feeds/api/users/" + account + "/uploads?v=2"
    };
    //make the request server side
    http.get(options, function (resp) {
        //console.log("hi",response);
        response.writeHead(200, { 'Content-Type': 'text/plain' });
        var pageData = "";
        resp.setEncoding('utf8');
        //stream the data into the response
        resp.on('data', function (chunk) {
            pageData += chunk;
        });
     
        //write the data at the end
        resp.on('end', function () {
            response.write(pageData);
            response.end();
        });
     
        });
    Mise en place du service

    Node.js est supporte par Azure mais comme ca coute un bras je vais opte pour un déploiement standard sur mon serveur perso avec IIS7.

    Ce lien nous explique comment héberger un service node.js dans IIS:

    http://www.amazedsaint.com/2011/09/c...ng-app-on.html

    En gros il faut:


    Voici le résultat:

    http://home.dollon.net/node/service/personalservice.js/

    Comme en Silverlight et WCF, il faut initialiser le clientaccesspolicy.

    Attention aux failles de sécurité avec une “*” en cas d’injection de code XSS.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    response.writeHead(200, {
            'Content-Type': 'text/plain',
            'Access-Control-Allow-Origin' : '*'
        });
    Typage du JavaScript et mode strict

    A ce stade, J’ai commence a utiliser du JS par ci par la mais je n’ai pas fait attention au best practices.

    Tout d’abord en terme d’architecture mais j’en parlerai a l’étape suivante.

    Mais aussi en terme de typage et propreté du code.

    Il existe un mode en JavaScript (ECMAScript 5) qui permet d’être dans un contexte plus stricte que celui de d’habitude. Cet environnement impose certaines règles de développement et désactives des fonctionnalités de JS pouvant être dangereuse.

    Pour l’utiliser il faut rajouter:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <code>"use strict";</code>
    Au niveau du scope du code a protéger.

    Désormais, si j’utilise une variable non déclarée, j’aurai une erreur dans la console JavaScript:



    Plus d’infos sur le mode strict ici:

    http://hacks.mozilla.org/2011/01/ecm...-in-firefox-4/

    Une deuxième chose qui existe et qui améliore le code JavaScript est TypedJS.

    TypedJS permet d’annoter nos fonctions avec un commentaire précisant le type de retour et des params.

    Ce commentaire est lu par des le lancement dans une console JS de “TypedJS.run_tests()”.

    A noter que TypedJS supporte Node.js.

    Mise en place de l’architecture avec Knockout.js

    Depuis le début, je n’utilise aucune architecture. Normal cote front end, puisque que ce soit en MVVM en Silverlight ou JS, tant que le code touche des aspects purement graphiques, je le laisse dans la vue.

    Sauf que la, je vais avoir du code pour consommer mon service! Je décide donc de partir sur Knockout.js.

    Un seul lien pour l’apprendre: http://learn.knockoutjs.com/

    Knockout fournis un framework MVVM avec tout ce qui tourne autours comme le Binding, Observables…

    Pour l’installer, tout est explique ici: http://knockoutjs.com/documentation/installation.html

    Notre ViewModel a besoin d’exposer:


    • Une propriété représentant la vidéo
    • Une collection de projets
    • Une collection de réseaux sociaux
    • Une collection d’articles
    • Une propriété IsBusy pour dire que le chargement est en cours
    • Une prop pour afficher si il y a une erreur
    Tous les liens auront le même model (attention au context “this” qui peut bouger):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function DataContractElement(title, image, description, link) {
        var self = this;
        self.title = title;
        self.image = image;
        self.description = description;
        self.link = link;
    }
    On crée le ViewModel, ici par exemple avec une propriété Observable qui sera l’url vers la vidéo youtube:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    "use strict";
    function principalViewModel() {
        var self = this;
     
        self.isBusy = ko.observable(true);
        self.videoUrl = ko.observable("");
        self.error = ko.observable("");
        self.projects = ko.observableArray([]);
        self.sociallinks = ko.observableArray([]);
        self.lastarticles = ko.observableArray([]);
     
        $.ajax({
            type: "GET",
            url: lastvideourl,
            success: function (json) {
                var mapped = new DataContractElement(
                    json[0].title, json[0].image, json[0].description, json[0].link);
                if (mapped.title == null) {//Bug Firefox
                    mapped = new DataContractElement(
                    JSON.parse(json)[0].title, JSON.parse(json)[0].image, JSON.parse(json)[0].description, JSON.parse(json)[0].link);
                }
                self.videoUrl(mapped.link);
                self.isBusy(false);
            },
            error: function (xhr, textStatus, errorThrown) {
                self.error(xhr.responseText);
            }
        });
    }
    On instancie, dans le load de notre page, le ViewModel de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ko.applyBindings(new principalViewModel());
    Et cote vue, on réalise un binding sur l’iframe de Youtube:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <iframe data-bind="attr: {src: videoUrl}"></iframe>
    De même pour la liste des articles, sauf que cette fois ci je travaille avec un observableArray et des templates.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    <ul data-bind="foreach: lastarticles">
        <li>Name: <span data-bind="text: title"> </span>
    </ul>
    Je termine avec la capture de l’évènement clic et ouverture du lien dans une popup:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <li data-bind="click: $parent.launchLink">
    Téléchargement des images

    Dans la version non public du site, j’ai voulu utiliser le web worker (un thread JS grâce a HTML5) pour télécharger les images de fond.

    Le problème est que très peu de navigateur le supporte, mais si vous souhaitez voir comment j’ai fais pour downloader une image, c’est par ici:

    http://www.html5rocks.com/en/tutoria...lesystem-sync/

    Splash screen

    Tout d’abord, je souhaite dessiner mon logo.

    Pour cela deux options s’offre a moi:

    Le canvas, qui va générer un bitmap, c’est a dire quelque chose de “plat” et fixe en 2d tel une image. Par default on dessine en 2D mais WebGL permet de faire de la 3D. On l’utilise avec une balise en HTML5 et on pilote le dessin avec JavaScript.

    Les points positifs: performant, possibiliter d’exporter le resultat en image.

    De l’autre cote, nous avons un format vectoriel, SVG, base sur du XML.

    Les points positifs: j’ai déjà au format Illustrator mon logo, facile a convertir en SVG, facilement animable.

    Je decide donc de partir sur SVG. Je rajoute une progressbar (nouveauté HTML5) avec un petit skin CSS3 et un binding en MVVM sur la propriété isBusy:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <div id="loadingpage" data-bind="visible: isBusy"> <!---->
     
        <svg version="1.1" id="svglogo"
                xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
                x="0px" y="0px" width="500px" height="500px"  viewBox="-96.46 -235.46 595 842"
                xml:space="preserve">
        <defs>
        </defs>
        <polygon fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" points="115.874,202.54 115.874,65.874 180.54,1.207 
            180.54,360.54 0.707,180.707 47.707,133.707 "/>
        <polygon fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" points="214.54,360.54 395.207,180.874 214.54,1.207 
            214.54,91.874 304.874,180.874 214.54,271.207 "/>
        </svg>
     
        <div id="loadingElement">
            <progress max="100" data-bind="value: pourcentage">
            </progress>
            <span  data-bind="text: pourcentage"></span>
        </div>
    </div>




    Un hack en CSS?

    A ce stade, on a presque fini… Mais on va pas se leurrer, seul peu de navigateurs le supporte.

    Le constat est le suivant:


    • Aucun pb pour Mozilla
    • Aucun pb pour WebKit (Chrome, Safari)
    • Opera chie dans la colle
    • IE9 a des pbs aussi (mais IE10 fonctionne)
    Normalement, je devrais faire plusieurs fichiers CSS et des hack JS pour que tout fonctionne sur tous les navigateurs… mais j’ai pas envi!

    Bon je sais bien, on peut pas dire ca entreprise mais comme c’est mon site perso, je m’en fou .

    Donc direction modernizr, un petit outil JS me permettant de tester les capacités d’un navigateur.

    http://www.modernizr.com/

    Je configure donc toutes les features dont j’ai besoin:



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function VerifyBrowserCapacities() {
        Modernizr.load();
        var listOfNonSupported = [];
        for (var propertyName in Modernizr) {
            if (!Modernizr[propertyName])
                listOfNonSupported.push(propertyName);
        }
     
        if (listOfNonSupported.length > 0) {
            var root = window.location.toString().toLowerCase().replace("index.html", "");
     
            //alert(root.split('')[root.length - 1]);
            if (root.split('')[root.length - 1] != '/')
                root += '/';
            //alert(listOfNonSupported.toString());
            window.location = root + "notsupported.html?error=" + listOfNonSupported.toString();
     
     
        }
    }
    A ce stade, voici le rendu:

    http://home.dollon.net/node/website3/

    Utilisation de Media en CSS

    Les media queries permettant de filtrer le CSS suivant le device.

    Je vais l’utiliser pour imposer une résolution minimum.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @minwidth: 800px;
    @minheight: 700px;
    @media screen and (max-width: @minwidth) or (max-height: @minheight) {
           .popuppage 
        {
            .popuppageabstract;
            visibility:visible;
        }
    }
    @media screen and (min-width: @minwidth) and (min-height: @minheight) {
        .popuppage 
        {
            .popuppageabstract;
            visibility:hidden;
        }
    }


    De même, mes images de fonds ont une taille maximum de 2598x1417 + l’effet de translation. Sur de gros écrans ou sur un iPad, le résultat n’est donc pas terrible. Pour cela je désactive le background pour ces résolutions trop haute.

    Une autre problématique, qui ne se résout pas avec le CSS mais que je met ici quand même: le viewport.

    Il faut pouvoir empêcher les tablettes de pouvoir zoomer/dezoomer et forcer le scale de base de la page.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
    une autre chose importante, est d’imposer a l’utilisateur le mode landscape. Mon site rendant clairement mieux tout en longueur.

    Pour forcer l’utilisateur, je pourrai utiliser body[orient="landscape"] en CSS mais cette propriété ne marche pas partout.

    J’utilise donc un petit hack JavaScript:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     <body onload="OnLoad();" onorientationchange="updateOrientation();">
    Version offline et stockage des articles hors ligne

    L’objectif de la version offline va être de pouvoir montrer mon beau site quand j’ai pas internet.

    Je vais devoir mettre en cache, la page, les scripts, les images mais aussi les données venant du service.

    Pour les données j’ai le choix entre les stockes dans un indexeddb ou dans le webstorage. Indexeddb n’est pas encore bien supporte par Safari, j’opte donc pour le second.

    Plus d’infos sur ces types de storages ici:

    http://stackoverflow.com/questions/6...dexed-database

    Pour commencer, je vais mettre en cache tout le site grâce a l’applicationcache feature.


    • Mise a jour du web.config pour gérer les fichiers manifest
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <configuration>
     <system.web>
      <httpHandlers>
       <add verb="GET,HEAD" path="*.appcache"        type="System.Web.StaticFileHandler" />
      </httpHandlers>
     </system.web>
     <system.webServer>
      <staticContent>
       <mimeMap fileExtension=".appcache"      mimeType="text/cache-manifest" />
      </staticContent>
     </system.webServer>
    </configuration>
    • Création du fichier manifest qui décrit les éléments accessibles offline
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    CACHE MANIFEST
    # version 1
     
    CACHE:
    Index.html
    notsupported.html
    favicon.ico
    Font/SEGOEUI.TTF
    Assets/less.css
    Assets/jquery-1.5.1.min.js
    Assets/jquery.mousewheel.min.js 
    Assets/principalViewModel.js
    Assets/wallpaper/0.jpg
    Assets/wallpaper/1.jpg
    Assets/wallpaper/2.jpg
    Assets/images/book.png
    Assets/images/df.png
     
    NETWORK:
    *
    • Eviter les conflits and client et browser caching en désactivant le caching du browser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <meta http-equiv='Pragma' content='no-cache'>
    <meta http-equiv='Expires' content='-1'>
    • Tester!
    Il faut maintenant stocker les données du service dans le storage.

    Le webstorage propose deux types de stores: local et Session.

    Local storage fonctionne comme un cookie, l’information pouvant être récupérer a tout moment alors que la session a une durée de vie plus limitée.

    Pour mon cas, ca sera donc le localstorage (taille entre 2 et 10mo, amplement suffisant).

    Désormais, même sans internet, ma page sera accessible.

    Simplifier les fichiers JS et CSS

    Me voici dans la phase avant déploiement: quelques petites choses sont encore a finaliser:


    Ce compilateur de Google se décrit comme un compilateur qui compile du JS en JS, mais un JS plus rapide, plus optimisé.

    Pour faire un test:

    http://closure-compiler.appspot.com/home

    Pour ma part:




    • Nettoyer le HTML (et si vous avez le courage, le faire passer W3C)
    • Optimiser les performances

    Résultats



    Résultat sur PC



    WTF WINDOWS ON A MAC!!!!

    Grace au site http://browserling.com/ je peux émuler le site web sur tous les navigateurs.

    Tous les derniers navigateurs de la famille IE, Chrome, Safari et Mozilla sont capables de l’afficher correctement.

    Le site final:

    home.dollon.net

    Résultat sur tablette

    Android



    iPad



    Windows 8



    Conclusion

    HTML5 pour le web est la, s’apprend assez vite et est un plaisir a utiliser.

    Cependant, il n’est la que depuis peu, car seul les derniers navigateurs (encore parfois en beta) le supporte.

    Internet Explorer est le navigateur un peu en retard par rapport aux autres. Mais le 10 corrige tout. C’est donc pour la sortie de IE10 RTM (fin 2012/début 2013) que je conseillerai le développement HTML5. D’ici la, nous avons le temps de monter en compétence.

    HTML5: Oui!
    Avant 2013? Non!
    Billet original du blog de Julien Dollon
    Dernière modification par Domi2 ; 25/05/2012 à 16h50.

Discussions similaires

  1. Intégrations sur site internet de contenue lisible pour IPAD : Flash ou HTML5
    Par tidou95220 dans le forum Autres Solutions d'entreprise
    Réponses: 1
    Dernier message: 18/09/2012, 16h07
  2. Une compétition pour les développeurs de jeux HTML5
    Par Golgotha dans le forum Actualités
    Réponses: 0
    Dernier message: 07/08/2012, 11h23
  3. [Autre] HTML5 est-il adapté pour les jeux sur le Web ?
    Par Hinault Romaric dans le forum Publications (X)HTML et CSS
    Réponses: 42
    Dernier message: 22/01/2012, 13h17
  4. HTML5 est-il adapté pour les jeux sur le Web ?
    Par Hinault Romaric dans le forum Balisage (X)HTML et validation W3C
    Réponses: 42
    Dernier message: 22/01/2012, 13h17
  5. Réponses: 13
    Dernier message: 18/12/2009, 16h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo