Subversion Repositories wimsdev

Rev

Rev 10818 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10818 obado 1
/*
2
 * Classe parente pour blocs "Essaim"
3
 * Un essaim est un ensemble d'instructions sous forme de bloc
4
 * qui interagit avec la partie "énoncé" et avec la partie "analyse"
5
 * Il faut faire dériver un essaim spécifique comme dans l'essaim "QCM"
6
 */
7
 
8
Essaim = function(num)
9
{
10
    //--------- ATTRIBUTS ---------//
11
 
12
    this.nom = "Essaim"+num;    // nom de cet essaim
13
    this.numero = num;          // numéro de cet essaim parmi les essaims de l'exercice
14
    this.proto = "Essaim";      // nature de la classe parente
15
};
16
 
17
Essaim.prototype.nomAffiche = "Essaim";  // nom affiché dans le menu
18
Essaim.prototype.proto = "Essaim"; // nature de la classe parente
19
Essaim.prototype.imageEnonce = "images_essaims/essaimVirtuel.png"; // image à insérer dans l'énoncé
20
Essaim.prototype.gereReponse = true; // drapeau, si "true", gère une réponse dans l'analyse
21
Essaim.prototype.aUneAide = false;   // drapeau, si "true" gère une aide dans le bloc préparation
22
Essaim.prototype.estUnEssaim = true; // drapeau pour retrouver plus facilement les essaims dans la liste ordonnée de blocs préparation.
23
Essaim.prototype.zNodesAide = [];        // titres des noeuds de l'arbre d'aide (zTree)
24
Essaim.prototype.elementsAide = [];  // contenu des aides
25
Essaim.prototype.idMenusDeroulants = []; // id des menus déroulants, dans l'ordre de fabrication. C'est au programmeur de savoir à quel bouton correspondent ces menus (par exemple, this.idMenusDeroulants[0] correspond au menu des composants dans un éditeur).
26
Essaim.nbMenuDeroul = 0;    // VARIABLE STATIQUE, nbre de menus deroulants dans chaque essaim de ce type
27
                            // ils peuvent être utilisés par exemple pour une liste de composants
28
Essaim.classeItemMenuDeroul = [];  // VARIABLE STATIQUE, classes des items des menus déroulants
29
 
30
 
31
    //--------- METHODES ----------//
32
 
33
 
34
Essaim.prototype.initBloc = function()
35
/*
36
 * Initialisation d'un bloc Essaim.
37
 * crée le bloc vide dans l'onglet préparation.
38
 * crée les boutons de suppression/déplacement/...
39
 */
40
{
41
 var bloc_pere = document.getElementById("Rid_Prep_Blocs");
42
 var liste = document.createElement("LI");
43
 liste.id = "RidPrBloc_"+this.nom;
44
 liste.className = "Rcl_Bloc_Essaim Rcl_Bloc";
45
 var posDrag = document.createAttribute("posdrag");
46
 posDrag.value=0;
47
 bloc_pere.setAttributeNode(posDrag);
48
 
49
 /* début des modifs pour le drap and drop */
50
 liste.draggable = true;
51
 var posDrag=0;
52
 
53
    liste.addEventListener('dragstart', function(e) {
54
 
55
        if(bloc_pere.getAttribute("posdrag")==0){
56
                    bloc_pere.setAttribute("posdrag",""+e.clientY);
57
                }
58
        e.dataTransfer.setData('text/plain', liste.id);
59
        e.dataTransfer.setDragImage(dragImg, 40, 40); // Une position de 40x40 pixels centrera l'image (de 80x80 pixels) sous le curseur
60
 
61
    });
62
 
63
    var dragImg = new Image(); // On précharge l'image
64
    dragImg.src = 'drag_img.png';
65
 
66
    //On gère la réception
67
    liste.addEventListener('dragover', function(e) {
68
        e.preventDefault(); // Annule l'interdiction de drop
69
        if(e!=this)
70
            {
71
                if(bloc_pere.getAttribute("posdrag")<e.clientY)
72
        {
73
            this.style.borderBottom="2px dotted red";
74
        }
75
        else
76
        {
77
            this.style.borderTop="2px dotted red";
78
        }
79
            }
80
        console.log('Un élément survole la zone');
81
    });
82
    // On gère le changement d'apparence entre les deux fonctions. 
83
 
84
    liste.addEventListener('dragenter', function(e) {
85
         //Lorsqu'on entre dans la zone de drop
86
         console.log('Entrée dans zone !');
87
     });
88
 
89
    liste.addEventListener('dragleave', function(e) {
90
         //Lorsqu'on sort d'une zone de drop.
91
        this.style.borderBottom="";      
92
        this.style.borderTop="";
93
        console.log('Sortie de zone');
94
     });
95
 
96
 
97
 
98
   liste.addEventListener('drop', function(e) {
99
        /*Cette fonction sert à décrire ce qui se passera pour le bloc ciblé ce qui se passera lorsqu'on lachera un objet droppable sur lui */
100
 
101
        this.style.borderBottom="";      
102
        this.style.borderTop="";
103
       if(bloc_pere.getAttribute("posdrag")!=""+0){
104
            bloc_pere.setAttribute("posdrag",0);
105
        }
106
        var nomZoneIn=" "; //on va récupérer l'id du bloc reçu. 
107
        nomZoneIn=e.dataTransfer.getData('text/plain'); // Affiche le contenu du type MIME « text/plain »
108
        console.log('Données reçu : ' + nomZoneIn);
109
        //Maintenant nous allons faire en sorte de changer de place le bloc si on passe sur le bloc avant ou après lui
110
 
111
        var id_drop = document.querySelector('#'+nomZoneIn);
112
        //var li = buttonHaut.parentNode.parentNode;
113
 
114
        // On va gérer le précédent
115
        var previous = id_drop.previousElementSibling;//l'élément précédent le bloc droppé
116
 
117
        var next = id_drop.nextElementSibling;//l'élément suivant le bloc droppé
118
 
119
       var lgNext= Essaim.prototype.trouverSuivant(id_drop,this); //Permet de donner à cb de cases se trouve le bloc ciblé wxc
120
        var lgPrev=0;
121
        console.log('Oui, vous avez bien entendu, '+lgNext+' blocs plus loin')
122
 
123
 
124
        var lgPrev= Essaim.prototype.trouverPrecedent(id_drop,this);
125
        //var actu= id_drop;
126
        if(lgNext>0)
127
        {
128
            console.log("Et ca, ca permet d'entrer dans la fonction de déplacement du suivant");
129
 
130
            for (var i = 0; i < lgNext; i++) { //on fait faire au bloc droppé lgNext descentes vers le bas.
131
 
132
                if(next){
133
                    next = next.nextElementSibling;
134
 
135
                    console.log('Un bloc suivant a été trouvé ! Changement...');
136
                    id_drop.parentNode.insertBefore(id_drop, next);
137
                    var nom = id_drop.id.slice("RidPrBloc_".length,id_drop.id.length);
138
 
139
                    var ind = rucheSys.rechercheIndice(nom,rucheSys.listeBlocPrepa);
140
 
141
                    var temp = rucheSys.listeBlocPrepa[ind];
142
                    rucheSys.listeBlocPrepa[ind] = rucheSys.listeBlocPrepa[ind+1];
143
                    rucheSys.listeBlocPrepa[ind+1] = temp;
144
 
145
 
146
                }
147
                else
148
                {
149
                    console.log("Fin du next");
150
                }
151
 
152
                //On change visuellement la place. 
153
 
154
                }
155
            }
156
 
157
        if (lgPrev) {
158
            for(var j=0; j< lgPrev;j++)
159
            {
160
             if (previous) {
161
                    console.log('Un bloc precedent a été trouvé ! Changement...');
162
                    id_drop.parentNode.insertBefore(id_drop, previous);
163
                    var nom = id_drop.id.slice("RidPrBloc_".length,id_drop.id.length);
164
 
165
                    var ind = rucheSys.rechercheIndice(nom,rucheSys.listeBlocPrepa);
166
 
167
                    var temp = rucheSys.listeBlocPrepa[ind];
168
                    rucheSys.listeBlocPrepa[ind] = rucheSys.listeBlocPrepa[ind-1];
169
                    rucheSys.listeBlocPrepa[ind-1] = temp;
170
                    previous = id_drop.previousElementSibling;
171
                }
172
                else
173
                {
174
                    console.log('Pas de précédent, désolé !');
175
                }
176
            }
177
        }
178
 
179
        else
180
        {
181
            console.log('Ni suivant, ne précédent !***********************');
182
        }
183
            console.log(this.id);
184
        });
185
 
186
 
187
 
188
    this.divBloc = document.createElement("DIV");
189
    this.divBloc.className = "Rcl_Bloc_Interne";
190
 
191
    /* Bouton de suppression */
192
    var buttonSuppr = document.createElement('button');
193
    buttonSuppr.id = "Rid_Button_Delete_" + this.nom;
194
    buttonSuppr.className = "Rcl_Button_Delete";
195
    buttonSuppr.onclick = function(){
196
      // supprime le bloc, ainsi que toute trace dans le tableau
197
        var n = liste.id.slice("RidPrBloc_".length,liste.id.length); //n est le nom+numero (Essaimxxx) de l'essaim
198
        var indEssaimCible = rucheSys.rechercheIndice(n,rucheSys.listeBlocPrepa);
199
//        rucheSys.supprInstruction(n,rucheSys.listeBlocPrepa);
200
        Essaim.prototype.detruitBloc.call(rucheSys.listeBlocPrepa[indEssaimCible]);
201
 
202
    }
203
 
204
    // Bouton pour diminuer / agrandir la fenêtre
205
    var buttonWindow = document.createElement('button');
206
    buttonWindow.id ="Rid_Button_MiniMaxi_"+this.nom;
207
    buttonWindow.className = "Rcl_Button_Minimize";
208
    buttonWindow.addEventListener('click', function (event)
209
    {
210
        if (buttonWindow.className == "Rcl_Button_Minimize")
211
        {
212
            buttonWindow.className = "";
213
            buttonWindow.className = "Rcl_Button_Maximize";
214
            buttonWindow.parentNode.parentNode.className = "Rcl_Bloc_Essaim Rcl_Closed";
215
        }
216
        else
217
        {
218
            buttonWindow.className = "";
219
            buttonWindow.className = "Rcl_Button_Minimize";
220
            buttonWindow.parentNode.parentNode.className = "";
221
            buttonWindow.parentNode.parentNode.className = "Rcl_Bloc_Essaim Rcl_Bloc";
222
        };
223
    },
224
    true);
225
 
226
    /* Bouton de deplacement vers le haut*/
227
    var buttonHaut = document.createElement('button');
228
    buttonHaut.id = "Rid_Button_Up_"+this.nom;
229
    buttonHaut.className = "Rcl_Move_Up_Arrow";
230
    buttonHaut.addEventListener('click', function (event)
231
    {
232
        var li = buttonHaut.parentNode.parentNode;
233
        var previous = li.previousElementSibling;
234
        if (previous) {
235
            li.parentNode.insertBefore(li, previous);
236
            var nom = li.id.slice("RidPrBloc_".length,li.id.length);
237
 
238
            var ind = rucheSys.rechercheIndice(nom,rucheSys.listeBlocPrepa);
239
 
240
            var temp = rucheSys.listeBlocPrepa[ind];
241
            rucheSys.listeBlocPrepa[ind] = rucheSys.listeBlocPrepa[ind-1];
242
            rucheSys.listeBlocPrepa[ind-1] = temp;
243
        }
244
    },
245
    true);
246
 
247
    /* Bouton de deplacement vers le bas*/
248
    var buttonBas = document.createElement('button');
249
    buttonBas.id = "Rid_Button_Down_"+this.nom;
250
    buttonBas.className = "Rcl_Move_Down_Arrow";
251
    buttonBas.addEventListener('click', function (event) {
252
        var li = buttonBas.parentNode.parentNode;
253
        var next = li.nextElementSibling;
254
        if (next) {
255
            next = next.nextElementSibling;
256
            var nom = li.id.slice("RidPrBloc_".length,li.id.length);
257
 
258
            var ind = rucheSys.rechercheIndice(nom,rucheSys.listeBlocPrepa);
259
 
260
            var temp = rucheSys.listeBlocPrepa[ind];
261
            rucheSys.listeBlocPrepa[ind] = rucheSys.listeBlocPrepa[ind+1];
262
            rucheSys.listeBlocPrepa[ind+1] = temp;
263
        }
264
        li.parentNode.insertBefore(li, next);
265
    },
266
    true);
267
 
268
    /* Bouton d'aide */
269
    if (this.aUneAide==true) {
270
        var buttonAide = document.createElement('button');
271
        buttonAide.id = "aide"+this.nom;
272
        buttonAide.className = "Rcl_Button_Help_Close";
273
        buttonAide.addEventListener('click', function (event)
274
        {
275
            var divAideNom = buttonAide.id.slice("aide".length,buttonAide.id.length);
276
            if (buttonAide.className == "Rcl_Button_Help_Open") {
277
                buttonAide.className = "";
278
                buttonAide.className = "Rcl_Button_Help_Close";
279
                $("#divAide"+divAideNom).toggleClass("Rcl_Help_Closed",true);
280
    //            buttonAide.parentNode.parentNode.className = "Rcl_Bloc_Essaim Rcl_Bloc closed";
281
            }
282
            else
283
            {
284
                buttonAide.className = "";
285
                buttonAide.className = "Rcl_Button_Help_Open";
286
                $("#divAide"+divAideNom).toggleClass("Rcl_Help_Closed",false);
287
    //            buttonAide.parentNode.parentNode.className = "";
288
    //            buttonAide.parentNode.parentNode.className = "Rcl_Bloc_Essaim Rcl_Bloc";
289
            }
290
        },
291
        true);
292
    }
293
 
294
    // Fabrication du contenu du bloc
295
 
296
    this.divBloc.appendChild(buttonSuppr);
297
    this.divBloc.appendChild(buttonWindow);
298
    this.divBloc.appendChild(buttonHaut);
299
    this.divBloc.appendChild(buttonBas);
300
    if (this.aUneAide==true) {
301
        this.divBloc.appendChild(buttonAide);
302
    }
303
 
304
    liste.appendChild(this.divBloc);
305
    if (this.aUneAide==true) {
306
        liste.appendChild(this.aideInit());
307
    }
308
    bloc_pere.appendChild(liste);
309
    if (this.aUneAide==true) {
310
        this.aideMenuInit();
311
    }
312
}
313
 
314
Essaim.prototype.aideInit = function()
315
/*
316
 * Construction de la partie "aide" du bloc essaim.
317
 * Cette aide vient normalement en dernière position, après les éléments
318
 * du bloc. Mais les classes filles peuvent mettre l'aide
319
 * où bon leur semble. Voir exemple dans l'essaim "Dessinflydraw".
320
 * sortie :     - element DIV contenant l'aide
321
 */
322
{
323
    var divAide = $("<div>", {
324
                    id: "divAide"+this.nom,
325
                    class: "Rcl_Help_Essaim Rcl_Help_Closed"
326
                    });
327
    divAide.css("overflow","hidden");   // pour empêcher les éléments flottants
328
                                        // (le menu) de dépasser du div
329
    return divAide[0];
330
}
331
 
332
Essaim.prototype.aideMenuInit = function(zNodes,elementsAide)
333
/*
334
 * Construction de la liste (menu) des éléments d'aide.
335
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
336
 * parametre(s) :       - zNodes : liste des noeuds cliquables (objet JSON).
337
 *                                      leur id doivent être dans l'ordre 1,2,..N
338
 *                      - elementsAide : tableau des chaines (html) contenant les aides.
339
 *                                      l'ordre est le même que les noeuds zNodes
340
 *                                      (l'id du noeud est l'indice de l'aide dans le tableau
341
 */
342
{
343
    // Initialisation des paramètres du menu zTree
344
    var curMenu = null, zTree_Menu = null;
345
    var settings = {
346
    view: {
347
                                showLine: false,
348
                                showIcon: false,
349
                                selectedMulti: false,
350
                                dblClickExpand: false,
351
                                addDiyDom: this.aideAddDiyDom
352
    },
353
    data: {
354
                                simpleData: {
355
                enable: true
356
                }
357
    },
358
    callback: {
359
                                beforeClick: this.aidePreClickMenu,
360
                onClick:this.aideClickMenu
361
    }
362
    };
363
 
364
    // Si pas de liste en entrée, fabrique une liste de test
365
    if (typeof zNodes =='undefined')
366
    {
367
        zNodes = [
368
                  {idAide:1, id:1, pId:0, name:"Première instance", open: true},
369
                  {idAide:2, id:2, pId:1, name:"Deuxième aide"},
370
                  {idAide:3, id:3, pId:1, name:"Lumière dans la nuit"},
371
                  {idAide:4, id:4, pId:3, name:"Tilt !!!!"},
372
                  {idAide:5, id:5, pId:3, name:"Et nous ?"},
373
                  {idAide:6, id:6, pId:5, name:"Fonction f( .. )"},
374
                  {idAide:7, id:7, pId:1, name:"Fin..."},
375
                  {idAide:8, id:8, pId:1, name:"Fin 2..."},
376
                  {idAide:9, id:9, pId:1, name:"Fin 3..."},
377
                  {idAide:10, id:10, pId:1, name:"Et puis zut, pas la fin !"},
378
                  {idAide:11, id:11, pId:1, name:"shuffle( .. )"},
379
                  {idAide:12, id:12, pId:1, name:"random()"},
380
        ];
381
    }
382
 
383
    this.zNodesAide = zNodes;
384
 
385
    if (typeof elementsAide=='undefined')
386
    {
387
        this.elementsAide = [];
388
        for (var i=0; i<zNodes.length; i++)
389
        {
390
            var chaineAide = "<div class=\"Rcl_Help_Title\"> Aide sur "+zNodes[i].name+"</div>";
391
            chaineAide += "<div>Test d'aide, l'identificateur de l'item est : "+zNodes[i].id+"</div>";
392
            chaineAide += "<div>Test d'aide, l'identificateur du parent de l'item est : "+zNodes[i].pId+"</div>";
393
            this.elementsAide.push(chaineAide);
394
        }
395
    }
396
    else
397
    {
398
        this.elementsAide = elementsAide;
399
    }
400
 
401
    // Fabrication du menu zTree
402
 
403
    var treeObj = $("<ul>", {
404
                    id: "aideMenu"+this.nom,
405
                    class: "ztree"
406
                    });
407
    var divAide = $("#divAide"+this.nom);
408
    divAide.prepend(treeObj);
409
 
410
    $.fn.zTree.init(treeObj, settings, this.zNodesAide);
411
    zTree_Menu = $.fn.zTree.getZTreeObj("aideMenu"+this.nom);
412
    curMenu = zTree_Menu.getNodes()[0];
413
    zTree_Menu.selectNode(curMenu);
414
 
415
    treeObj.hover(function () {
416
        if (!treeObj.hasClass("showIcon")) {
417
            treeObj.addClass("showIcon");
418
        }
419
    }, function() {
420
        treeObj.removeClass("showIcon");
421
    });
422
 
423
    // Affichage du premier élément
424
    divAide.append(this.elementsAide[0]);
425
 
426
}
427
 
428
 
429
Essaim.prototype.aideAddDiyDom = function(treeId, treeNode)
430
/*
431
 * Fonction de callback "addDiyDom" du menu zTree
432
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
433
 * Personalisation de l'apparence du noeud de menu zTree
434
 * parametre(s) :       - treeId : id du menu zTree
435
 *                      - treeNode : noeud du menu
436
 */
437
{
438
    var spaceWidth = 20; // ajoute des espaces à chaque niveau si le noeud n'est pas de niveau 0
439
    var switchObj = $("#" + treeNode.tId + "_switch"), icoObj = $("#" + treeNode.tId + "_ico");
440
    switchObj.remove();
441
    icoObj.before(switchObj);
442
 
443
    if (treeNode.level > 0) {
444
        var spaceStr = "<span style='display: inline-block;width:" + (spaceWidth * treeNode.level)+ "px'></span>";
445
        switchObj.before(spaceStr);
446
    }
447
}
448
 
449
Essaim.prototype.aidePreClickMenu = function(treeId, treeNode)
450
/*
451
 * Fonction de callback "beforeClick" du menu zTree
452
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
453
 * Extension des menus de niveau inférieur à 0 si on clique SUR L'ITEM
454
 * et pas seulement sur le triangle
455
 * parametre(s) :       - treeId : id du menu zTree
456
 *                      - treeNode : noeud du menu
457
 */
458
{
459
    if (treeNode.level == 0 ) {
460
        var zTree = $.fn.zTree.getZTreeObj(treeId);
461
        zTree.expandNode(treeNode);
462
    }
463
    return true;
464
}
465
 
466
Essaim.prototype.aideClickMenu = function(event, treeId, treeNode, clickFlag)
467
/*
468
 * Fonction de callback "onClick" du menu zTree
469
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
470
 * Affiche l'aide si clique sur le menu
471
 * parametre(s) :       - treeId : id du menu zTree
472
 *                      - treeNode : noeud du menu
473
 */
474
{
475
//    console.log("click sur élément "+treeNode.id+" de menu "+treeId);
476
    var nomEssaim = treeId.slice("aideMenu".length,treeId.length);
477
    var ind = rucheSys.rechercheIndice(nomEssaim,rucheSys.listeBlocPrepa);
478
    var essaim = rucheSys.listeBlocPrepa[ind];
479
    $("#"+treeId).nextAll().remove();
480
    $("#"+treeId).parent().append(essaim.elementsAide[treeNode.idAide-1]);
481
}
482
 
483
 
484
Essaim.prototype.menuDeroulInit = function(elemId, zNodes, classesItems)
485
/*
486
 * Initialisation d'un menu déroulant. Il peut y en avoir plusieurs.
487
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
488
 * parametre(s) :       - elemId : id de l'élément en dessous duquel on met le menu.
489
 *                      - zNodes : liste des noeuds cliquables (objet JSON).
490
 *                                      leur id doivent être dans l'ordre 1,2,..N
491
 *                      - classesItem : tableau des classes de composants
492
 */
493
{
494
    Essaim.nbMenuDeroul++; // nouveau menu...
495
    Essaim.classeItemMenuDeroul.push(classesItems); // enregistre le tableau des classes de composants
496
 
497
    // Construction du div contenant le menu. C'est lui qui sera invisible au départ
498
    // Voir les fonctions Essaim.prototype.showMenu() et hideMenu()
499
    var divMenuDeroul = $("<div>", {
500
                    id: "divMenuDeroul"+this.nom+"_"+Essaim.nbMenuDeroul,
501
                    class: "menuContent",
502
                    style: "display: none; position: absolute;"
503
        });
504
 
505
    // Initialisation des paramètres du menu zTree
506
    var curMenu = null, zTree_Menu = null;
507
    var settings = {
508
    view: {
509
                                showLine: false,
510
                                showIcon: false,
511
                                selectedMulti: false,
512
                                dblClickExpand: false,
513
                                addDiyDom: this.menuDeroulAddDiyDom
514
    },
515
    data: {
516
                                simpleData: {
517
                enable: true
518
                }
519
    },
520
    callback: {
521
                                beforeClick: this.menuDeroulPreClickMenu,
522
                onClick: this.menuDeroulClickMenu
523
    }
524
    };
525
 
526
    // Si pas de liste en entrée, fabrique une liste de test
527
    if (typeof zNodes =='undefined')
528
    {
529
        zNodes = [
530
                       { id:1, pId:0, name:"Liste composants 1", open: true},
531
                       { id:2, pId:1, name:"Composant 1"},
532
                       { id:3, pId:1, name:"Sous liste composants"},
533
                       { id:4, pId:3, name:"Composant S1"},
534
                       { id:5, pId:3, name:"Composant S2"},
535
                       { id:6, pId:3, name:"Composant S3"},
536
                       { id:7, pId:1, name:"Composant 2"},
537
                       { id:8, pId:1, name:"Composant 3"},
538
                       { id:9, pId:1, name:"Composant 4"},
539
                       { id:10, pId:1, name:"Composant 5"},
540
                       { id:11, pId:1, name:"Composant 6"},
541
                       { id:12, pId:1, name:"Composant 7"},
542
                       ];
543
    }
544
 
545
    // Fabrication du menu zTree
546
 
547
    var idMenu = "menuDeroul"+this.nom+"_"+Essaim.nbMenuDeroul;
548
    var treeObj = $("<ul>", {
549
                    id: idMenu,
550
                    class: "ztree ztreeMenuDeroul",
551
                    style: "margin-top: 0; width:160px;"
552
                    });
553
//    treeObj.css("overflow","hidden"); // pas de barre de défilement
554
    divMenuDeroul.append(treeObj); // la position du div est en "absolute"
555
    var pElem = $("#"+elemId);
556
    $("body").append(divMenuDeroul);
557
 
558
    $.fn.zTree.init(treeObj, settings, zNodes);
559
    zTree_Menu = $.fn.zTree.getZTreeObj(idMenu);
560
    curMenu = zTree_Menu.getNodes()[0];
561
    zTree_Menu.selectNode(curMenu);
562
 
563
    treeObj.hover(function () {
564
                  if (!treeObj.hasClass("showIcon")) {
565
                  treeObj.addClass("showIcon");
566
                  }
567
                  }, function() {
568
                  treeObj.removeClass("showIcon");
569
                  });
570
 
571
    return idMenu;
572
}
573
 
574
Essaim.prototype.menuDeroulIdFind = function(iMenuDeroul)
575
/*
576
 * Trouve l'id du menu deroulant numero iMenuDeroul de l'essaim courant
577
 * parametre(s) :   - iMenuDeroul : numero du menu deroulant dans l'essaim (convention décidée par le développeur)
578
 */
579
{
580
    kMenuDeroul = 0;
581
    var regex = new RegExp(this.nom);
582
    for (var i=0;i<this.idMenusDeroulants.length;i++)
583
    {
584
        if (regex.test(this.idMenusDeroulants[i])) {
585
            kMenuDeroul++;
586
            if (kMenuDeroul == iMenuDeroul) {
587
                return this.idMenusDeroulants[i];
588
            }
589
        }
590
    }
591
    return null;
592
}
593
 
594
Essaim.prototype.menuDeroulShow = function(menuId, parentId)
595
/*
596
 * Montre un menu déroulant (le fait apparaître).
597
 * parametre(s) :       - menuId : id du menu
598
 *                      - parentId : id de l'élément en dessous duquel le menu apparaît
599
 */
600
{
601
    var parentObj = $("#"+parentId);
602
    var menuOffset = parentObj.offset();
603
    $("#"+menuId).parent().css({left:menuOffset.left + "px", top:menuOffset.top + parentObj.outerHeight() + "px"}).slideDown("fast");
604
 
605
    // le prochain click n'importe où fera disparaître le menu
606
    $("body").bind("mousedown", Essaim.prototype.menuDeroulClicBodyCache);
607
}
608
 
609
Essaim.prototype.menuDeroulHide = function()
610
/*
611
 * Cache tous les menus déroulants (les fait disparaître).
612
 */
613
{
614
    $("[id^=divMenuDeroul]").fadeOut("fast");
615
    $("body").unbind("mousedown", Essaim.prototype.menuDeroulClicBodyCache);
616
}
617
 
618
Essaim.prototype.menuDeroulClicBodyCache = function(event)
619
/*
620
 * Cache un menu déroulant sur un click en dehors du menu.
621
 */
622
{
623
    // Laisse le menu si clic dedans ou sur le bouton
624
    if ( !(typeof $(event.target).parents(".menuContent")[0] != 'undefined' || $(event.target)[0].class == "Rcl_Editor_Button_Composant")) {
625
        Essaim.prototype.menuDeroulHide.call(this);
626
    }
627
}
628
 
629
Essaim.prototype.menuDeroulPreClickMenu = function(treeId, treeNode)
630
/*
631
 * Fonction de callback "beforeClick" des menus déroulants
632
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
633
 * parametre(s) :       - treeId : id du menu zTree
634
 *                      - treeNode : noeud du menu
635
 * Fonction virtuelle, doit être surchargée dans la classe fille
636
 */
637
{
638
//    console.log("pre-click sur élément "+treeNode.id+" de menu "+treeId);
639
}
640
 
641
 
642
Essaim.prototype.menuDeroulClickMenu = function(event, treeId, treeNode, clickFlag)
643
/*
644
 * Fonction de callback "onClick" des menus déroulants
645
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
646
 * parametre(s) :       - treeId : id du menu zTree
647
 *                      - treeNode : noeud du menu
648
 *                      - clickFlag : le noeud est sélectionné ou non (si checkbox activé). Ne nous sert pas ici
649
 * Fonction virtuelle, doit être surchargée dans la classe fille
650
 */
651
{
652
//    console.log("click sur élément "+treeNode.id+" de menu "+treeId+", clickFlag = "+clickFlag);
653
 
654
    // récupère le numéro du menu déroulant, qui est le numéro derrière le "_" à la fin de treeId
655
    var numMenuDeroul = treeId.match(/_[0-9]*$/)[0];
656
    numMenuDeroul = numMenuDeroul.slice(1,numMenuDeroul.length);
657
 
658
    // récupère l'essaim
659
    var nomEssaim = treeId.slice("menuDeroul".length,treeId.length);
660
    nomEssaim = nomEssaim.slice(0,-numMenuDeroul.length-1);
661
    var ind = rucheSys.rechercheIndice(nomEssaim,rucheSys.listeBlocPrepa);
662
    var essaim = rucheSys.listeBlocPrepa[ind];
663
 
664
    // cache le menu lorsqu'on a cliqué
665
    essaim.menuDeroulHide();
666
 
667
    // Fait exécuter l'action commandée par l'essaim
668
    // pour le moment, il n'y a que des "composants"
669
    // qui sont pointés par des actions de menus déroulants
670
    var classeComposant = (Essaim.classeItemMenuDeroul[numMenuDeroul-1])[treeNode.idAction];
671
 
672
    // Appel de la méthode "nouveauComposant" de la classe essaim fille...
673
    // ... qui devrait savoir quoi en faire
674
    essaim.nouveauComposant(classeComposant);
675
}
676
 
677
 
678
Essaim.prototype.nouveauComposant = function(classeComposant)
679
/*
680
 * construit un nouveau composant de classe "classeComposant"
681
 * correspondant à cet essaim
682
 */
683
{
684
    // par exemple (dans classe dérivée...
685
    // va s'enregistrer dans l'objet système rucheSys
686
    // rucheSys.ajoutComposantEssaim(nomEdit, classeComposant)
687
}
688
 
689
 
690
Essaim.prototype.menuDeroulAddDiyDom = function(treeId, treeNode)
691
/*
692
 * Fonction de callback "addDiyDom" des menus déroulants
693
 * Utilisation du plugin jquery zTree : http://www.ztree.me/
694
 * Personalisation de l'apparence du noeud de menu zTree
695
 * parametre(s) :       - treeId : id du menu zTree
696
 *                      - treeNode : noeud du menu
697
 */
698
{
699
    var spaceWidth = 10; // ajoute des espaces à chaque niveau si le noeud n'est pas de niveau 0
700
    var switchObj = $("#" + treeNode.tId + "_switch"), icoObj = $("#" + treeNode.tId + "_ico");
701
    switchObj.remove();
702
    icoObj.before(switchObj);
703
 
704
    if (treeNode.level > 0) {
705
        var spaceStr = "<span style='display: inline-block;width:" + (spaceWidth * treeNode.level)+ "px'></span>";
706
        switchObj.before(spaceStr);
707
    }
708
}
709
 
710
 
711
Essaim.prototype.initEnonce = function()
712
/*
713
 * Initialisation de la partie "énoncé" de l'essaim
714
 * ajoute un bouton dans la liste d'Essaims
715
 * Voir dans l'essaim "QCM" l'exemple d'une surcharge de cette fonction
716
 */
717
{
718
    var tab = document.getElementById('Rid_Enonce_Essaims_List');
719
    var li = document.createElement('li');
720
    li.id = "RidEnEs_"+this.nom;
721
 
722
    // Bouton ajouté dans la liste des "actions d'Essaim" de l'énoncé
723
    var bouton = document.createElement('button');
724
    bouton.id = "boutonEssaimEnonce"+this.nom;
725
    bouton.className = "Rcl_Surligne_Essaim";
726
 
727
    /* Modif 2016 : mise en place du drag and drop */
728
    bouton.draggable = true; //Permet de rendre le boutton déplacable.
729
 
730
    //permet d'envoyer des données à la zone de drop
731
    bouton.addEventListener('dragstart', function(e) {
732
 
733
        e.dataTransfer.setData("texte", bouton.id);
734
 
735
    });
736
 
737
    //clonedElement = draggedElement.cloneNode(true);  //On fais en sorte que l'élément soit cloné
738
    /* Fin des modifs */
739
    var txt = document.createTextNode( this.nom );
740
    bouton.appendChild(txt);
741
 
742
    bouton.onclick = function(){
743
        nomEssaim = li.id.slice("RidEnEs_".length,li.id.length); // On supprime le "liEssaim" devant le nom de la variable
744
        var ind = rucheSys.rechercheIndice(nomEssaim,rucheSys.listeBlocPrepa);
745
 
746
        // Si gère réponse, ne peut pas créer deux images "essaim" à la fois
747
        if (rucheSys.listeBlocPrepa[ind].gereReponse == true)
748
        {
749
            // recherche si image essaim existe déjà
750
            if (document.getElementsByClassName("nomEssaim"+rucheSys.listeBlocPrepa[ind].nom).length == 0)
751
            {
752
                rucheSys.listeBlocPrepa[ind].initEnonceVersAnalyse(); // ajoute une réponse correspondant à l'essaim
753
                rucheSys.enonce.ajoutImageEssaim(rucheSys.listeBlocPrepa[ind]);
754
            }
755
            else
756
            {
757
                alert("Cet essaim gère une réponse. Il ne peut en gérer plusieurs");
758
            }
759
        }
760
        else
761
        {
762
            rucheSys.enonce.ajoutImageEssaim(rucheSys.listeBlocPrepa[ind]);
763
        }
764
    }
765
 
766
    li.appendChild(bouton);
767
    tab.appendChild(li);
768
 
769
}
770
 
771
 
772
Essaim.prototype.initEnonceVersAnalyse = function()
773
/*
774
 * Initialisation de la partie "analyse" de l'essaim
775
 * lorsqu'on clique sur le bouton "essaim" de l'énoncé
776
 * de façon générique, ajoute un bloc réponse dans l'onglet "Analyse"
777
 * peut aussi faire des tas d'autres choses dans les essaims dérivés
778
 * Voir dans l'essaim "QCM" l'exemple d'une surcharge de cette fonction
779
 */
780
{
781
    rucheSys.ajoutReponseEssaim(this);
782
}
783
 
784
 
785
Essaim.prototype.initAnalyse = function()
786
/*
787
 * Initialisation de la partie "analyse" de l'essaim
788
 * de façon générique, ne fait rien
789
 * Voir dans l'essaim "QCM" l'exemple d'une surcharge de cette fonction
790
 */
791
{
792
    console.log("Essaim virtuel "+this.nom+", initialisation de la partie Analyse");
793
}
794
 
795
Essaim.prototype.sauveEtatInterfaceReponse = function()
796
/*
797
 * Sauvegarde l'état de l'interface du bloc réponse dans les variables internes
798
 * de l'essaim. Sert juste avant la sauvegarde, permet de rétablir l'état au rechargement
799
 */
800
{
801
    // fonction virtuelle ici
802
}
803
 
804
Essaim.prototype.chargeEtatInterfaceReponse = function(elem)
805
/*
806
 * Chargement de l'état de l'interface du bloc réponse depuis les variables de l'objet JSON elem
807
 * parametre(s) :    - elem : objet JSON
808
 */
809
{
810
    // fonction virtuelle ici
811
}
812
 
813
Essaim.prototype.sauveEtatInterface = function()
814
/*
815
 * Sauvegarde l'état de l'interface du bloc Essaim (boutons éventuels, sélecteurs...)
816
 * dans les variables internes de l'essaim.
817
 * Sert juste avant la sauvegarde, permet de rétablir l'état au rechargement
818
 */
819
{
820
    // fonction virtuelle ici
821
}
822
 
823
Essaim.prototype.creerBloc = function(dataRecup)
824
/*
825
 * Méthode qui permet de créer un bloc essaim dans l'onglet préparation
826
 * fonction générique, ne crée "que" le div cadre,
827
 * les boutons de suppression, déplacement du bloc, etc...
828
 * à utiliser dans l'essaim dérivé (voir exemple QCM)
829
 * dataRecup : contient l'élément éventuel sauvegardé
830
 */
831
{
832
    this.initBloc();
833
 
834
    var titreBloc = document.createElement("DIV");
835
    var txt = document.createTextNode("Essaim virtuel");
836
    titreBloc.appendChild(txt);
837
    titreBloc.style.textAlign="center";
838
 
839
    this.divBloc.appendChild(titreBloc);
840
 
841
    this.initEnonce();
842
 
843
    this.initAnalyse();
844
}
845
 
846
 
847
Essaim.prototype.chargeEtat = function(elem)
848
/*
849
 * Chargement de l'état de l'objet depuis les variables de l'objet JSON elem
850
 * parametre(s) :    - elem : objet JSON
851
 */
852
{
853
    // fonction virtuelle ici
854
}
855
 
856
 
857
Essaim.prototype.creerBlocReponse = function(dataRecup)
858
/*
859
 * Création d'un bloc réponse dans l'onglet analyse
860
 * géré par cet essaim.
861
 * paramètre(s) :       - dataRecup : données éventuelles pour le chargement à partir d'une sauvegarde
862
 *
863
 * fonction générique, ne crée "que" le div cadre,
864
 * les boutons de base du bloc, etc...
865
 * pas de bouton de suppression, il faut que l'essaim s'en charge
866
 * si c'est nécessaire... ou pas !
867
 * à surcharger dans l'essaim dérivé (voir exemple QCM)
868
 */
869
{
870
    // Récupère le div du bloc réponse
871
    var listeBloc = document.getElementsByClassName("divRep"+this.nom);
872
    var bloc = listeBloc[0];
873
 
874
    var titreBloc = document.createElement("DIV");
875
    var txt = document.createTextNode("Réponse envoyée par l'essaim "+this.nom);
876
    titreBloc.appendChild(txt);
877
    titreBloc.style.textAlign="center";
878
 
879
    bloc.appendChild(titreBloc);
880
}
881
 
882
 
883
Essaim.prototype.detruitBloc = function()
884
/*
885
 * Destruction du bloc et de toutes les dépendances (boutons, réponses...)
886
 *
887
 * *********** ATTENTION : si d'autres variables sont définies par la classe fille,
888
 * ***********             les détruire dans celle-ci  ********
889
 *
890
 *
891
 */
892
{
893
    rucheSys.supprInstruction(this.nom,rucheSys.listeBlocPrepa);
894
    if ( document.getElementById("RidEnEs_"+this.nom) != null ) {
895
        document.getElementById("RidEnEs_"+this.nom).remove();
896
    }
897
 
898
    // Destruction des images correspondantes dans les éditeurs.
899
    if (!(this.gereReponse))
900
    {
901
        $("img.nomEssaim"+this.nom).remove();
902
    }
903
 
904
    // Destruction du bouton énoncé lié à l'essaim
905
    $("li#RidEnEs_"+this.nom).remove();
906
 
907
    // Destruction de la réponse
908
    if (this.gereReponse)
909
    {
910
        this.supprimeReponse(this.chercheNomReponse());
911
    }
912
 
913
}
914
 
915
Essaim.prototype.supprimeReponse = function(id)
916
/*
917
 * Suppression d'une réponse liée à un essaim.
918
 * Si d'autres variables sont définies dans la classe fille et associées
919
 * à la réponse (par exemple des éditeurs), elles devront être détruites
920
 * dans cette classe fille.
921
 * parametres - id : id de la réponse à supprimer, de la forme "reponseXXXX"
922
 */
923
{
924
    // supprime la réponse dans la liste des réponses
925
    var indice = rucheSys.rechercheIndice(id, rucheSys.listeReponse);
926
 
927
    if (indice<0) // si réponse pas encore affichée
928
    {
929
        return;
930
    }
931
 
932
    rucheSys.listeReponse.splice(indice, 1);
933
 
934
    // supprime le bloc html
935
    var idBlocRepAnalyse = "#RidAnBlocRep_"+id;
936
    $(idBlocRepAnalyse).remove();  // détruit le bloc
937
 
938
    // supprime l'image si elle existe dans l'éditeur principal
939
    $("img#"+id).remove();
940
 
941
    // remet l'avertissement si plus de réponse
942
    if (rucheSys.listeReponse.length==0)
943
    {
944
        $("#Rid_Warning_No_Answer").css('display','inline-block');
945
    }
946
 
947
    rucheSys.verifReponse(); // reordonne les réponses restantes
948
}
949
 
950
 
951
Essaim.prototype.chercheNomReponse = function()
952
/*
953
 * Récupère le nom de la réponse gérée par cet essaim si il existe.
954
 */
955
{
956
    var nomRep = "";
957
    if (!(this.gereReponse)) {
958
        return nomRep;
959
    }
960
 
961
    // teste toutes les réponses pour savoir laquelle est gérée par cet essaim
962
 
963
    for (var i=0; i<rucheSys.listeReponse.length; i++)
964
    {
965
        if (rucheSys.listeReponse[i].format != null) {
966
            if (rucheSys.listeReponse[i].format.nomEssaimGerant == this.nom)
967
            {
968
                var nomRep = rucheSys.listeReponse[i].format.nom;
969
            }
970
        }
971
    }
972
    return nomRep;
973
}
974
 
975
 
976
//---------------------------------//
977
 
978
    Essaim.prototype.reduireBloc = function()
979
    {
980
        console.log(this.nom);
981
        if(document.getElementById("Rid_Button_MiniMaxi_"+this.nom).className=="Rcl_Button_Minimize")
982
        {
983
            document.getElementById("RidPrBloc_"+this.nom).className = "Rcl_Bloc_Essaim Rcl_Closed";
984
            document.getElementById("Rid_Button_MiniMaxi_"+this.nom).className="Rcl_Button_Maximize";
985
 
986
        }
987
    }
988
 
989
    Essaim.prototype.agrandirBloc =function()
990
    {
991
        if(document.getElementById("Rid_Button_MiniMaxi_"+this.nom).className=="Rcl_Button_Maximize")
992
            {
993
                document.getElementById("Rid_Button_MiniMaxi_"+this.nom).className= "Rcl_Button_Minimize";
994
                document.getElementById("RidPrBloc_"+this.nom).className = "Rcl_Bloc_Essaim Rcl_Bloc";
995
            }
996
    }
997
 
998
 
999
 
1000
 
1001
        //---------------------------------//
1002
 
1003
 
1004
Essaim.prototype.toOEF = function()
1005
/*
1006
 * Fonction qui permet de générer le code OEF de l'essaim, partie préparation
1007
 * retourne une chaine de caractère contenant le code OEF.
1008
 * fonction générique.
1009
 * Voir dans l'essaim "QCM" l'exemple d'une surcharge de cette fonction
1010
 */
1011
{
1012
 
1013
    // Construit le code OEF
1014
    var codePrepEssaim = "\n// Code envoyé par l'essaim vide "+this.nom+"\n";
1015
 
1016
    return codePrepEssaim;
1017
}
1018
 
1019
Essaim.prototype.toOEFFromStatement = function(idReponse)
1020
/*
1021
 * Fonction qui permet de générer le code OEF correspondant
1022
 * à l'action de l'essaim dans le statement.
1023
 * paramètre(s) :    - idReponse = "reponseXXX" où XXX est le numéro (donc l'ordre) de la réponse
1024
 * retourne une chaine de caractère contenant le code OEF.
1025
 * fonction générique.
1026
 * Voir dans l'essaim "QCM" l'exemple d'une surcharge de cette fonction
1027
 */
1028
{
1029
 
1030
    // Construit le code OEF
1031
 
1032
    var codePrepEssaim = "<div>Sortie de l'essaim "+this.nom+" dans l'énoncé</div>";
1033
 
1034
    // Construit le numéro de la réponse gérée par l'essaim dans l'ordre d'apparition (ordre dans l'analyse)
1035
    var numeroReponse = $("#RidAnBlocRep_"+this.nom).index()+1;
1036
 
1037
    codePrepEssaim += "<div>L'essaim "+this.nom+" gère la réponse "+numeroReponse+"</div>";
1038
 
1039
    return codePrepEssaim;
1040
}
1041
 
1042
Essaim.prototype.toOEFFromAnswer = function()
1043
/*
1044
 * Fonction qui permet de générer le code OEF correspondant
1045
 * à la réponse gérée par l'essaim dans l'analyse
1046
 * retourne une chaine de caractères contenant le code OEF.
1047
 * fonction générique.
1048
 * Voir dans l'essaim "QCM" l'exemple d'une surcharge de cette fonction
1049
 */
1050
{
1051
 
1052
    // Construit le code OEF
1053
 
1054
    var codePrepEssaim = "\n// Code OEF de la réponse gérée par l'essaim "+this.nom+"\n";
1055
//    codePrepEssaim += "answer{}{}{}{}";
1056
 
1057
    return codePrepEssaim;
1058
}
1059
 
1060
/*
1061
 * Déclaration du type d'essaim (enregistre la classe dans l'objet système Ruche)
1062
 * au chargement du code. IMPORTANT : le code des classes dérivées
1063
 * doit être chargé APRES le code de la classe "Essaim" de base.
1064
 */
1065
 
1066
// ne charge pas cet Essaim, il est virtuel
1067
// rucheSys.initClasseEssaim(Essaim);
1068
 
1069
 
1070
Essaim.prototype.trouverSuivant = function(source,cible)
1071
/*
1072
* Pour le drag and drop
1073
* Sert à trouver si le bloc pointé suit le bloc source, et renvoi la longueur à laquelle il se trouve si il est bien suivant.
1074
* Paramètres :
1075
* - source : Le bloc qu'on drag sur un autre bloc
1076
* - cible : le bloc sur lequel on relache le bloc dragué
1077
*/
1078
{        
1079
    var cpt = 0;
1080
    var next = source;
1081
    var trouve = false;
1082
 
1083
    while(next != null && !trouve)
1084
    {
1085
        next = next.nextElementSibling;//l'élément suivant le bloc droppé
1086
        cpt++;
1087
        if (next==cible)
1088
         {
1089
            trouve = true;
1090
         }
1091
 
1092
    }
1093
 
1094
    //cpt++;
1095
 
1096
    if (!trouve)
1097
    {
1098
        cpt =0;
1099
    }
1100
    console.log("Le bloc visé et de "+cpt+" bloc après.")
1101
 
1102
    return cpt;
1103
}
1104
 
1105
Essaim.prototype.trouverPrecedent = function(source,cible)
1106
/*
1107
* Pour le drag and drop
1108
* Sert à trouver si le bloc pointé precede le bloc source, et renvoi le nombre de bloc à laquelle il se trouve si il est bien precedent.
1109
* Paramètres :
1110
* - source : Le bloc qu'on drag sur un autre bloc
1111
* - cible : le bloc sur lequel on relache le bloc dragué
1112
*/
1113
{        
1114
    var cpt = 0;
1115
    var prev = source;
1116
    var trouve = false;
1117
 
1118
    while(prev != null && !trouve)
1119
    {
1120
        //next = next.nextElementSibling;//l'élément suivant le bloc droppé
1121
        prev = prev.previousElementSibling;
1122
        cpt++;
1123
        if (prev==cible)
1124
         {
1125
            trouve = true;
1126
         }
1127
 
1128
    }
1129
 
1130
    if (!trouve)
1131
    {
1132
        cpt =0;
1133
    }
1134
    console.log("Le bloc visé et de "+cpt+" bloc avant.")
1135
 
1136
    return cpt;
1137
}