Proposition de structure JavaScript

Modified version of the Garber-Irish Implementation of a Markup-based unobtrusive comprehensive DOM-ready execution.

by fparent

HTML

<link rel="stylesheet" href="https://raw.github.com/fparent/StarterCSS/master/starter.min.css">
<h1>Structure JavaScript</h1>

<p>Voici la nouvelle technique (aussi appelée "DOM-based Routing" et présente dans plusieurs frameworks comme Backbone, Ruby, CodeIgniter, etc.) que j'ai commencé à utilisée dernièrement dans mes projets. C'est une version que j'ai adaptée de la méthode Garber-Irish qui exécute automatiquement des functions JavaScript à la fin du chargement des pages, sans obstruer le document HTML (comme nous le faisais actuellement en faisant NAMESPACE.function partout).</p>

<p>À mon avis, c'est une excellente technique autant pour les petits projets que pour les gros. Elle peut sembler limitée à première vue, mais qui offre une très bonne structure tout en étant extrêmement flexible. Elle permettrait de développer des sites plus modulaires, faciles à maintenir, mieux structurés, avec avec du code plus compréhensif et "propre", et qui évolueraient bien avec le temps.</p>

<p>Le fonctionnement est simple: au lieu d'appeller toutes les functions individuellement dans chacunes des pages comme ceci...</p>

<div class="code">
    &lt;script&gt;<br />
        &nbsp;&nbsp;&nbsp;PROJET.initHome();<br />
        &nbsp;&nbsp;&nbsp;PROJET.initValidation();<br />
        &nbsp;&nbsp;&nbsp;PROJET.initCarousel();<br />
    &lt;/script&gt;
</div>
        
<p>... la technique utilise les attributs HTML5 "data" sur le body, ce qui fait plus "propre" et fait du sens sémantiquement parlant.</p>

<h3>Nouveaux attributs, moins de redondance</h3>
<p>Les attributs disponibles sont "data-controller" et "data-action" et ils sont utilisés sur la balise "body". Le controller représente une function spécifique de la page en cours (par exemple, data-attribute="contact" équivaut à SITE.contact.init() et serait probablement utilisé dans la page "Contact Us") et l'action correspond à une tâche particulière de cette page. Les controlleurs peuvent aussi avoir une function "init";...

CSS

html {
    font-family: sans-serif;
    font-size: 80%;
    line-height: 1.3em;
    color: #444;   
}

h3 { 
    margin-top: 3em;
}

p, .code, li {
    margin-bottom: 1.5em;
}

.code {
    background-color: #fefdf2;
    border: solid 1px #dad8c5;
    padding: 1em;
    margin-top: 0.5em;
}

mark {
    background-color: #15e1ff;
    color: #fff;
}

JavaScript

// Une version sans commentaire du boilerplate est disponible ici: 
// http://bit.ly/Mahd5J (1.5k)

// Namespace principal du projet.
// Sert à englober et restreindre le code du projet, ainsi
// qu'à exposer l'interface publique. Je suggère qu'on utilise
// toujours le préfixe "UI_" dans nos variables globales pour
// réduire au maximum les chances de conflits et être plus
// représentatif de l'entreprise.
var UI_PROJECT = (function( $, window, document, undefined ) {
    
    // Devrait maintenant être utilisé dans tous nos projets.
    // Va nous permettre de développer du meilleur code JavaScript:
    // http://bit.ly/JNBf5z
    'use strict';

    var SITE = {}, UTIL = SITE;

    // Objet contenant toutes les fonctionnalitées propres au site en cours.
    SITE = {
        common: {
            // Function commune exécutée dans toutes les pages
            init: function() {
                console.log('exécute une action générale');
            },
            
            // Exemple de function commune qui pourrait servir pour
            // certains controlleurs seulement
            notSoCommon: function() {
                console.log('exécute une action générale spécifique à certaines pages');                    
            },
            
            // Exemple d'action commune qui pourrait être appellé sans controlleur,
            // comme dans les pages d'erreur par exemple, en utilisant
            // <body data-action="error">...
            error: function() {
                console.log('oups, ceci ressemble à une page d\'erreur!');
            }
        },

        // Chaque controlleur représente une page
        home: {
            init: function() {
                console.log('initialisation de la page Home');
                
                // Appelle une function semi-commune, qui pourrait servir à certains 
                // controlleurs seulement.
                SITE.common.notSoCommon();
            },
            
           ...