<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapitre SYSTEM "../ressources/chapitre22.dtd">

<chapitre typecourssiteweb="dhtml">
	<cours nomfichier="pluginsjquery">Cours de manipulation du DOM et DHTML</cours>
	<entete>
		<titre>Initiation à la création de plugins jQuery</titre>
		<auteur email="Gilles.Chagnon@upmc.fr">G. Chagnon</auteur>
		<resume>Ce chapitre présente un gabarit de construction d'un plugin jQuery</resume>
		<motsclefs>jquery</motsclefs>
	</entete>
	<corpus>
		<partie titre="Introduction" ancre="intro">
			<section titre="Principe des plugins" ancre="pcp">
				<paragraphe>
					<texte>jQuery est une bibliothèque facilitant la création de code <code type="langage">JavaScript</code> portable, et facile à lire. Mais son intérêt ne se limite pas à cela&#160;: ses concepteurs ont élaboré un mécanisme permettant de compléter la bibliothèque. Il existe un répertoire «&#160;,officiel&#160;» des plugins, mais de nombreux autres peuvent être trouvés sur le Web.</texte>
					<texte></texte>
				</paragraphe>
			</section>
		</partie>
		<partie titre="Construction pas à pas d'un plugin" ancre="constr">
			<section titre="Introduction" ancre="constrintro">
				<paragraphe>
					<texte>Une présentation plus complète, en anglais, peut être trouvée sur le site officiel sur une page intitulée <reference href="http://docs.jquery.com/Plugins/Authoring" lang="en">Plugins/Authoring</reference>, qui détaille la manière «&#160;canonique&#160;» de conception d'un plugin, qui se retrouve dans la plupart de ceux qui existent. Nous ne passerons pas en revue dans ce cours d'introduction tout ce qui y est exposé, mais seulement le début en nous arrêtant au paramétrage du plugin, en construisant un plugin élémentaire pas à pas.</texte>
				</paragraphe>
			</section>
			<section titre="Pour bien commencer" ancre="plugdeb">
				<paragraphe titre="Structure de base" ancre="bs">
					<texte>On crée un plugin en étendant la fonction <code>$</code>. Pour cela, on écrit...</texte>
					<exemplejavascript>
						<autres>(</autres><instruction name="function"/><autres>( $ )</autres><sautligne/>
						<bloc avec_retour="faux">
							<autres niveau="1">$.fn.monPlugin = </autres><instruction name="function"/><autres>()</autres>
							<bloc niveau="1" avec_retour="faux">
								<commentaire_js niveau="2">Code du plugin</commentaire_js>
							</bloc><finligne/>
						</bloc><autres>)(jQuery)</autres><finligne/>
					</exemplejavascript>
				</paragraphe>
				<paragraphe titre="Utilisation de this" ancre="this">
					<texte>D'habitude avec <code>jQuery</code>, pour faire référence à l'objet jQuery courant on utilise <code>$(this)</code> (<code>this</code> renvoie en effet d'habitude l'objet du DOM). Cependant, le fait que le code du plugin sera appliqué à un objet jQuery fait qu'il n'est pas nécessaire de prendre cette précaution, et on peut écrire directement <code>this</code>.</texte>
				</paragraphe>
			</section>
			<section titre="Les bases" ancre="plugbs">
				<paragraphe>
					<texte>Il suffit ensuite d'écrire le code du plugin. Analysons par exemple ceci&#160;:</texte>
					<exemplejavascript>
						<autres>(</autres><instruction name="function"/><autres>( $ )</autres><sautligne/>
						<bloc avec_retour="faux">
							<autres niveau="1">$.fn.metEnGras = </autres><instruction name="function"/><autres>(e)</autres>
							<bloc niveau="1" avec_retour="faux">
								<instruction name="this" niveau="2"/><autres>.</autres><fonction name="html"><autres>"&lt;b&gt;"+$(this).text()+"&lt;/b&gt;"</autres></fonction><finligne/>
								<sautligne/>
								<variable name="e" niveau="2"/><autres>.</autres><fonction name="stopPropagation"></fonction><finligne/>
							</bloc><finligne/>
						</bloc><autres>)(jQuery)</autres><finligne/>
					</exemplejavascript>
					<texte>Ce code remplace le contenu de l'élément auquel le plugin est appliqué. Il prend un paramètre <code>e</code>, qui sera en fait un objet de type événement jQuery. On en a besoin afin d'arrêter sa propagation vers le haut du DOM et ainsi éviter que, de proche en proche, les remplacements de code HTML ne finissent par remplacer l'élément <code>body</code> lui-même. Après l'avoir chargé, on l'applique dans le fichier HTML à un objet jQuery&#160;:</texte>
					<exemplejavascript>
						<fonction name="$"><autres>document</autres></fonction><autres>.</autres><fonction name="ready"><autres>hop</autres></fonction><finligne/>
						<sautligne/>
						<instruction name="function"/><fonction name=" hop"></fonction>
						<bloc niveau="1">
							<fonction name="$" niveau="2"><autres>"p,i"</autres></fonction><autres>.</autres><fonction name="click"><autres>testP</autres></fonction><finligne/>
						</bloc>
						<sautligne/>
						<instruction name="function"/><fonction name=" testP"><autres>evt</autres></fonction>
						<bloc niveau="1">
							<fonction name="$" niveau="2"><autres>this</autres></fonction><autres>.</autres><fonction name="metEnGras"><autres>evt</autres></fonction><finligne/>
						</bloc>
					</exemplejavascript>
					<texte>Ainsi qu'on peut le constater, le plugin s'applique comme n'importe quelle fonction <code type="langage">jQuery</code>, directement à un objet <code type="langage">jQuery</code> renvoyé par la fonction <code>$</code>. Pour un test grandeur nature, vous pouvez consulter cet <reference href="exemples/exemple_plugin_jquery1.html">exemple HTML de mise en œuvre du plugin</reference>, ainsi que ce <reference href="exemples/plugin_jquery1.js">premier plugin lui-même</reference>.</texte>
				</paragraphe>
			</section>
			<section titre="Permettre l'utilisation du plugin dans une chaîne de commandes jQuery" ancre="chaine">
				<paragraphe>
					<texte>Un des atouts de <code type="langage">jQuery</code> est la possibilité de constituer une chaîne de commandes, par exemple <code>$("p").addClass("rouge").slideToggle()</code> afin de pouvoir les appliquer successivement à un objet jQuery. À cet effet, chaque fonction retourne elle-même un objet jQuery (un peu comme si on écrivait une suite de commandes Unix en ligne, séparées par plusieurs caractères <code>|</code>). Afin de préserver cette capacité, il faut faire en sorte que le plugin que l'on crée retourne un objet jQuery. Or un objet jQuery est créé de la même manière que nous l'avons fait précédemment. Notre plugin doit donc retourner une fonction. De plus, comme a priori il peut s'insérer dans une chaîne traitant une collection de nœuds, il faut s'assurer que la fonction est retournée pour chacun des nœuds de la collection. On obtient donc&#160;:</texte>
					<exemplejavascript>
						<autres>(</autres><instruction name="function"/><autres>( $ )</autres><sautligne/>
						<bloc avec_retour="faux">
							<autres niveau="1">$.fn.metEnGras = </autres><instruction name="function"/><autres>(e)</autres>
							<bloc niveau="1" avec_retour="faux">
								<instruction name="return this" niveau="2"/><autres>.</autres><fonction name="each"><autres>function(</autres></fonction>
								<bloc niveau="2" avec_retour="faux">
									<instruction name="this" niveau="3"/><autres>.</autres><fonction name="html"><autres>"&lt;b&gt;"+$(this).text()+"&lt;/b&gt;"</autres></fonction><finligne/>
									<sautligne/>
									<variable name="e" niveau="3"/><autres>.</autres><fonction name="stopPropagation"></fonction><finligne/>
								</bloc><autres>)</autres><sautligne/>
							</bloc><finligne/>
						</bloc><autres>)(jQuery)</autres><finligne/>
					</exemplejavascript>
					<texte>On peut alors tester la <reference href="exemples/test_chaine.html">chaîne sur ce fichier HTML</reference>, avec le <reference href="exemples/testpg_chaine.js">plugin associé</reference>.</texte>
				</paragraphe>
			</section>
			<section titre="Passer des options: le paramétrage et les options par défaut" ancre="options">
				<paragraphe>
					<texte>La plupart du temps, le fonctionnement d'un plugin peut être personnalisé à l'aide de paramètres. Il est souvent utile de préciser un lot d'options pour le plugin, avec des valeurs définies par défaut. Ces options sont spécifiées dans un littéral objet qui va «&#160;étendre&#160;x le jeu d'options par défaut&#160;:</texte>
					<exemplejavascript>
						<autres>(</autres><instruction name="function"/><autres>( $ )</autres><sautligne/>
						<bloc avec_retour="faux">
							<autres niveau="1">$.fn.metEnGras = </autres><instruction name="function"/><autres>(e, options)</autres>
							<sautligne/>
							<instruction name="var " niveau="1"/><autres>settings = $.extend(</autres>
							<bloc niveau="2" avec_retour="faux">
								<autres niveau="3">balise:"b",</autres><sautligne/>
								<autres niveau="3">classe:""</autres><sautligne/>
							</bloc><autres>, options)</autres><finligne/>
							<sautligne/>
							<bloc niveau="1" avec_retour="faux">
								<instruction name="return this" niveau="2"/><autres>.</autres><fonction name="each"><autres>function(</autres></fonction>
								<bloc niveau="2" avec_retour="faux">
									<instruction name="this" niveau="3"/><autres>.</autres><fonction name="html"><autres>"&lt;"+settings.balise+"&gt;"+$(this).text()+"&lt;/"+settings.balise+"&gt;"</autres></fonction><finligne/>
									<sautligne/>
									<instruction name="if" niveau="3"/><autres> (settings.classe!="") $(this).</autres><fonction name="addClass"><autres>settings.classe</autres></fonction><finligne/>
									<sautligne/>
									<variable name="e" niveau="3"/><autres>.</autres><fonction name="stopPropagation"></fonction><finligne/>
								</bloc><autres>)</autres><sautligne/>
							</bloc><finligne/>
						</bloc><autres>)(jQuery)</autres><finligne/>
					</exemplejavascript>
					<texte>On peut alors tout à fait insérer l'appel au plugin dans une chaîne, <valeur>et</valeur> lui passer des options sous la forme d'un objet littéral&#160;: <code>$(this).metEnGras(evt,{balise:"strong",classe:"souligne"}).addClass("rouge");</code>. Les options sont facultatives. Si on écrit <code>$(this).metEnGras(evt,{balise:"strong"}).addClass("rouge");</code>, au lieu d'insérer une balise <code><![CDATA[<b>]]></code>, le plugin insérera <code><![CDATA[<strong>]]></code>.</texte>
				</paragraphe>
			</section>
			<exercice titre="Création d'un plugin" ancre="exocrea">
				<enonce href="exercices/exo45.html"/>
				<correction href="exercices/exo45base.html" description="Correction du code jQuery de départ"/>
				<correction href="exercices/exo45cor_1.js" description="Plugin de base"/>
				<correction href="exercices/exo45cor_1.html" description="Page HTML appelant le plugin de base"/>
				<correction href="exercices/exo45cor_2.js" description="Plugin pouvant s'insérer dans une chaîne"/>
				<correction href="exercices/exo45cor_2.html" description="Page HTML appelant le plugin s'insérant dans une chaîne"/>
				<correction href="exercices/exo45cor_3.js" description="Plugin avec options"/>
				<correction href="exercices/exo45cor_3.html" description="Page HTML appelant le plugin avec options"/>
			</exercice>
		</partie>
	</corpus>
</chapitre>
