I. Prérequis▲
Cet article est basé sur l'acquis après la lecture de l'article : « Adapter jQuery à vos besoins » et de ses prérequis.
De plus, le lecteur doit avoir une bonne maîtrise du JavaScript et de la bibliothèque jQuery, car il ne trouvera aucune aide sur les techniques réputées acquises dans cet article.
II. Introduction▲
On peut trouver sur le Web de nombreuses méthodes pour écrire un plugin multitâche.
Le guide officiel résume l'essentiel des bonnes pratiques, mais il ne s'agit que d'un point de départ. Il promeut l'usine de construction de widget UI, mais plusieurs auteurs trouvent cette méthode lourde et contraignante.
Plusieurs méthodes de construction utilisent une technique particulière pour résoudre un aspect particulier. Certains auteurs préfèrent mettre l'accent sur l'écriture de modules, sur l'utilisation de prototypes, sur l'utilisation des événements, etc.
Il n'existe pas un modèle idéal applicable en toutes circonstances et la méthode utilisée peut avoir une grande influence sur les performances, sur la lisibilité et sur la maintenabilité du code de votre plugin.
Addy Osmani a recensé et étudié les approches principales, j'ai résumé ci-dessous les principales qualités recherchées par les auteurs de méthodes de plugin.
- S'intégrer dans un espace de noms ou permettre l'usage d'un espace de noms ;
- Cacher la « plomberie » et « automatiser » les tâches répétitives ;
- Placer la logique du plugin dans un objet séparé du « système de construction » du plugin pour améliorer la lisibilité et la maintenabilité ;
- Permettre la gestion de propriétés, d'objets, et de méthodes publiques et privées ;
- Offrir une méthode versatile pour l'initialisation de l'instance (un objet jQuery) ;
- Empêcher l'initialisation multiple ;
- Offrir une méthode pour la destruction de l'instance ;
- Sauvegarder l'état (les options) de l'instance ;
- Être capable de gérer et de déclencher des événements, ce qui permet une utilisation asynchrone par un système de souscription et de publication d'événements ;
- Permettre la définition et la modification des options par défaut ;
- Permettre la définition d'options par l'intermédiaire d'un attribut data HTML5. Ce qui permet l'initialisation d'une collection d'instances avec les options par défaut, suivi d'une personnalisation par instance.
La méthode que j'ai mise au point respecte ce cahier des charges.
- elle a résisté à toutes les épreuves que je lui ai fait subir pendant plus de trois mois ;
- elle me convient bien.
Certes, le dernier argument n'est pas rationnel, mais à mes yeux c'est le principal et il est incontestable ! ;)
J'ai bien entendu des choses à reprocher aux autres méthodes, mais en dehors du fait que la plupart ne satisfont pas à mon cahier des charges, les autres arguments sont essentiellement subjectifs.
Pour tester les codes, veuillez charger le ZIP.
III. La méthode de construction▲
Le plugin multitâche appelle une fonction « universelle » qui gère l'appel aux méthodes d'un objet, que j'appelle simplement un objet méthodes, c'est lui qui contient l'intégralité du « savoir-faire » du plugin.
Par fonction « universelle », il faut comprendre que c'est la même fonction qui gère tous les dvjhPlugins.
Rappel : les fenêtres de code s'ouvrent en cliquant sur le bouton placé à droite.
III-A. La structure d'un plugin▲
Dans l'espace de nom dvjh (Adapter jQuery à vos besoins) on écrira :
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.
var dvjh = (
function(
$ ){
// objet méthodes du plugin A
var dvjhPluginAMethods =
{
};
// objet méthodes du plugin B
var dvjhPluginBMethods =
{
};
/*
* Ajouts de méthodes (plugin) au prototype de l'objet jQuery ($.fn).
*
* Pour créer un dvjhPlugin il suffit de lui donner
* un nom et d'appeler la fonction dvjhPluginCreate dans le
* contexte du plugin.
* Les paramètres sont le nom de son objet méthodes et les
* arguments de l'utilisateur.
*/
$.extend
(
$.
fn,
{
"dvjhPluginA"
:
function(
){
return dvjhPluginCreate.call
(
this,
dvjhPluginAMethods,
arguments );
},
"dvjhPluginB"
:
function(
){
return dvjhPluginCreate.call
(
this,
dvjhPluginBMethods,
arguments );
}
}
);
return {
"$"
:
$
};
}
)(
jQuery.sub
(
) );
III-B. La fonction dvjhPluginCreate▲
Cette fonction gère l'initialisation du plugin (avec ou sans options utilisateur, avec ou sans paramètres supplémentaires) et l'appel des méthodes du plugin (avec ou sans paramètres).
Si vous n'êtes pas un expert, je vous recommande de n'apporter aucune modification à cette méthode.
Toutes les instances du plugin sont traitées par un unique objet méthodes, chaque instance (jObj : un objet jQuery) doit par conséquent stocker une copie de son état (les options) dans jObj.data( objMethods._copyright.objMethodsName ).
Cet état est transmis à l'objet méthodes au début de l'action. Il est alors stocké temporairement dans l'objet options de l'objet méthodes. Lorsque l'action est terminée, l'état est sauvegardé dans l'instance et l'objet méthodes n'en conserve plus nulle trace.
Lors de l'initialisation, l'état de l'instance est constitué d'une copie des options par défaut et des options et paramètres transmis par l'utilisateur du plugin à la fonction d'initialisation de l'objet méthodes.
Chaque instance doit travailler sur sa copie des arguments (objMethods, method, params).
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
/*
* Fonction "universelle" pour l'initialisation et l'appel des
* méthodes d'un plugin multitâche.
*
* Ne pas copier-coller ni modifier sans nécessité.
*/
var dvjhPluginCreate =
function(
objMethods,
params ){
var args =
Array.
prototype.
slice.call
(
params ),
method =
args.shift
(
);
// console.log( "dvjhPluginCreate, arguments : ", objMethods, method, args );
if (
!
objMethods ){
$.error
(
"dvjhPluginCreate : objMethods n'est pas défini !"
);
}
if (
typeof method ===
"string"
&&
method.slice
(
0
,
1
) ===
"_"
){
$.error
(
"dvjhPluginCreate : les propriétés, les méthodes "
+
"et les objets précédés d'un tiret bas (underscore) sont privés !"
);
}
var boolOK,
boolInit,
boolDestroy,
objOpts,
jObj,
cMethod,
cParams,
name
=
objMethods.
_copyright.
objMethodsName;
/*
* Attention ! Ici, this c'est l'objet jQuery !
*
* La valeur de this est particulière, elle
* correspond au sélecteur qui a créé le plugin.
* On ne doit donc jamais écrire $( this ) car
* cette écriture crée un $( $( selecteur ) ) inutile !
*
* Objet et array : attention chaque instance ($( item ),
* un objet jQuery) doit travailler sur sa copie.
*
* Les options de l'instance sont stockées dans l'instance
* (par data( name )). À l'initialisation, il s'agit d'une
* copie des options par défaut.
*/
return this.each
(
function(
i,
item ){
boolOK =
true;
boolInit =
false;
boolDestroy =
false;
objOpts =
$(
item ).data
(
name
) ||
null;
jObj =
$(
item );
if (
objOpts ==
null ){
boolInit =
true;
jObj.data
(
name
,
$.extend
(
true,
{},
objMethods.
_options ) );
objOpts =
jObj.data
(
name
);
}
if (
method ){
if (
$.isPlainObject
(
method ) ){
cMethod =
$.extend
(
true,
{},
method );
}
else if (
$.isArray
(
method ) ){
cMethod =
method.concat
(
);
}
else {
cMethod =
method;
}
}
cParams =
args.concat
(
);
objMethods.
options =
objOpts;
// important !
objMethods.
jObj =
$(
item );
// important !
// debug
/*
console.log( "dvjhPluginCreate, boolOK : ", boolOK );
console.log( "dvjhPluginCreate, boolInit : ", boolInit );
console.log( "dvjhPluginCreate, jObj : ", jObj );
console.log( "dvjhPluginCreate, objOpts : ", objOpts );
console.log( "dvjhPluginCreate, objMethods.options : ",
objMethods.options );
console.log( "dvjhPluginCreate, cMethod, typeof cMethod : ",
cMethod, typeof cMethod );
console.log( "dvjhPluginCreate, cParams, $.isArray( cParams ) : ",
cParams, $.isArray( cParams ) );
*/
if (
boolInit ){
if (
cMethod ===
"init"
){
objMethods[
cMethod ](
cParams );
}
else if (
$.isPlainObject
(
cMethod ) ||
!
cMethod ){
objMethods.init
(
cMethod,
cParams );
}
else {
/*
* cMethod peut contenir un paramètre de n'importe
* quel type sauf un objet. Car si le premier argument
* est un objet il doit contenir les options de
* l'utilisateur.
*
* On peut passer un autre objet si l'on passe un objet
* anonyme vide comme premier argument, exemple :
* jObj.dvjhPlugin( {}, new Date() );
*
* On doit construire un nouvel array regroupant le
* contenu de cMethod et de l'array cParams.
*/
var tab;
if (
typeof cMethod ===
"string"
||
typeof cMethod ===
"number"
){
tab =
[
cMethod ];
}
else {
tab =
$.map
(
cMethod,
function(
value,
key ){
return value;
}
);
}
objMethods.init
(
{},
$.merge
(
tab,
cParams ) );
}
}
else {
if (
cMethod !=
"init"
&&
cMethod in objMethods ){
if (
cMethod ===
"destroy"
){
boolDestroy =
true;
}
objMethods[
cMethod ](
cParams );
}
else {
boolOK =
false;
}
}
jObj.data
(
name
,
objMethods.
options );
objMethods.
options =
{};
// important !
objMethods.
jObj =
null;
// important !
objOpts =
cMethod =
cParams =
null;
if (
boolDestroy ){
jObj.removeData
(
name
);
}
if (
!
boolOK ){
$.error
(
"dvjhPluginCreate : la méthode "
+
method +
" n'existe pas ou cet élément du DOM "
+
"a déjà été initialisé !"
);
}
}
);
};
III-C. Squelette d'un objet méthodes▲
Les propriétés, les méthodes et les objets précédés d'un tiret bas sont privés !
- les objets privés : _copyright et _options ;
- les objets publics : jObj et options ;
- les méthodes publiques : init, destroy, setOption et getOption.
- un accès, en lecture, à la propriété _copyright.objMethodsName ;
- une fonction gérant la modification des options par défaut (_options).
Pour simplifier l'écriture d'un objet méthodes, j'ai construit un « squelette », que j'ai dénommé dvjhSqueletteMethods. Il permet de construire l'ébauche d'un nouvel objet méthodes par copier-coller sans oublier aucun des objets et des méthodes qu'il doit impérativement contenir.
À l'usage, vous trouverez sans doute les commentaires dans dvjhSqueletteMethods surabondants et gênants, mais je vous conseille vivement de les conserver en production au bénéfice de la personne qui modifiera vos plugins.
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
var dvjh = (
function(
$ ){
/*
* dvjhSqueletteMethods est le squelette d'un objet méthodes.
*
* Il contient les méthodes minimales pour la création d'un
* plugin multitâche.
*
* Ne pas modifier le squelette sans nécessité.
*
* On copie-collera le code de cet objet pour créer
* son propre objet méthode.
*
* Attention ! $.extend( obj1, obj2 ) modifie
* le code de l'obj1.
*
* var obj3 = $.extend( true, {}, obj1, obj2 );
*
* Ce code crée un nouvel obj3 sans altérer le
* code de obj1 et de obj2. Mais ici l'utilisation de
* $.extend n'apporte rien puisque l'on doit personnaliser
* la quasi-totalité du code du squelette.
*/
var dvjhSqueletteMethods =
{
"_copyright"
:
{
// informations sur le plugin
/*
* La propriété objMethodsName est importante.
* Sa valeur doit être unique, elle est
* utilisée par dvjhPluginCreate et l'objet
* méthodes, elle ne doit jamais être modifiée
* après la mise en production du dvjhPlugin.
*/
"objMethodsName"
:
"dvjhSqueletteMethods"
,
"auteur"
:
"Daniel Hagnoul"
,
"version"
:
"1.0.0"
,
"date"
:
"2012-01-13T02:15:29.000+01:00"
,
"licence"
:
"libre de tous droits"
},
"_options"
:
{
// les options par défaut
/*
* L'option boolDebug doit toujours exister !
*
* N'oubliez pas de la mettre à false dans la
* version de production de votre plugin.
*/
"boolDebug"
:
true,
"class"
:
"dvjhClass"
},
/*
* Lors du traitement d'une instance (un objet
* jQuery), "jObj" contiendra l'objet jQuery
* et l'objet options contiendra les options de
* cette instance.
*
* C'est la fonction dvjhPluginCreate qui est
* responsable de la gestion de "jObj" et de
* "options".
*/
"jObj"
:
null,
// l'instance
"options"
:
{},
// les options de l'instance
"init"
:
function(
){
// initialisation du plugin
/*
* Ne modifiez pas le traitement des arguments
* sans nécessité !
*/
var args =
Array.
prototype.
slice.call
(
arguments ),
param1 =
args.shift
(
),
param2 =
args.shift
(
);
/*
* Traitement d'un éventuel objet anonyme contenant
* les options de l'utilisateur.
*
* Ne modifiez pas ce code sans nécessité !
*/
if (
$.isPlainObject
(
param1 ) &&
!
$.isEmptyObject
(
param1 ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
param1 ) );
}
$.extend
(
this.
options,
param1 );
}
/*
* Traitement dans this.jObj d'un éventuel attribut
* data HTML5, data-plugin-options, contenant
* les options de l'utilisateur.
*
* Ne modifiez pas ce code sans nécessité !
*/
var dataOptions =
this.
jObj.data
(
"pluginOptions"
);
if (
$.isPlainObject
(
dataOptions ) &&
!
$.isEmptyObject
(
dataOptions ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
dataOptions ) );
}
$.extend
(
this.
options,
dataOptions );
}
/*
* Si votre fonction d'initialisation nécessite des
* arguments, il faut les chercher dans param1 ou
* dans param2.
*
* La méthode init peut recevoir de 0 à 2 arguments.
*
* S'il y a deux arguments, le premier doit être
* un objet contenant les options de l'utilisateur,
* le second argument est alors un array contenant les
* éventuels paramètres supplémentaires.
*
* S'il n'y a qu'un argument, ce peut être soit un
* objet anonyme contenant les options soit un array
* contenant les éventuels paramètres.
*/
var mesArguments =
[];
if (
$.isArray
(
param1 ) ){
mesArguments =
param1.concat
(
);
}
else if (
$.isArray
(
param2 ) ){
mesArguments =
param2.concat
(
);
}
if (
this.
options.
boolDebug ){
console.log
(
"init, this.jObj : "
,
this.
jObj );
console.log
(
"init, mesArguments : "
,
mesArguments.concat
(
) );
}
/*
* Votre code pour traiter this.jObj.
*
* Exemple :
*/
this._setClass
(
this.
options.
class );
},
"destroy"
:
function(
params ){
// 1. Supprimer les gestionnaires d'événements.
// Exemple :
// this.options.jObjTexte.off( "click mouseenter mouseleave" );
// 2. Supprimer les composants UI.
// Exemple :
// this.options.jObjTexte.remove();
// 3. Rendre null les objets (y compris array)
// Exemple :
// this.options.jObjTexte = null;
},
"exemple"
:
function(
params ){
/*
* params est un array.
*
* À l'exception d'init, toutes vos méthodes
* publiques doivent avoir cette signature.
*
* Vous devez extraire vos paramètres de
* l'array params.
*
* var monParam = params.shift();
*
* N'oubliez pas de contrôler la validité
* des paramètres extraits.
*/
},
"setOption"
:
function(
params ){
/*
* Ne modifiez pas le traitement des arguments
* sans nécessité !
*/
var option
=
params.shift
(
),
value =
params.shift
(
);
if (
!
option
||
!
value ){
$.error
(
"Les paramètres ne sont pas conformes : ( "
+
option
+
", "
+
value +
" )."
);
}
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
this._setBoolDebug
(
value );
break;
case "class"
:
this._setClass
(
value );
break;
default:
$.error
(
"Cette option existe mais elle n'est pas publique !"
);
};
}
else {
$.error
(
"Cette option n'existe pas !"
);
}
},
"_setBoolDebug"
:
function(
value ){
if (
typeof value ===
"boolean"
){
this.
options.
boolDebug =
value;
}
},
"_setClass"
:
function(
value ){
if (
typeof value ===
'string'
){
if (
this.
jObj.hasClass
(
this.
options.
class ) ){
this.
jObj.removeClass
(
this.
options.
class );
}
this.
options.
class =
value;
this.
jObj.addClass
(
value );
}
},
"getOption"
:
function(
params ){
/*
* Ne modifiez pas le traitement des arguments
* sans nécessité !
*/
var option
=
params.shift
(
),
callback =
params.shift
(
) ||
function(
){},
name
=
"getOption."
+
this.
_copyright.
objMethodsName;
if (
!
option
){
$.error
(
"getOption : le paramètre n'est pas conforme : ( "
+
option
+
" )."
);
}
/*
* Objet et array : attention de toujours transmettre une copie !
*/
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
var value =
this.
options.
boolDebug;
this.
jObj.data
(
name
,
value );
callback
(
option
,
value );
break;
case "class"
:
var value =
this.
options.
class;
this.
jObj.data
(
name
,
value );
callback
(
option
,
value );
break;
default:
$.error
(
"getOption : cette option existe mais elle n'est pas publique !"
);
};
}
else {
$.error
(
"getOption : cette option n'existe pas !"
);
}
}
};
/*
* Pour créer un plugin multitâche il vous suffit de
* copier-coller et de personnaliser ce code en changeant
* le nom du plugin et de son objet méthodes.
*
* La méthode peut recevoir de 0 à n arguments.
*
* L'objet contenant les options de l'utilisateur doit
* toujours être passé dans le premier argument.
*
* Si le premier argument est un objet, il doit
* contenir les options de l'utilisateur.
*
* Le String contenant le nom d'une méthode doit
* toujours être passé dans le premier argument.
*
* Si le premier argument est un String, il doit
* contenir le nom d'une méthode.
*
* Avec 0 argument, le premier argument
* contenant un objet ou le string "init", la
* fonction dvjhPluginCreate provoquera
* l'initialisation du dvjhPlugin ou une erreur
* si l'initialisation a déjà eu lieu.
*
* Ci-dessous, n'oubliez pas de remplacer
* dvjhSqueletteMethods par le nom de votre
* objet méthodes.
*
* Ajouts de méthodes (plugin) au prototype de l'objet jQuery ($.fn).
*/
$.extend
(
$.
fn,
{
"dvjhSquelette"
:
function(
){
return dvjhPluginCreate.call
(
this,
dvjhSqueletteMethods,
arguments );
}
}
);
return {
"$"
:
$,
"squeletteObjMethodsName"
:
dvjhSqueletteMethods.
_copyright.
objMethodsName,
"squeletteObjMethodsDefaultOptions"
:
function(
objOptions ){
/*
* Modifications des options par défaut.
*
* Ne modifiez pas ce code sans nécessité !
*/
if (
$.isPlainObject
(
objOptions ) &&
!
$.isEmptyObject
(
objOptions ) ){
$.extend
(
dvjhSqueletteMethods.
_options,
objOptions );
}
}
};
}
)(
jQuery.sub
(
) )
Rappel : pour tester les codes, veuillez charger le ZIP.
Examinons le code jQuery du fichier dvjhSquelette.html :
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
$(
function(
){
try {
/*
* Construction d'un objet jQuery : jObj.
* Il peut être exploité comme un array d'objet jQuery, un pour chaque
* division dont l'ID commence par "divTest".
*
* N'oubliez pas que seule la version de jQuery accessible
* par dvjh.S a accès au dvjhPlugin.
*/
var jObj =
dvjh.
$(
"[id^='divTest']"
);
// Il est possible de modifier ou d'ajouter des options par défaut.
dvjh.squeletteObjMethodsDefaultOptions
({
"moi"
:
"Prénom Nom"
}
);
// Initialisation du dvjhSquelette avec modification de l'option "moi".
jObj.dvjhSquelette
({
"moi"
:
"Daniel Hagnoul"
}
);
/*
* On peut initialiser un dvjhPlugin de plusieurs
* manières différentes en fonction des besoins
* du plugin.
*
* jObj.dvjhSquelette();
* jObj.dvjhSquelette({ "key" : "value" });
* jObj.dvjhSquelette({ "key" : "value" }, "hello everybody !" );
*
* Si le premier argument est un objet, il doit
* contenir les options ou être vide.
* jObj.dvjhSquelette({ }, new Date() );
*
* jObj.dvjhSquelette( "init", "hello everybody !" );
*
* La double initialisation provoque une erreur
* Exemple : jObj.eq( 2 ).dvjhSquelette();
*/
/*
* Nota bene : pour les besoins du débogage on peut
* facilement consulter les options appliquées à une
* instance (un objet jQuery).
* Pour des raisons évidentes de sécurité (le respect
* des données) vous devez toujours manipuler une
* copie d'un objet (object et array).
*/
jObj.each
(
function(
i,
item ){
console.log
(
"options : "
,
i,
item,
$.extend
(
true,
{},
$(
item ).data
(
dvjh.
squeletteObjMethodsName ) ) );
}
);
/*
* Vous remarquerez certainement que le troisième
* objet jQuery n'a pas la "class" par défaut !
* En effet, au lieu d'être rouge (dvjhClass) il est orange !
* C'est le résultat de la modification des options d'une
* instance par l'intermédiaire d'un attribut data HTML5.
*/
/*
* Modification de l'option "class" du deuxième
* objet jQuery en utilisant "setOption"
*/
jObj.eq
(
1
).dvjhSquelette
(
"setOption"
,
"class"
,
"helloClass"
);
/*
* Consultation de la valeur de l'option "class" avec "getOption".
*
* Dans la majorité des cas, on manipulera cette valeur dans
* une fonction de rappel. Mais cette valeur est également
* disponible par jObj.data( "getOption." + dvjh.squeletteObjMethodsName ).
*
* Avec une fonction de rappel (callback) :
*/
jObj.dvjhSquelette
(
"getOption"
,
"class"
,
function(
option
,
value ){
console.log
(
"getOption, option = "
,
option
,
", value = "
,
value );
}
);
// Avec jObj.data( "getOption." + dvjh.squeletteObjMethodsName ).
jObj.each
(
function(
i,
item ){
console.log
(
"class : "
,
i,
item,
$(
item ).data
(
"getOption."
+
dvjh.
squeletteObjMethodsName ) );
}
);
}
catch(
e){
alert
(
"dvjhSquelette, "
+
e.
message );
}
}
);
Le code d'utilisation d'un dvjhPlugin doit toujours se trouver dans un bloc « try catch », c'est l'ultime rempart avant le crash global.
Ne surchargez pas inutilement l'objet _options (les options par défaut) ! Je n'ai rencontré aucun problème de performance avec le stockage des options dans l'instance lors de mes tests, mais pour des données encombrantes et communes à toutes les instances, il est important de se souvenir que dans le code de l'objet méthodes vous avez accès au contenu de la clôture jQuery.
IV. Les exemples▲
Commençons par un exemple simple. Un plugin multitâche qui gère la modification de ses options.
IV-A. Le plugin dvjhTourne▲
Dans le tutoriel « Adapter jQuery à vos besoins », le plugin tourne est un bon candidat car pour gérer les modifications de son option « degrees » il avait besoin de deux autres plugins : tourneSetOptions et tourneGetOptions. De plus, toutes les instances du plugin tourne utilisaient la même option.
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
var dvjh = (
function(
$ ){
/*
* L'objet méthodes ci-dessous reprend le code des plugins tourne,
* tourneSetOptions, tourneGetOptions et celui de l'objet privé
* _objTourne publié dans le tutoriel "Adapter jQuery à vos besoins".
*/
var dvjhTourneMethods =
{
"_copyright"
:
{
// informations sur le plugin
"objMethodsName"
:
"dvjhTourneMethods"
,
"auteur"
:
"Daniel Hagnoul"
,
"version"
:
"1.0.0"
,
"date"
:
"2012-01-17T15:53:15.000+01:00"
,
"licence"
:
"libre de tous droits"
},
"_options"
:
{
// les options par défaut
"boolDebug"
:
false,
"boolInfos"
:
true,
"degrees"
:
0
},
"jObj"
:
null,
// l'instance (objet jQuery)
"options"
:
{},
// les options de l'instance
"init"
:
function(
){
// initialisation du plugin
var args =
Array.
prototype.
slice.call
(
arguments ),
param1 =
args.shift
(
),
param2 =
args.shift
(
);
/*
* Traitement d'un éventuel objet anonyme contenant
* les options de l'utilisateur.
*
* Ne modifiez pas ce code sans nécessité !
*/
if (
$.isPlainObject
(
param1 ) &&
!
$.isEmptyObject
(
param1 ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
param1 ) );
}
$.extend
(
this.
options,
param1 );
}
/*
* Traitement dans this.jObj d'un éventuel attribut
* data HTML5, data-plugin-options, contenant
* les options de l'utilisateur.
*
* Ne modifiez pas ce code sans nécessité !
*/
var dataOptions =
this.
jObj.data
(
"pluginOptions"
);
if (
$.isPlainObject
(
dataOptions ) &&
!
$.isEmptyObject
(
dataOptions ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
dataOptions ) );
}
$.extend
(
this.
options,
dataOptions );
}
/*
* Si votre fonction d'initialisation nécessite des
* arguments, il faut les chercher dans param1 ou
* dans param2.
*
* La méthode init peut recevoir de 0 à 2 arguments.
*
* S'il y a deux arguments, le premier doit être
* un objet contenant les options de l'utilisateur,
* le second argument est alors un array contenant les
* éventuels paramètres supplémentaires.
*
* S'il n'y a qu'un argument, ce peut être soit un
* objet anonyme contenant les options soit un array
* contenant les éventuels paramètres.
*/
var mesArguments =
[];
if (
$.isArray
(
param1 ) ){
mesArguments =
param1.concat
(
);
}
else if (
$.isArray
(
param2 ) ){
mesArguments =
param2.concat
(
);
}
if (
this.
options.
boolDebug ){
console.log
(
"init, this.jObj : "
,
this.
jObj );
console.log
(
"init, mesArguments : "
,
mesArguments.concat
(
) );
}
/*
* Votre code pour traiter this.jObj.
*/
if (
this.
options.
boolInfos ){
this.
jObj.on
(
"optionsChanged.dvjhTourne"
,
function(
event
){
var obj =
event
.
dvjh,
el =
obj.
initiateur[
0
];
console.log
(
new Date(
event
.
timeStamp).formatISO
(
) +
" : l'élément "
+
el.
tagName +
" , ID = "
+
el.
id +
" , Class = '"
+
el.
className +
"' a modifié son option "
+
obj.
optionsKey +
", elle a pris la valeur "
+
obj.
optionsValue );
}
);
}
/*
* Rotation.
*
* Traite le cas dvjhTourne( "init", "25" ),
* sinon traite la valeur de l'option degrees
*/
if (
$.isNumeric
(
mesArguments[
0
]
) ){
this._setDegrees
(
mesArguments[
0
]
);
}
else {
this._setDegrees
(
this.
options.
degrees );
}
},
"destroy"
:
function(
params ){
// 1. Supprimer les gestionnaires d'événements.
this.
jObj.off
(
"optionsChanged.dvjhTourne"
);
// 2. Supprimer les composants UI.
// 3. Rendre null les objets (y compris array)
},
"setOption"
:
function(
params ){
var option
=
params.shift
(
),
value =
params.shift
(
);
if (
!
option
||
!
value ){
$.error
(
"Les paramètres ne sont pas conformes : ( "
+
option
+
", "
+
value +
" )."
);
}
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
this._setBoolDebug
(
value );
break;
case "degrees"
:
this._setDegrees
(
value );
break;
default:
$.error
(
"Cette option existe mais elle n'est pas publique !"
);
};
}
else {
$.error
(
"Cette option n'existe pas !"
);
}
},
"_setBoolDebug"
:
function(
value ){
if (
typeof value ===
"boolean"
){
this.
options.
boolDebug =
value;
}
},
"_setDegrees"
:
function(
value ){
/*
* Cette méthode traite la rotation
* initiale et les rotations demandées
* par la méthode setOption.
*/
if (
$.isNumeric
(
value ) ){
var v =
parseInt
(
value,
10
) ||
0
;
this.
options.
degrees =
v;
var rad =
v *
Math.
PI *
2
.
0
/
360
.
0
,
costheta =
Math.cos
(
rad),
sintheta =
Math.sin
(
rad),
a =
parseFloat
(
costheta,
10
).toFixed
(
8
),
c =
parseFloat
(-
sintheta,
10
).toFixed
(
8
),
b =
parseFloat
(
sintheta,
10
).toFixed
(
8
),
d =
parseFloat
(
costheta,
10
).toFixed
(
8
),
matrix =
"matrix("
+
a +
", "
+
b +
", "
+
c +
", "
+
d +
", 0, 0);"
;
this._avecStyle
(
matrix );
var optionsChangedEvent =
new $.Event
(
"optionsChanged.dvjhTourne"
);
optionsChangedEvent.
dvjh =
{
"initiateur"
:
this.
jObj,
"optionsKey"
:
"degrees"
,
"optionsValue"
:
v
};
this.
jObj.trigger
(
optionsChangedEvent );
}
else {
$.error
(
"_setDegrees : "
+
value +
" n'est pas un nombre !"
);
}
},
"_avecStyle"
:
function(
matrix ){
if (
this.
options.
boolDebug ){
console.log
(
"_avecStyle : "
,
this.
jObj,
matrix );
}
this.
jObj.attr
(
"style"
,
"-moz-transform:"
+
matrix +
"; -webkit-transform:"
+
matrix +
"; -ms-transform:"
+
matrix +
"; -o-transform:"
+
matrix +
"; transform:"
+
matrix +
";"
);
},
"getOption"
:
function(
params ){
var option
=
params.shift
(
),
callback =
params.shift
(
) ||
function(
){},
name
=
"getOption."
+
this.
_copyright.
objMethodsName;
if (
!
option
){
$.error
(
"getOption : le paramètre n'est pas conforme : ( "
+
option
+
" )."
);
}
/*
* Objet et array : attention de toujours transmettre une copie !
*/
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
var value =
this.
options.
boolDebug;
this.
jObj.data
(
name
,
value );
callback
(
option
,
value );
break;
case "degrees"
:
var value =
this.
options.
degrees;
this.
jObj.data
(
name
,
value );
callback
(
option
,
value );
break;
default:
$.error
(
"getOption : cette option existe mais elle n'est pas publique !"
);
};
}
else {
$.error
(
"getOption : cette option n'existe pas !"
);
}
}
};
// Ajouts de méthodes (plugin) au prototype de l'objet jQuery ($.fn).
$.extend
(
$.
fn,
{
"dvjhTourne"
:
function(
){
// un plugin multitâche
return dvjhPluginCreate.call
(
this,
dvjhTourneMethods,
arguments );
}
}
);
return {
"$"
:
$,
// voir le tutoriel "Adapter jQuery à vos besoins".
"dvjhTourneObjMethodsName"
:
dvjhTourneMethods.
_copyright.
objMethodsName,
"dvjhTourneObjMethodsDefaultOptions"
:
function(
objOptions ){
/*
* Modifications des options par défaut.
*
* Ne modifiez pas ce code sans nécessité !
*/
if (
$.isPlainObject
(
objOptions ) &&
!
$.isEmptyObject
(
objOptions ) ){
$.extend
(
dvjhTourneMethods.
_options,
objOptions );
}
}
};
}
)(
jQuery.sub
(
) );
Rappel : pour tester les codes, veuillez charger le ZIP.
Utilisation du plugin, extrait de dvjhTourne.html :
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.
41.
42.
43.
44.
45.
46.
$(
function(
){
$(
"#rotationBtnID"
).on
(
"click"
,
function(
){
$(
this ).hide
(
);
/*
* Rappel, le prototype de jQuery n'a pas de méthode dvjhTourne !
* Voir le tutoriel "Adapter jQuery à vos besoins".
*/
// $( ".divTest" ).dvjhTourne();
var jObjs =
dvjh.
$(
".divTest"
),
name
=
dvjh.
dvjhTourneObjMethodsName;
try {
// initialisation
// jObjs.dvjhTourne({ "degrees" : "45" }).css( "color", "blue" );
// ou
jObjs.dvjhTourne
(
"init"
,
"25"
).css
(
"color"
,
"blue"
);
var jObj2 =
jObjs.eq
(
1
);
// modification de la rotation du deuxième objet jQuery
jObj2.dvjhTourne
(
"setOption"
,
"degrees"
,
"-105"
).css
(
"color"
,
"red"
);
setTimeout
(
function(
){
jObj2.dvjhTourne
(
"getOption"
,
"degrees"
,
function(
option
,
value ){
/*
* Rappel : this est undefined !
*/
//console.log( this );
/*
* L'instance restaure son état à partir de ses options
* qui ne contiennent pas la couleur rouge du texte.
*/
jObj2.dvjhTourne
(
"setOption"
,
"degrees"
,
value +
52
).css
(
"color"
,
"red"
);
}
);
},
2000
);
}
catch(
e ){
alert
(
"dvjhTourne, "
+
e.
message );
}
}
);
}
);
IV-B. Le plugin dvjhEventShow▲
Bien entendu, lorsqu'un événement se produit l'objet méthodes est inactif et this.jObj a la valeur « null » !
On est donc obligé d'activer l'objet méthodes à partir du gestionnaire d'événements.
- Stocker la valeur de this.jObj par un $( l'élément du DOM qui intercepte l'événement ).data( "dvjhEventShowElement", this.jObj[0] ) ;
- Pour les cas simples, retrouver this.jObj à partir de l'élément du DOM qui intercepte l'événement. Ici: $( this ).parent().
Dans dvjhEventShow le premier cas est mis en commentaires, mais il est utilisable.
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
var dvjh = (
function(
$){
/*
* Le plugin dvjhEventShow illustre la gestion
* des événements.
*/
var dvjhEventShowMethods =
{
"_copyright"
:
{
// informations sur le plugin
"objMethodsName"
:
"dvjhEventShowMethods"
,
"auteur"
:
"Daniel Hagnoul"
,
"version"
:
"1.0.0"
,
"date"
:
"2012-02-07T22:04:41.000+01:00"
,
"licence"
:
"libre de tous droits"
},
"_options"
:
{
// les options par défaut
"boolDebug"
:
false,
"eventShowTexteCSS"
:
{
"font-family"
:
"Sofia"
,
"font-size"
:
"2rem"
,
"color"
:
"rgba( 211, 28, 56, 0.75)"
,
"background-color"
:
"rgba( 21, 68, 77, 0.5)"
,
"width"
:
"40rem"
,
"height"
:
"4rem"
,
"margin"
:
"1.4rem"
,
"padding"
:
"0.6rem"
,
"border"
:
"0.1rem dotted grey"
},
"number"
:
-
1
},
"jObj"
:
null,
// l'instance (un objet jQuery)
"options"
:
{},
// les options de l'instance
"init"
:
function(
){
// initialisation du plugin
var args =
Array.
prototype.
slice.call
(
arguments ),
param1 =
args.shift
(
),
param2 =
args.shift
(
);
if (
$.isPlainObject
(
param1 ) &&
!
$.isEmptyObject
(
param1 ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
param1 ) );
}
$.extend
(
this.
options,
param1 );
}
var dataOptions =
this.
jObj.data
(
"pluginOptions"
);
if (
$.isPlainObject
(
dataOptions ) &&
!
$.isEmptyObject
(
dataOptions ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
dataOptions ) );
}
$.extend
(
this.
options,
dataOptions );
}
var mesArguments =
[];
if (
$.isArray
(
param1 ) ){
mesArguments =
param1.concat
(
);
}
else if (
$.isArray
(
param2 ) ){
mesArguments =
param2.concat
(
);
}
if (
this.
options.
boolDebug ){
console.log
(
"init, this.jObj : "
,
this.
jObj );
console.log
(
"init, mesArguments : "
,
mesArguments.concat
(
) );
}
if (
mesArguments.
length >
0
){
/*
* Déclenche une exception si l'argument ne peut pas
* être converti dans une couleur valide.
*/
$.parseColor
(
mesArguments[
0
]
);
this.
options.
eventShowTexteCSS[
"background-color"
]
=
mesArguments[
0
];
}
var self
=
this;
this.
options.
jObjTexte =
$(
"<div/>"
,
{
"id"
:
"eventShowTexte"
+
$.now
(
),
"html"
:
"<p> "
+
self
.
options.
number +
". Un mot pour remplir.</p>"
,
"css"
:
self
.
options.
eventShowTexteCSS,
"click"
:
function(
e ){
/*
var jObj = $( $( this ).data( "dvjhEventShowElement" ) );
jObj.dvjhEventShow( "eventClickHandler", e );
*/
$(
this ).parent
(
).dvjhEventShow
(
"eventClickHandler"
,
e );
},
"mouseenter"
:
function(
e ){
/*
var jObj = $( $( this ).data( "dvjhEventShowElement" ) );
jObj.dvjhEventShow( "eventMouseEnterHandler", e );
*/
$(
this ).parent
(
).dvjhEventShow
(
"eventMouseEnterHandler"
,
e );
},
"mouseleave"
:
function(
e ){
/*
var jObj = $( $( this ).data( "dvjhEventShowElement" ) );
jObj.dvjhEventShow( "eventMouseLeaveHandler", e );
*/
$(
this ).parent
(
).dvjhEventShow
(
"eventMouseLeaveHandler"
,
e );
}
}
).data
(
"dvjhEventShowElement"
,
this.
jObj[
0
]
).appendTo
(
this.
jObj );
self
=
null;
},
"destroy"
:
function(
params ){
// 1. Supprimer les gestionnaires d'événements.
this.
options.
jObjTexte.off
(
"click mouseenter mouseleave"
);
// 2. Supprimer les composants UI.
this.
options.
jObjTexte.remove
(
);
// 3. Rendre null les objets (y compris array)
this.
options.
jObjTexte =
null;
},
"eventClickHandler"
:
function(
params ){
var e =
params.shift
(
);
/*
* N'oubliez pas que l'élément cliqué est disponible
* dans event.target, et que l'élément qui a intercepté
* l'événement est disponible dans event.currentTarget.
*
* Suivant la composition de l'élément et l'endroit cliqué
* le target et le currentTarget peuvent être identiques.
*/
console.log
(
e.
target,
e.
currentTarget,
" : "
,
this.
options.
number );
},
"eventMouseEnterHandler"
:
function(
params ){
var e =
params.shift
(
);
this.
options.
jObjTexte.css
(
"background-color"
,
"yellow"
);
},
"eventMouseLeaveHandler"
:
function(
params ){
var e =
params.shift
(
);
this.
options.
jObjTexte.css
(
"background-color"
,
this.
options.
eventShowTexteCSS[
"background-color"
]
);
},
"setOption"
:
function(
params ){
var option
=
params.shift
(
),
value =
params.shift
(
);
if (
!
option
||
!
value ){
$.error
(
"Les paramètres ne sont pas conformes : ( "
+
option
+
", "
+
value +
" )."
);
}
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
this._setBoolDebug
(
value );
break;
default:
$.error
(
"Cette option existe mais elle n'est pas publique !"
);
};
}
else {
$.error
(
"Cette option n'existe pas !"
);
}
},
"_setBoolDebug"
:
function(
value ){
if (
typeof value ===
"boolean"
){
this.
options.
boolDebug =
value;
}
},
"getOption"
:
function(
params ){
var option
=
params.shift
(
),
callback =
params.shift
(
) ||
function(
){},
name
=
"getOption."
+
this.
_copyright.
objMethodsName;
if (
!
option
){
$.error
(
"getOption : le paramètre n'est pas conforme : ( "
+
option
+
" )."
);
}
/*
* Objet et array : attention de toujours transmettre une copie !
*/
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
var value =
this.
options.
boolDebug;
this.
jObj.data
(
name
,
value );
callback
(
option
,
value );
break;
default:
$.error
(
"getOption : cette option existe mais "
+
"elle n'est pas publique !"
);
};
}
else {
$.error
(
"getOption : cette option n'existe pas !"
);
}
}
};
// Ajouts de méthodes (plugin) au prototype de l'objet jQuery ($.fn).
$.extend
(
$.
fn,
{
"dvjhEventShow"
:
function(
){
// un plugin multitâche
return dvjhPluginCreate.call
(
this,
dvjhEventShowMethods,
arguments );
}
}
);
return {
"$"
:
$,
"eventShowObjMethodsName"
:
dvjhEventShowMethods.
_copyright.
objMethodsName,
"eventShowObjMethodsDefaultOptions"
:
function(
objOptions ){
/*
* Modifications des options par défaut.
*
* Ne modifiez pas ce code sans nécessité !
*/
if (
$.isPlainObject
(
objOptions ) &&
!
$.isEmptyObject
(
objOptions ) ){
$.extend
(
dvjhEventShowMethods.
_options,
objOptions );
}
}
};
}
)(
jQuery.sub
(
) );
Cet exemple montre également comment gérer la destruction d'une instance.
Rappel : pour tester les codes, veuillez charger le ZIP.
Utilisation du plugin, extrait de dvjhEventShow.html :
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
$(
function(
){
try {
var bgColor =
[
"rgba( 159, 159, 234, 0.95 )"
,
"rgba( 159, 159, 234, 0.75 )"
,
"rgba( 159, 159, 234, 0.55 )"
,
"rgba( 159, 159, 234, 0.35 )"
,
"rgba( 159, 159, 234, 0.15 )"
,
];
var jObjTab =
[];
$(
"div"
,
"#test"
).each
(
function(
i,
item ){
/*
* Pour chaque division on initialise le plugin et
* on stocke l'objet jQuery.
*
* Lors de l'initialisation, on modifie l'option
* number de l'instance et on modifie la valeur
* par défaut du "background-color" pour la division
* ajoutée dans l'instance par le plugin.
*
* Signatures :
* jObj.dvjhEventShow( [options] [, bgColor] );
* jObj.dvjhEventShow( "init" [, bgColor] );
*/
jObjTab.push
(
dvjh.
$(
item ).dvjhEventShow
({
"number"
:
i +
1
// numérotation de 1 à n.
},
bgColor[
i]
)
/*
* Exemples d'initialisations alternatives :
*
* dvjh.$( item ).dvjhEventShow()
*
* Test du déclenchement d'une exception par $.parseColor().
* dvjh.$( item ).dvjhEventShow( "rgba(-16, 210, 27, 0.25)" )
*
* dvjh.$( item ).dvjhEventShow( bgColor[i] )
*
* dvjh.$( item ).dvjhEventShow( "init" )
*
* dvjh.$( item ).dvjhEventShow( "init", bgColor[i] )
*
* dvjh.$( item ).dvjhEventShow({
* "number" : i + 1 // numérotation de 1 à n.
* })
*/
);
}
);
for (
var i in jObjTab){
// une copie des options de chaque objet jQuery
console.log
(
$.extend
(
true,
{},
jObjTab[
i]
.data
(
dvjh.
eventShowObjMethodsName ) ) );
}
for (
var i in jObjTab){
jObjTab[
i]
.dvjhEventShow
(
"getOption"
,
"boolDebug"
,
function(
option
,
value ){
console.log
(
"getOption, option = "
,
option
,
", value = "
,
value );
}
);
}
jObjTab[
0
]
.dvjhEventShow
(
"destroy"
);
// les options de l'objet jQuery jObjTab[0] n'existent plus !
console.log
(
jObjTab[
0
]
.data
(
dvjh.
eventShowObjMethodsName ) );
/*
* Après la destruction, il est de votre
* responsabilité de rendre l'objet null.
*/
jObjTab[
0
]
=
null;
console.log
(
jObjTab );
}
catch(
e ){
alert
(
"dvjhEventShow, "
+
e.
message );
}
}
);
IV-C. Le plugin dvjhStorage▲
Ce plugin n'agit pas sur l'interface utilisateur, mais qui dit multitâche implique la complexité.
Le plugin dvjhStorage gère simplement le stockage de données dans un objet jQuery (jObj.data( "dvjhStorage" )), dans le sessionStorage et dans le localStorage des navigateurs non obsolètes.
Bien entendu on peut ajouter, supprimer ou chercher des données. Mais on peut aussi copier ou transférer des données d'un espace de stockage à l'autre.
Chaque donnée est représentée par un couple « key, value ». La variable « key » doit être du type « string ». La variable « value » peut contenir n'importe quoi car elle sera sauvegardée au format JSON. Lorsque la donnée est extraite du stockage, elle est restaurée dans son type d'origine. Lorsque la donnée est copiée ou transférée dans un autre stockage elle reste au format JSON.
Firefox : le sessionStorage n'est pas disponible en « local mode ».
On sauvegarde des données au format JSON. Si l'on passe un objet qui contient une fonction elle sera supprimée de la sauvegarde. De même toute clé (key) qui n'est pas un texte (string) ou un nombre (number).
Méthode | Signature |
initialisation | jObj = dvjh.initStorage( selector ); |
set | jObj.dvjhStorage( "set", ( "data" || "session" || "local" ), key, value ); |
get | jObj.dvjhStorage( "get", ( "data" || "session" || "local" ), key [, callback] ); |
has | jObj.dvjhStorage( "has", key [, callback] ); |
remove | jObj.dvjhStorage( "remove", ( "data" || "session" || "local" ), key ); |
copy | jObj.dvjhStorage( "copy", origine ( "data" || "session" || "local" ), destination ( "data" || "session" || "local" ), key ); |
relocate | jObj.dvjhStorage( "relocate", origine ( "data" || "session" || "local" ), destination ( "data" || "session" || "local" ), key ); |
clear | jObj.dvjhStorage( "clear", ( "data" || "session" || "local" ) ); |
clearAll | jObj.dvjhStorage( "clearAll" ); |
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
var dvjh = (
function(
$){
/*
* Plugin pour gérer le stockage des données au format JSON.
* On peut stocker dans le navigateur (sessionStorage ou localSorage)
* ou dans l'élément du DOM ( jObj.data( "dvjhStorage" ) ).
*
* Firefox : le sessionStorage n'est pas disponible en
* "local mode", mais il fonctionnera lorsque vous
* chargerez cette page Web à partir d'un serveur !
*
* On sauvegarde des données. Si l'on passe un objet qui contient
* une fonction elle sera supprimée. "Non-integer/string keys are
* skipped in the object, as are keys that point to a function".
*/
var dvjhStorageMethods =
{
"_copyright"
:
{
// informations sur le plugin
"objMethodsName"
:
"dvjhStorageMethods"
,
"auteur"
:
"Daniel Hagnoul"
,
"version"
:
"1.0.0"
,
"date"
:
"2012-01-21T20:30:45.000+01:00"
,
"licence"
:
"libre de tous droits"
},
"_options"
:
{
// les options par défaut
"boolDebug"
:
true
},
"jObj"
:
null,
// l'instance (un objet jQuery )
"options"
:
{},
// les options de l'instance
"init"
:
function(
){
// initialisation du plugin
var args =
Array.
prototype.
slice.call
(
arguments ),
param1 =
args.shift
(
),
param2 =
args.shift
(
);
if (
$.isPlainObject
(
param1 ) &&
!
$.isEmptyObject
(
param1 ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
param1 ) );
}
$.extend
(
this.
options,
param1 );
}
var dataOptions =
this.
jObj.data
(
"pluginOptions"
);
if (
$.isPlainObject
(
dataOptions ) &&
!
$.isEmptyObject
(
dataOptions ) ){
if (
this.
options.
boolDebug ){
console.log
(
"init, options de l'utilisateur : "
,
$.extend
(
true,
{},
dataOptions ) );
}
$.extend
(
this.
options,
dataOptions );
}
var mesArguments =
[];
if (
$.isArray
(
param1 ) ){
mesArguments =
param1.concat
(
);
}
else if (
$.isArray
(
param2 ) ){
mesArguments =
param2.concat
(
);
}
if (
this.
options.
boolDebug ){
console.log
(
"init, this.jObj : "
,
this.
jObj );
console.log
(
"init, mesArguments : "
,
mesArguments.concat
(
) );
}
/*
* Si le navigateur n'est pas compatible, l'objet
* jQuery n'est pas créé !
*/
if (
!
window
.
localStorage ){
$.error
(
"Le localStorage n'est pas disponible ! "
+
"Le navigateur est obsolète !"
);
}
this.
jObj.data
(
"dvjhStorage"
,
{}
);
if (
window
.
location
.
protocol ===
"file:"
){
console.log
(
"Sur Firefox, le sessionStorage n'est pas disponible "
+
"en
\"
local mode
\"
, mais il fonctionnera lorsque vous "
+
"chargerez cette page Web à partir d'un serveur !"
);
}
},
"destroy"
:
function(
params ){
// 1. Supprimer les gestionnaires d'événements.
// 2. Supprimer les composants UI.
// 3. Rendre null les objets (y compris array)
},
"set"
:
function(
params ){
var location
=
params.shift
(
),
key =
params.shift
(
),
value =
params.shift
(
);
if (
typeof location
===
"string"
&&
typeof key ===
"string"
&&
value ){
var jsonValue =
JSON.stringify
(
value );
if (
this.
options.
boolDebug ){
console.log
(
"set, location : "
,
location
);
console.log
(
"set, key : "
,
key );
if (
$.isArray
(
value ) ){
console.log
(
"set, value : "
,
value.concat
(
) );
}
else if (
$.isPlainObject
(
value ) ){
console.log
(
"set, value : "
,
$.extend
(
true,
{},
value ) );
}
else {
console.log
(
"set, value : "
,
value );
}
}
switch(
location
){
case "session"
:
this._sessionSet
(
key,
jsonValue );
break;
case "local"
:
this._localSet
(
key,
jsonValue );
break;
case "data"
:
this._dataSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette location ("
+
location
+
") n'existe pas !"
);
}
}
else {
$.error
(
"dvjhStorageMethods, set : les paramètres location ( "
+
location
+
" ) ( session || local || data ) et key ( "
+
key +
" ) doivent être de type text et le paramètre value ( "
+
value +
" ) doit exiter !"
);
}
},
"_sessionSet"
:
function(
key,
jsonValue ){
try {
window
.
sessionStorage.setItem
(
key,
jsonValue );
}
catch(
e ){
$.error
(
"dvjhStorage, sessionSet : "
+
e.
message );
}
},
"_localSet"
:
function(
key,
jsonValue ){
try {
window
.
localStorage.setItem
(
key,
jsonValue );
}
catch(
e ){
$.error
(
"dvjhStorage, localSet : "
+
e.
message );
}
},
"_dataSet"
:
function(
key,
jsonValue ){
try {
var objAnonyme =
this.
jObj.data
(
"dvjhStorage"
);
objAnonyme[
key ]
=
jsonValue;
this.
jObj.data
(
"dvjhStorage"
,
objAnonyme );
}
catch(
e ){
$.error
(
"dvjhStorage, dataSet : "
+
e.
message );
}
},
"get"
:
function(
params ){
var location
=
params.shift
(
),
key =
params.shift
(
),
callback =
params.shift
(
) ||
function(
){};
if (
typeof location
===
"string"
&&
typeof key ===
"string"
){
if (
this.
options.
boolDebug ){
console.log
(
"get, location : "
,
location
);
console.log
(
"get, key : "
,
key );
}
switch(
location
){
case "session"
:
this._sessionGet
(
key,
callback );
break;
case "local"
:
this._localGet
(
key,
callback );
break;
case "data"
:
this._dataGet
(
key,
callback );
break;
default:
$.error
(
"Cette location ("
+
location
+
") n'existe pas !"
);
}
}
else {
$.error
(
"dvjhStorageMethods, get : les paramètres location ( "
+
location
+
" ) ( session || local || data ) et key ( "
+
key +
" ) doivent être de type text !"
);
}
},
"_sessionGet"
:
function(
key,
callback ){
var name
=
"get."
+
this.
_copyright.
objMethodsName;
try {
// getItem retourne null si key n'existe pas !
var value =
JSON.parse
(
window
.
sessionStorage.getItem
(
key ) );
this.
jObj.data
(
name
,
value );
callback
(
key,
value );
}
catch(
e ){
$.error
(
"dvjhStorage, sessionGet : "
+
e.
message );
}
},
"_localGet"
:
function(
key,
callback ){
var name
=
"get."
+
this.
_copyright.
objMethodsName;
try {
// getItem retourne null si key n'existe pas !
var value =
JSON.parse
(
window
.
localStorage.getItem
(
key ) );
this.
jObj.data
(
name
,
value );
callback
(
key,
value );
}
catch(
e ){
$.error
(
"dvjhStorage, localGet : "
+
e.
message );
}
},
"_dataGet"
:
function(
key,
callback ){
var name
=
"get."
+
this.
_copyright.
objMethodsName;
try {
// getItem retourne null si key n'existe pas !
var objAnonyme =
this.
jObj.data
(
"dvjhStorage"
),
value =
null;
if (
key in objAnonyme ){
value =
JSON.parse
(
objAnonyme[
key ]
);
}
this.
jObj.data
(
name
,
value );
callback
(
key,
value );
}
catch(
e ){
$.error
(
"dvjhStorage, dataGet : "
+
e.
message );
}
},
"has"
:
function(
params ){
var key =
params.shift
(
),
callback =
params.shift
(
) ||
function(
){},
name
=
"has."
+
this.
_copyright.
objMethodsName;
if (
typeof key ===
"string"
){
if (
this.
options.
boolDebug ){
console.log
(
"has, key : "
,
key );
}
try {
var boolSession =
false,
boolLocal =
false,
boolData =
false;
if (
key in window
.
sessionStorage ){
boolSession =
true;
}
if (
key in window
.
localStorage ){
boolLocal =
true;
}
if (
key in this.
jObj.data
(
"dvjhStorage"
) ){
boolData =
true;
}
this.
jObj.data
(
name
,
{
"session"
:
boolSession,
"local"
:
boolLocal,
"data"
:
boolData
}
);
callback
(
key,
{
"session"
:
boolSession,
"local"
:
boolLocal,
"data"
:
boolData
}
);
}
catch(
e ){
$.error
(
"dvjhStorage, has : "
+
e.
message );
}
}
else {
$.error
(
"dvjhStorageMethods, has : le paramètre key ( "
+
key +
" ) doit être de type text !"
);
}
},
"remove"
:
function(
params ){
var location
=
params.shift
(
),
key =
params.shift
(
);
if (
typeof location
===
"string"
&&
typeof key ===
"string"
){
if (
this.
options.
boolDebug ){
console.log
(
"remove, location : "
,
location
);
console.log
(
"remove, key : "
,
key );
}
switch(
location
){
case "session"
:
this._sessionRemove
(
key );
break;
case "local"
:
this._localRemove
(
key );
break;
case "data"
:
this._dataRemove
(
key );
break;
default:
$.error
(
"Cette location ("
+
location
+
") n'existe pas !"
);
}
}
else {
$.error
(
"dvjhStorageMethods, remove : les paramètres location ( "
+
location
+
" ) ( session || local || data ) et key ( "
+
key +
" ) doivent être de type text !"
);
}
},
"_sessionRemove"
:
function(
key ){
try {
// removeItem ne fait rien si key n'existe pas !
window
.
sessionStorage.removeItem
(
key );
}
catch(
e ){
$.error
(
"dvjhStorage, sessionRemove : "
+
e.
message );
}
},
"_localRemove"
:
function(
key ){
try {
// removeItem ne fait rien si key n'existe pas !
window
.
localStorage.removeItem
(
key );
}
catch(
e ){
$.error
(
"dvjhStorage, localRemove : "
+
e.
message );
}
},
"_dataRemove"
:
function(
key ){
try {
// remove ne fait rien si key n'existe pas !
var objAnonyme =
this.
jObj.data
(
"dvjhStorage"
);
if (
key in objAnonyme ){
delete objAnonyme[
key ];
}
this.
jObj.data
(
"dvjhStorage"
,
objAnonyme );
}
catch(
e ){
$.error
(
"dvjhStorage, dataRemove : "
+
e.
message );
}
},
"clear"
:
function(
params ){
var location
=
params.shift
(
);
if (
typeof location
===
"string"
){
if (
this.
options.
boolDebug ){
console.log
(
"clear, location : "
,
location
);
}
switch(
location
){
case "session"
:
this._sessionClear
(
);
break;
case "local"
:
this._localClear
(
);
break;
case "data"
:
this._dataClear
(
);
break;
default:
$.error
(
"Cette location ("
+
location
+
") n'existe pas !"
);
}
}
else {
$.error
(
"dvjhStorageMethods, setItem : le paramètre location ( "
+
location
+
" ) ( session || local || data ) et key ( "
+
" ) doit être de type text !"
);
}
},
"clearAll"
:
function(
params ){
if (
this.
options.
boolDebug ){
console.log
(
"clearAll"
);
}
this._sessionClear
(
);
this._localClear
(
);
this._dataClear
(
);
},
"_sessionClear"
:
function(
){
try {
window
.
sessionStorage.clear
(
);
}
catch(
e ){
$.error
(
"dvjhStorage, sessionClear : "
+
e.
message );
}
},
"_localClear"
:
function(
){
try {
window
.
localStorage.clear
(
);
}
catch(
e ){
$.error
(
"dvjhStorage, localClear : "
+
e.
message );
}
},
"_dataClear"
:
function(
){
try {
this.
jObj.data
(
"dvjhStorage"
,
{}
);
}
catch(
e ){
$.error
(
"dvjhStorage, dataClear : "
+
e.
message );
}
},
"relocate"
:
function(
params ){
var origine =
params.shift
(
),
destination =
params.shift
(
),
key =
params.shift
(
);
if (
typeof origine ===
"string"
&&
typeof destination ===
"string"
&&
typeof key ===
"string"
){
if (
this.
options.
boolDebug ){
console.log
(
"relocate, origine : "
,
origine );
console.log
(
"relocate, destination : "
,
destination );
console.log
(
"relocate, key : "
,
key );
}
switch(
origine ){
case "session"
:
this._sessionRelocate
(
key,
destination );
break;
case "local"
:
this._localRelocate
(
key,
destination );
break;
case "data"
:
this._dataRelocate
(
key,
destination );
break;
default:
$.error
(
"Cette origine ("
+
origine +
") n'existe pas !"
);
}
}
else {
$.error
(
"dvjhStorageMethods, relocate : les paramètres origine ( "
+
origine +
" ) ( session || local || data ), destination ( "
+
destination +
" ) ( session || local || data ) et key "
+
" doivent être de type text !"
);
}
},
"_sessionRelocate"
:
function(
key,
destination ){
try {
// getItem retourne null si key n'existe pas !
var jsonValue =
window
.
sessionStorage.getItem
(
key );
if (
jsonValue ){
// removeItem ne fait rien si key n'existe pas !
window
.
sessionStorage.removeItem
(
key );
switch(
destination ){
case "local"
:
this._localSet
(
key,
jsonValue );
break;
case "data"
:
this._dataSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette destination ("
+
destination +
") n'existe pas !"
);
}
}
}
catch(
e ){
$.error
(
"dvjhStorage, sessionRelocate : "
+
e.
message );
}
},
"_localRelocate"
:
function(
key,
destination ){
try {
// getItem retourne null si key n'existe pas !
var jsonValue =
window
.
localStorage.getItem
(
key );
if (
jsonValue ){
// removeItem ne fait rien si key n'existe pas !
window
.
localStorage.removeItem
(
key );
switch(
destination ){
case "session"
:
this._sessionSet
(
key,
jsonValue );
break;
case "data"
:
this._dataSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette destination ("
+
destination +
") n'existe pas !"
);
}
}
}
catch(
e ){
$.error
(
"dvjhStorage, localRelocate : "
+
e.
message );
}
},
"_dataRelocate"
:
function(
key,
destination ){
try {
var objAnonyme =
this.
jObj.data
(
"dvjhStorage"
),
jsonValue =
null;
if (
key in objAnonyme ){
jsonValue =
objAnonyme[
key ];
delete objAnonyme[
key ];
}
this.
jObj.data
(
"dvjhStorage"
,
objAnonyme )
if (
jsonValue ){
switch(
destination ){
case "local"
:
this._localSet
(
key,
jsonValue );
break;
case "session"
:
this._sessionSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette destination ("
+
destination +
") n'existe pas !"
);
}
}
}
catch(
e ){
$.error
(
"dvjhStorage, dataRelocate : "
+
e.
message );
}
},
"copy"
:
function(
params ){
var origine =
params.shift
(
),
destination =
params.shift
(
),
key =
params.shift
(
);
if (
typeof origine ===
"string"
&&
typeof destination ===
"string"
&&
typeof key ===
"string"
){
if (
this.
options.
boolDebug ){
console.log
(
"copy, origine : "
,
origine );
console.log
(
"copy, destination : "
,
destination );
console.log
(
"copy, key : "
,
key );
}
switch(
origine ){
case "session"
:
this._sessionCopy
(
key,
destination );
break;
case "local"
:
this._localCopy
(
key,
destination );
break;
case "data"
:
this._dataCopy
(
key,
destination );
break;
default:
$.error
(
"Cette origine ("
+
origine +
") n'existe pas !"
);
}
}
else {
$.error
(
"dvjhStorageMethods, copy : les paramètres origine ( "
+
origine +
" ) ( session || local || data ), destination ( "
+
destination +
" ) ( session || local || data ) et key "
+
" doivent être de type text !"
);
}
},
"_sessionCopy"
:
function(
key,
destination ){
try {
// getItem retourne null si key n'existe pas !
var jsonValue =
window
.
sessionStorage.getItem
(
key );
if (
jsonValue ){
switch(
destination ){
case "local"
:
this._localSet
(
key,
jsonValue );
break;
case "data"
:
this._dataSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette destination ("
+
destination +
") n'existe pas !"
);
}
}
}
catch(
e ){
$.error
(
"dvjhStorage, sessionCopy : "
+
e.
message );
}
},
"_localCopy"
:
function(
key,
destination ){
try {
// getItem retourne null si key n'existe pas !
var jsonValue =
window
.
localStorage.getItem
(
key );
if (
jsonValue ){
switch(
destination ){
case "session"
:
this._sessionSet
(
key,
jsonValue );
break;
case "data"
:
this._dataSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette destination ("
+
destination +
") n'existe pas !"
);
}
}
}
catch(
e ){
$.error
(
"dvjhStorage, localCopy : "
+
e.
message );
}
},
"_dataCopy"
:
function(
key,
destination ){
try {
var objAnonyme =
this.
jObj.data
(
"dvjhStorage"
),
jsonValue =
null;
if (
key in objAnonyme ){
jsonValue =
objAnonyme[
key ];
}
if (
jsonValue ){
switch(
destination ){
case "local"
:
this._localSet
(
key,
jsonValue );
break;
case "session"
:
this._sessionSet
(
key,
jsonValue );
break;
default:
$.error
(
"Cette destination ("
+
destination +
") n'existe pas !"
);
}
}
}
catch(
e ){
$.error
(
"dvjhStorage, dataCopy : "
+
e.
message );
}
},
"setOption"
:
function(
params ){
var option
=
params.shift
(
),
value =
params.shift
(
);
if (
!
option
||
!
value ){
$.error
(
"Les paramètres ne sont pas conformes : ( "
+
option
+
", "
+
value +
" )."
);
}
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
this._setBoolDebug
(
value );
break;
default:
$.error
(
"Cette option existe mais elle n'est \
pas publique !"
);
};
}
else {
$.error
(
"Cette option n'existe pas !"
);
}
},
"_setBoolDebug"
:
function(
value ){
if (
typeof value ===
"boolean"
){
this.
options.
boolDebug =
value;
}
},
"getOption"
:
function(
params ){
var option
=
params.shift
(
),
callback =
params.shift
(
) ||
function(
){},
name
=
"getOption."
+
this.
_copyright.
objMethodsName;
if (
!
option
){
$.error
(
"getOption : le paramètre n'est pas conforme : ( "
+
option
+
" )."
);
}
/*
* Objet et array : attention de toujours transmettre une copie !
*/
if (
option
in this.
options ){
switch(
option
){
case "boolDebug"
:
var value =
this.
options.
boolDebug;
this.
jObj.data
(
name
,
value );
callback
(
option
,
value );
break;
default:
$.error
(
"getOption : cette option existe mais "
+
"elle n'est pas publique !"
);
};
}
else {
$.error
(
"getOption : cette option n'existe pas !"
);
}
}
};
// Ajouts de méthodes (plugin) au prototype de l'objet jQuery ($.fn).
$.extend
(
$.
fn,
{
"dvjhStorage"
:
function(
){
// un plugin multitâche
return dvjhPluginCreate.call
(
this,
dvjhStorageMethods,
arguments );
}
}
);
return {
"initStorage"
:
function(
selector ){
/*
* La seule méthode disponible pour l'initialisation
* d'un dvjhStorage.
*
* Cette méthode garantit que l'on ne traite qu'un seul objet
* jQuery à la fois. Dans le cas contraire, on aurait autant
* d'opérations sur le navigateur (localStorage et
* sessionStorage) qu'il y a d'instances dans selector.
*
* Si le navigateur n'est pas compatible jObj est null !
*/
var jObj =
null;
try {
if (
typeof selector ===
"string"
&&
$.isFunction
(
$(
selector ).
is ) ){
jObj =
$(
selector ).eq
(
0
).dvjhStorage
(
);
}
}
catch(
e ){
console.log
(
"dvjhStorage, initStorage : "
+
e.
message );
}
return jObj;
},
"storageObjMethodsName"
:
dvjhStorageMethods.
_copyright.
objMethodsName;
"storageObjMethodsDefaultOptions"
:
function(
objOptions ){
/*
* Modifications des options par défaut.
*
* Ne modifiez pas ce code sans nécessité !
*/
if (
$.isPlainObject
(
objOptions ) &&
!
$.isEmptyObject
(
objOptions ) ){
$.extend
(
dvjhStorageMethods.
_options,
objOptions );
}
}
};
}
)(
jQuery.sub
(
) );
Rappel : pour tester les codes, veuillez charger le ZIP.
Utilisation du plugin, extrait de dvjhStorage.html :
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.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
$(
function(
){
// fonction de rappel pour traiter le résultat de "get"
function getResult
(
key,
value ){
console.log
(
"getResult, key = "
,
key,
", value = "
,
value )
}
// fonction de rappel pour traiter le résultat de "has"
function hasResult
(
key,
boolObj ){
console.log
(
"hasResult, key = "
,
key,
", boolObj = "
);
for (
var n in boolObj){
console.log
(
"prop = "
,
n,
", value = "
,
boolObj[
n ]
);
}
}
try {
/*
* Initialisation du premier élément du DOM
* contenu dans le sélecteur.
*
* Bien entendu, dans une page Web, plusieurs éléments du DOM
* peuvent posséder un espace de stockage (data) distinct.
*
* Pour sélectionner un seul élément du DOM, utilisez une
* classe spécifique ou un ID.
*
* Si le navigateur n'est pas compatible, jObjStorage est null !
*/
var jObjStorage =
dvjh.initStorage
(
"section.conteneur"
);
if (
jObjStorage ){
/*
* L'usage d'un espace de noms pour étiqueter les
* données sauvegardées n'est pas une obligation
* mais une recommandation car cela diminue le
* risque d'une collision de noms dans le
* navigateur (session et local storage).
*/
var strNamespace =
"sectionConteneur"
;
/*
* L'objet JavaScript qui sera sauvegardé au format JSON
*/
var mesDatas =
{
"maProp"
:
"Daniel Hagnoul"
,
"monArray"
:
[
"hello"
,
42
.
42
,
-
42
,
"bye"
],
"monObj"
:
{
"uneProp"
:
"dvjh"
,
"unArray"
:
[
"bonjour"
,
42
.
42
,
-
42
,
"bonsoir"
]
}
};
var dataKey =
"mesDatas."
+
strNamespace;
// stocke dataKey et sa valeur dans data
jObjStorage.dvjhStorage
(
"set"
,
"data"
,
dataKey,
mesDatas );
// trouve dataKey et sa valeur dans data et place une copie
// dans une éventuelle fonction de rappel (callback)
jObjStorage.dvjhStorage
(
"get"
,
"data"
,
dataKey,
getResult );
// et dans :
var lesDatas =
jObjStorage.data
(
"get."
+
dvjh.
storageObjMethodsName );
// lesDatas est un véritable objet JavaScript
console.log
(
"lesDatas = "
,
lesDatas );
// une copie des options du plugin pour jObjStorage
console.log
(
$.extend
(
true,
{},
jObjStorage.data
(
dvjh.
storageObjMethodsName ) ) );
// une copie du contenu du stockage dans data
console.log
(
$.extend
(
true,
{},
jObjStorage.data
(
"dvjhStorage"
) ) );
// supprime dataKey et sa valeur dans data
//jObjStorage.dvjhStorage( "remove", "data", dataKey );
// console.log( $.extend( true, {}, jObjStorage.data( "dvjhStorage" ) ) );
// supprime toutes les données dans data
//jObjStorage.dvjhStorage( "clear", "data" );
// copie dataKey et sa valeur dans le sessionStorage du navigateur
jObjStorage.dvjhStorage
(
"copy"
,
"data"
,
"session"
,
dataKey );
//console.log( $.extend( true, {}, jObjStorage.data( "dvjhStorage" ) ) );
// copie dataKey et sa valeur dans le localStorage du navigateur
// puis supprime dataKey et sa valeur dans data
jObjStorage.dvjhStorage
(
"relocate"
,
"data"
,
"local"
,
dataKey );
console.log
(
$.extend
(
true,
{},
jObjStorage.data
(
"dvjhStorage"
) ) );
// cherche si dataKey existe dans data et dans le navigateur
// place le résultat dans une éventuelle fonction de rappel (callback)
jObjStorage.dvjhStorage
(
"has"
,
dataKey,
hasResult );
// et dans :
console.log
(
jObjStorage.data
(
"has."
+
dvjh.
storageObjMethodsName ) );
// efface toutes les données dans data et dans le navigateur
jObjStorage.dvjhStorage
(
"clearAll"
);
}
}
catch(
e ){
alert
(
"dvjhStorage, "
+
e.
message );
}
}
);
V. Remerciements▲
Un grand merci à ceux qui auront le courage de lire et de tester mon travail !
Un grand merci au correcteur Claude LELOUP pour son excellent travail.