11540 sujets

JavaScript, DOM et API Web HTML5

Trouvez-vous utile le principe d'appliquer les plugins jQuery directement via le code HTML ?




Bonjour,

Je continue dans ma lancée afin de vous présenter mes plugins, celui-ci est certainement celui que j'utilise le plus car il permet d'appliquer des plugins jQuery sur les DOMs HTML sans une ligne de Javascript.

Site internet: http://marcbuils.github.com/jquery.pluginautoload/
Documentation en français: http://www.marcbuils.fr/2012/10/jquerypluginautoload-chargement.html

Exemple d'utilisation
Le code suivant charge en ajax les fichiers script js/jquery.myplugin.js et js/jquery.mypluginparams.js puis applique ces plugins sur les DOMs respectifs.

<!doctype>
<html>
<head>
    <meta charset="UTF-8" />
    <title>jQuery.pluginautoload: Exemple1 - Auto-loading Full options/without configuration</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="../jquery.pluginautoload.js"></script>
</head>
<body>
    <h1>jQuery.pluginautoload: Exemple 1 - Auto-loading Full options/without configuration</h1>
    <div data-jquery-type="myplugin"></div>
    <div data-jquery-type="mypluginwithparams" data-jquery-params='["parameters1", {"paramaters2": "is a struct"}, 325]'></div>
</body>
</html> 


Je trouve ça plus propre, plus rapide et plus facile de pouvoir appliquer les plugins jQuery sans devoir passer par du code Javascript qu'on ne sait pas toujours ou mettre.

Qu'en pensez vous ?
Modifié par marcbuils (24 Oct 2012 - 22:48)
J'ai du mal à comprendre l'apport de cette technique.

Actuellement je charge mon js dans mon header ou dans mon footer et l'execution de ce dernier s'applique au DOM que je veux, sans mettre une seule ligne de JS dans mon html.

Peux-tu m'en dire plus ?
En fait, avec cette méthode, tu n'as plus besoin d'avoir ce js custom dans ton header ou ton footer.

Par exemple, imaginons que tu souhaites faire des tabs avec le plugin jQueryUI. Actuellement tu dois avoir un code qui ressemble à ça:

<!doctype html>
 
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>jQuery UI Tabs - Default functionality</title>
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.0/themes/base/jquery-ui.css" />
    <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
    <script src="http://code.jquery.com/ui/1.9.0/jquery-ui.js"></script>
    <link rel="stylesheet" href="/resources/demos/style.css" />

    <script src="mon_js_custom.js"></script>

</head>
<body>
 
<div id="tabs">
    <ul>
        <li><a href="#tabs-1">Nunc tincidunt</a></li>
        <li><a href="#tabs-2">Proin dolor</a></li>
        <li><a href="#tabs-3">Aenean lacinia</a></li>
    </ul>
    <div id="tabs-1">
        <p>Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.</p>
    </div>
    <div id="tabs-2">
        <p>Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.</p>
    </div>
    <div id="tabs-3">
        <p>Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.</p>
        <p>Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.</p>
    </div>
</div>
</body>
</html>


Et un fichier 'mon_js_custom.js' à part qui ressemble à ça:

;(function($){
    $(function() {
        $( "#tabs" ).tabs();
    });
})(jQuery);



Avec le plugin jQuery.pluginautoload, tu n'as plus besoin du fichier 'mon_js_custom.js' ce qui donne:

<!doctype html>
 
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>jQuery UI Tabs - Default functionality</title>
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.0/themes/base/jquery-ui.css" />
    <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
    <script src="http://code.jquery.com/ui/1.9.0/jquery-ui.js"></script>
    <link rel="stylesheet" href="/resources/demos/style.css" />

    <script src="jquery.pluginautoload.js"></script>

</head>
<body>
 
<div data-jquery-type="tabs">
    <ul>
        <li><a href="#tabs-1">Nunc tincidunt</a></li>
        <li><a href="#tabs-2">Proin dolor</a></li>
        <li><a href="#tabs-3">Aenean lacinia</a></li>
    </ul>
    <div id="tabs-1">
        <p>Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.</p>
    </div>
    <div id="tabs-2">
        <p>Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.</p>
    </div>
    <div id="tabs-3">
        <p>Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.</p>
        <p>Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.</p>
    </div>
</div>
</body>
</html>
Donc je remplace <script src="fonctions.js"></script> par <script src="jquery.pluginautoload.js"></script>. Je ne vois toujours pas le gain de la manipulation :S dans mon cas de figure.

En gros c'est utile pour charger les fonctions par défaut des plugins ?
Modifié par Klesk (24 Oct 2012 - 10:07)
Hello,

Sur la question de la "propreté" : je ne vois pas trop l’intérêt de blinder le HTML de data-type pour éviter quelques balises scripts. La question du "code Javascript qu'on ne sait pas toujours ou mettre" a été réglée depuis des années : juste avant la fermeture du body.

En terme de code, ton plugin pose un grand nombre de soucis :

- Tu as une dépendance entre le nom de ton plugin et le nom de sa méthode d'appel. Ex: tabs.js pour $.tabs(). SI le fichier est renommé en tabs-v2.1.js, c'est mort.

- Tu passes les params via le HTML, et les parses par un JSON.parse. Donc, tu ne peux pas passer de callbacks, et sous les vieux IE, ça ne marchera pas (pas de support de JSON).

- Des consoles dans le code. IE < 9 ne va pas trop apprécier.

- Si tu utilises plusieurs fois le même plugin dans une page, tu le recharges. Pas la joie au niveau perf.

- Tu lazyload tes appels de scripts, mais via Ajax, ce qui craint pour plein de raisons, et de façon synchrone, ce qui gèle la page.

- Le fait d'avoir un libs_dir te bloque totalement si tu désires avoir une arborescence un peu plus complexe dans tes répertoires de scripts.

- Aucune possibilité de créer un build avec tous tes fichiers concaténés en un seul, donc tu t'interdit les optimisations de perf à postériori.


Désolé si j'ai l'air rude. Le but n'est pas du tout de te descendre, mais en l'état ton plugin viole beaucoup de bonne pratiques, en particuliers la séparation HTML / JS, et ne permet en aucun cas un développement flexible, tout en massacrant les perfs.
Klesk: Je te confirme en effet que c'est uniquement pour les fonctions par défaut des plugins. Tu peux passer des paramètres mais pas de callback par exemple.
Je n'ai pas réussi à comprendre tout de suite ta remarque tout simplement parce que je ne développe que sous forme de plugin jQuery par défaut.
C'est à dire que lorsque j'ai des callbacks à traiter ou des traitements plus complexe à effectuer, je créé un plugin jQuery custom car je trouve ça plus simple à maintenir (mais c'est un point de vu très personnel Smiley langue )

Florian_R: c'est rude, je te confirme Smiley cligne
Mais c'est cependant très intéressant et je te remercie pour tes remarques.

Réponse 1:
a écrit :

- Tu as une dépendance entre le nom de ton plugin et le nom de sa méthode d'appel. Ex: tabs.js pour $.tabs(). SI le fichier est renommé en tabs-v2.1.js, c'est mort.

Si tu regarde mon exemple, il n'existe pas de fichier tabs.js car la fonction $.fn.tabs est incluse par la librairie jQuery.UI (jquery-ui.js).
En fait le plugin jQuery.pluginautoload vérifie si le plugin est connu (si $.fn[{NOM_DU_PLUGIN}] existe) et ne charge le fichier en Ajax que si le plugin n'a pas encore été chargé.
De plus, si tu as une arborescence simplement organisée différemment, le nom du fichier chargé est généré par une fonction options.filename. On peux donc modifier cette fonction afin de l'adapter à son arborescence et sa nomenclature.
Et ce n'est pas possible parce qu'il n'y a pas de nomenclature particulière ou parce qu'on préfère charger les fichier de manière classique (ce qui est plus simple pour débugger par exemple), on peut utiliser la balise script ou bien tout autre moyen.

Réponse 2:
a écrit :

- Tu passes les params via le HTML, et les parses par un JSON.parse. Donc, tu ne peux pas passer de callbacks, et sous les vieux IE, ça ne marchera pas (pas de support de JSON).

C'est une excellente remarque.
En faite il existe des librairie JSON qui ajoute ces fonctionnalités pour d'ancien navigateur, mais il faudrait au moins préciser la dépendance au niveau du readme et de l'intégrer dans les exemple ou faire en sorte que le plugin charge celle-ci automatiquement lorsque c'est nécessaire.
En tout cas si tu sais comment résoudre le problème n'hésites pas à forker le projet afin de l'améliorer, je pourrais ainsi intégrer tes modifications dans le projet initial. Sinon peux tu ajouter ta remarque dans une nouvelle issue sur le projet github afin que je la prenne en compte pour la prochaine version ?
Merci !

Réponse 3:
a écrit :

- Des consoles dans le code. IE < 9 ne va pas trop apprécier.

Je t'avoue que lorsque j'ai besoin de débugguer j'ajoute temporairement la <script> qui va bien pour charger le fichier de manière classique ce qui facilite le boulot du debugger.
Mais si quelqu'un connait une autre méthode, je suis preneur car ce n'est pas le plus pratique...

Réponse 4:
a écrit :

- Si tu utilises plusieurs fois le même plugin dans une page, tu le recharges. Pas la joie au niveau perf.

Non, Il n'est chargé qu'une seule fois (voir Réponse 1).

Réponse 5:
a écrit :

- Tu lazyload tes appels de scripts, mais via Ajax, ce qui craint pour plein de raisons, et de façon synchrone, ce qui gèle la page.

Tu as raison, je devrais regarder du coté du Lazyload qui ajoute une balise <script>...
En ce qui concerne le faite de geler la page je suis d'accord que ce n'est pas la meilleur solution et que c'est à améliorer pour la prochaine version. D'ailleurs, après ta remarque, je viens de m'apercevoir que je pourrais faire une solution assez propre avec des $.Deferred.
N'hésites pas à ajouter aussi cette remarques dans les issues ou à modifier directement le code si tu es partant Smiley cligne

Réponse 6:
a écrit :

- Le fait d'avoir un libs_dir te bloque totalement si tu désires avoir une arborescence un peu plus complexe dans tes répertoires de scripts.

En faite libs_dir n'est utilisé qu'à titre indicatif dans la fonction filename par défaut. Mais on peux adapter cette fonction filename suivant l'arbo utilisée Smiley cligne

Réponse 7:
a écrit :

- Aucune possibilité de créer un build avec tous tes fichiers concaténés en un seul, donc tu t'interdit les optimisations de perf à postériori.

Si, c'est tout à fait envisageable car comme je l'expliquait dans la réponse 1, aucun fichier n'est chargé en ajax si le plugin demandé est déjà chargé Smiley cligne


En tout cas merci beaucoup pour vos remarques, ça va m'aider à améliorer le plugin, et n'hésitez surtout pas à en faire d'autres !!!
Au temps pour moi, j'étais passé à côté du if($.fn[{NOM_DU_PLUGIN}) dans le code.

Donc si je résume bien :

- Dès que l'arborescence est un peu complexe, ou que les noms de fichiers ne mappent pas directement sur le nom de la méthode du plugin, tu passes par options.filename.
Du coup, pour des cas un peu complexe, la solution la plus simple que je vois est que cette fonction renvoie le filename suivant un hash type => chemin du fichier. Je ne vois pas la souplesse là-dedans.

- Si tu as optimisé avec un build ou pour certains cas particuliers, tu utilises quand même une balise script avant ton plugin. Donc avec un build bien fait, tu appelles ton plugin pour rien. Smiley sweatdrop

- La remarque pour les consoles, c'était juste pour souligner qu'il y en a dans le code du plugin et qu'un console dans le code pète dans les vieux IE (pris en charge uniquement à partir de IE9).

- Purement techniquement parlant (même si je persiste à croire que charger du js en Ajax n'est PAS la solution), je ne vois pas l’intérêt du async ou des $.Deferred. Un simple callback sur le success est largement suffisant.

Je ne vois vraiment pas l’intérêt de parser tous le DOM (this.find('[data-jquery-type]:not(.jquery_pluginautoload)').each), pourrir le markup de paramètres pour le JS et se priver de callbacks quand un basique loadScript, quelques data-attributes si nécessaire pour s'apporter de la souplesse et une méthode pour lancer son appli avec un seul js (voir DOM-ready execution) font largement mieux le boulot en conservant la séparation des couches.
Florian_R a écrit :
Au temps pour moi, j'étais passé à côté du if($.fn[{NOM_DU_PLUGIN}) dans le code.

Donc si je résume bien :

- Dès que l'arborescence est un peu complexe, ou que les noms de fichiers ne mappent pas directement sur le nom de la méthode du plugin, tu passes par options.filename.
Du coup, pour des cas un peu complexe, la solution la plus simple que je vois est que cette fonction renvoie le filename suivant un hash type =&gt; chemin du fichier. Je ne vois pas la souplesse là-dedans.

Je pense que la solution la plus simple est de ne pas utiliser cette fonctionnalité si elle ne te sert à rien.

Florian_R a écrit :

- Si tu as optimisé avec un build ou pour certains cas particuliers, tu utilises quand même une balise script avant ton plugin. Donc avec un build bien fait, tu appelles ton plugin pour rien. Smiley sweatdrop

Je trouve surtout que ça permet d'avoir une meilleur visibilité du fonctionnement du site rien qu'en lisant le code HTML. Mais ce n'est qu'un point de vu personnel. De plus, ce principe est utilisé également pour des librairies tel que Dojo ou encore jQuery mobile (que j'ai pris en exemple pour écrire ce plugin), je ne l'ai pas inventé mais j'ai juste souhaité l'appliquer sur mes autres développements jQuery.

Florian_R a écrit :

- La remarque pour les consoles, c'était juste pour souligner qu'il y en a dans le code du plugin et qu'un console dans le code pète dans les vieux IE (pris en charge uniquement à partir de IE9).

En effet, je n'avais pas pensé à ça, je te remercie pour ta remarque.

Florian_R a écrit :

- Purement techniquement parlant (même si je persiste à croire que charger du js en Ajax n'est PAS la solution), je ne vois pas l’intérêt du async ou des $.Deferred. Un simple callback sur le success est largement suffisant.

Purement techniquement parlant le principe que tu me donnes ne fonctionnes pas (mais j'ai été le premier à me faire avoir), tout simplement parce que le plugin peut essayer de charger plusieurs fois le même script (si il est appliqué sur plusieurs DOM) le temps que le js se charge en asynchrone.

Florian_R a écrit :

Je ne vois vraiment pas l’intérêt de parser tous le DOM (this.find('[data-jquery-type]:not(.jquery_pluginautoload)').each), pourrir le markup de paramètres pour le JS et se priver de callbacks quand un basique loadScript, quelques data-attributes si nécessaire pour s'apporter de la souplesse et une méthode pour lancer son appli avec un seul js (voir DOM-ready execution) font largement mieux le boulot en conservant la séparation des couches.

Je vais analyser plus en détail ta remarque.

Merci !
Modifié par marcbuils (24 Oct 2012 - 14:16)
Aucune agressivité de ma part, désolé si le ton est un peu sec, j'ai tendance à ne pas trop mettre les formes quand je me retrouve à rédiger des pavés.

Je n'ai rien contre le fait que le HTML soit descriptif via quelques data-attributes, c'est comme tu le disais comme ça que fonctionne jQuery Mobile ou X-Tag, et plus clean que la méthode à l'ancienne à base de classe.

Pour autant, même avec du HTML déclaratif, ces libs ne font pas du lazyload à la volée comme tu le pratiques (ou alors j'ai raté un truc sur jQuery Mobile).

Et quitte à persister, se retrouver avec tous les params dans le HTML, et les transformer en JSON, désolé, mais je trouve ça sale et je qualifie ça d'anti-pratique (ça ne reste que mon avis).

J'attends de voir s'il y a d'autres réactions que la mienne pour intervenir du coup.
Ok, pas de problème Smiley cligne
En tout cas je te remercie pour tes remarques, en particulier pour la fonction loadScript qui permet de facilité grandement le debug Smiley cligne