/**
 * @version $Id$
 * @author Thomas Crespin <thomas.crespin@sesamath.net>
 * @copyright Thomas Crespin 2009-2022
 * 
 * ****************************************************************************************************
 * SACoche <http://sacoche.sesamath.net> - Suivi d’Acquisitions de Compétences
 * © Thomas Crespin pour Sésamath <http://www.sesamath.net> - Tous droits réservés.
 * Logiciel placé sous la licence libre Affero GPL 3 <https://www.gnu.org/licenses/agpl-3.0.html>.
 * ****************************************************************************************************
 * 
 * Ce fichier est une partie de SACoche.
 * 
 * SACoche est un logiciel libre ; vous pouvez le redistribuer ou le modifier suivant les termes 
 * de la “GNU Affero General Public License” telle que publiée par la Free Software Foundation :
 * soit la version 3 de cette licence, soit (à votre gré) toute version ultérieure.
 * 
 * SACoche est distribué dans l’espoir qu’il vous sera utile, mais SANS AUCUNE GARANTIE :
 * sans même la garantie implicite de COMMERCIALISABILITÉ ni d’ADÉQUATION À UN OBJECTIF PARTICULIER.
 * Consultez la Licence Publique Générale GNU Affero pour plus de détails.
 * 
 * Vous devriez avoir reçu une copie de la Licence Publique Générale GNU Affero avec SACoche ;
 * si ce n’est pas le cas, consultez : <http://www.gnu.org/licenses/>.
 * 
 */

// Activer le mode strict afin de tendre vers un code rigoureux
'use strict';

// Variables globales à ne pas définir plus tard sinon la minification les renomme et cela pose ensuite souci.
var tab_items         = [];
var tab_profs         = [];
var tab_eleves        = [];
var tab_sujet         = [];
var tab_corrige       = [];
var tab_sujet_perso   = [];
var tab_corrige_perso = [];
var tab_cell          = [];
var tab_equipe        = [];

// jQuery !
$(document).ready
(
  function()
  {

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Initialisation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    var mode                  = false;
    var modification          = false;
    var memo_presentation     = 'tableau';
    var memo_pilotage         = 'clavier';
    var memo_direction        = 'down';
    var memo_input_id         = false;
    // var memo_eleve            = 0; // déjà défini de façon globale par script.js car besoin dans script.js
    var colonne               = 1;
    var ligne                 = 1;
    var nb_colonnes           = 1;
    var nb_lignes             = 1;
    var nb_lignes_max         = 20;
    var nb_caracteres_max     = 2000;
    var audio_duree_restante  = 0;
    var obj_table_saisir_voir = $('#table_saisir_voir');
    var obj_plan_saisir_voir  = $('#ul_plan');
    var item_reste            = { 'liste' : '' , 'nombre' : 0 };
    var nb_notes              = 0;

    var i_col_date           = 0;
    var i_col_devoir_visible = 1;
    var i_col_saisie_visible = 2;
    var i_col_autoeval       = 3;
    var i_col_groupe         = 4;
    var i_col_description    = 5;
    var i_col_items          = 6;
    var i_col_profs          = 7;
    var i_col_diagnostic     = 8;
    var i_col_pluriannuel    = 9;
    var i_col_repartition    = 10;
    var i_col_fichiers       = 11;
    var i_col_remplissage    = 12;
    var i_col_icones         = 13;

    // tri du tableau (avec jquery.tablesorter.js).
    // les variables i_col_* ci-dessus ne peuvent pes être utilisées ici...
    var sorting = (window.TYPE=='groupe') ? [[0,1],[4,0]] : [[0,1],[5,0]] ;
    $('#table_action').tablesorter({ sortLocaleCompare : true, headers:{
      0:{sorter:'date_fr'},
      1:{sorter:false},
      2:{sorter:false},
      3:{sorter:false},
      6:{sorter:false},
      7:{sorter:false},
      8:{sorter:false},
      9:{sorter:false},
      10:{sorter:false}
    } });
    var tableau_tri = function(){ $('#table_action').trigger( 'sorton' , [ sorting ] ); };
    var tableau_maj = function(){ $('#table_action').trigger( 'update' , [ true ] ); };
    tableau_tri();

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Fonctions utilisées
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function activer_boutons_upload(ref)
    {
      $('#zone_upload button').prop('disabled',false);
      if(!tab_sujet[ref])     {$('#bouton_supprimer_sujet').prop('disabled',true);}
      if(!tab_corrige[ref]) {$('#bouton_supprimer_corrige').prop('disabled',true);}
    }

    function maj_choix_tri_eleves()
    {
      var groupe_id = $('#f_groupe option:selected').val().substring(1);
      if(groupe_id)
      {
        var groupe_type = $('#f_groupe option:selected').parent().attr('label');
        var nb_options_possibles = 0;
        $('#f_eleves_ordre option').each
        (
          function()
          {
            var value = $(this).val();
            if( (value=='nom') || (value=='prenom') )
            {
              $(this).prop('disabled',false);
              nb_options_possibles++;
            }
            else if(value=='classe')
            {
              if(groupe_type=='Classes')
              {
                $(this).prop('disabled',true).prop('selected',false);
              }
              else
              {
                $(this).prop('disabled',false);
                nb_options_possibles++;
              }
            }
            else
            {
              var plan_groupe = $(this).data('data');
              if(groupe_id==plan_groupe)
              {
                $(this).prop('disabled',false);
                nb_options_possibles++;
              }
              else
              {
                $(this).prop('disabled',true).prop('selected',false);
              }
            }
          }
        );
        $('#bloc_ordre').hideshow( nb_options_possibles > 1 );
        $('#bloc_equipe').hideshow( $('#f_eleves_ordre option:selected').data('data') );
      }
      else
      {
        $('#bloc_ordre').hide();
      }
    }

    function indication_periode()
    {
      if(window.TYPE=='groupe')
      {
        $('#indication_periode').html('');
        var id_groupe = $('#f_groupe option:selected').val().substring(1);
        var date_sql  = test_dateITA( $('#f_date_devoir').val() , true );
        if( date_sql && (typeof(window.tab_groupe_periode[id_groupe])!='undefined') )
        {
          var tab_indication = [];
          for(var id_periode in window.tab_groupe_periode[id_groupe]) // Parcourir un tableau associatif...
          {
            var tab_split = window.tab_groupe_periode[id_groupe][id_periode].split('_');
            if( (date_sql>=tab_split[0]) && (date_sql<=tab_split[1]) )
            {
              tab_indication.push( $('#f_aff_periode option[value='+id_periode+']').html() );
            }
          }
          var indication = ( tab_indication.length ) ? tab_indication.join(' + ') : 'Hors-période définie' ;
          $('#indication_periode').html( indication );
        }
        else if( (id_groupe) && date_sql )
        {
          $('#indication_periode').html('(pas de période associée au regroupement)');
        }
      }
    }

    function afficher_form_gestion( mode , ref , date_devoir , date_devoir_visible , date_saisie_visible , date_autoeval , time_autoeval , groupe_val , groupe_nom , eleve_nombre , eleve_liste , eleves_ordre , equipe , prof_nombre , prof_liste , description , compet_nombre , compet_liste , diagnostic , pluriannuel , repartition , doc_sujet , doc_corrige , sujets_nombre , corriges_nombre , copies_nombre , fini , proprio_id )
    {
      // Éviter, en cas de duplication d’évaluation dont on n’est pas le propriétaire, de se retrouver avec des complications
      // (droit du propriétaire d’origine ? évaluations en exemplaires multiples pour les autres ?)
      if( (mode=='dupliquer') && (window.USER_ID!=proprio_id) )
      {
        prof_nombre = 'non';
        prof_liste = '';
      }
      // Choix des collègues à masquer en cas de modification d’une évaluation dont on n’est pas le propriétaire
      // (ingérable sinon : on apparait comme propriétaire, le vrai propriétaire n’apparait pas comme tel...)
      $('#choisir_prof'    ).hideshow( (mode!='modifier') || (window.USER_ID==proprio_id) );
      $('#choisir_prof_non').hideshow( (mode=='modifier') && (window.USER_ID!=proprio_id) );
      $('#f_action').val(mode);
      $('#f_ref').val(ref);
      $('#f_date_devoir').val(date_devoir);
      if(eleves_ordre)
      {
        $('#f_eleves_ordre option[value='+eleves_ordre+']').prop('selected',true);
        var check_equipe = equipe ? true : false ;
        $('#f_equipe').prop('checked',check_equipe)
      }
      if(window.TYPE=='groupe')
      {
        var selected_groupe = (mode=='ajouter') ? window.select_groupe.replace('value="'+groupe_val+'"','value="'+groupe_val+'" selected') : window.select_groupe.replace('>'+groupe_nom,' selected>'+groupe_nom) ;
        $('#f_groupe').html(selected_groupe);
        maj_choix_tri_eleves();
        indication_periode();
      }
      else
      {
        $('#f_eleve_nombre').val(eleve_nombre);
        $('#f_eleve_liste').val(eleve_liste);
      }
      $('#f_prof_nombre').val(prof_nombre);
      $('#f_prof_liste').val(prof_liste);
      $('#f_description').val(description);
      $('#f_compet_nombre').val(compet_nombre);
      $('#f_compet_liste').val(compet_liste);
      $('#f_doc_sujet').val(doc_sujet);
      $('#f_doc_corrige').val(doc_corrige);
      $('#f_sujets_nombre').val(sujets_nombre);
      $('#f_corriges_nombre').val(corriges_nombre);
      $('#f_copies_nombre').val(copies_nombre);
      $('#f_fini').val(fini);
      // répartition
      if(repartition=='non')
      {
        $('#f_voir_repartition_non').prop('checked',true)
      }
      else
      {
        $('#f_voir_repartition_oui').prop('checked',true)
      }
      // diagnostic
      if(diagnostic=='non')
      { 
        $('#f_diagnostic').prop('checked',false).next().show(0).next().hide(0);
      }
      else
      {
        $('#f_diagnostic').prop('checked',true).next().hide(0).next().show(0);
      }
      // pluriannuel
      if(pluriannuel=='non')
      { 
        $('#f_pluriannuel').prop('checked',false).next().show(0).next().hide(0);
      }
      else
      {
        $('#f_pluriannuel').prop('checked',true).next().hide(0).next().show(0);
      }
      // dates de visibilité
      if( test_dateITA(date_devoir_visible) )
      {
        $('#f_choix_devoir_visible option[value=perso]').prop('selected',true);
        $('#f_date_devoir_visible').val(date_devoir_visible).parent().show(0);
      }
      else
      {
        $('#f_choix_devoir_visible option[value='+date_devoir_visible+']').prop('selected',true);
        $('#f_date_devoir_visible').val('').parent().hide(0);
      }
      if( test_dateITA(date_saisie_visible) )
      {
        $('#f_choix_saisie_visible option[value=perso]').prop('selected',true);
        $('#f_date_saisie_visible').val(date_saisie_visible).parent().show(0);
      }
      else
      {
        $('#f_choix_saisie_visible option[value='+date_saisie_visible+']').prop('selected',true);
        $('#f_date_saisie_visible').val('').parent().hide(0);
      }
      // heure fin auto-évaluation
      var heure_autoeval  = time_autoeval.substring(0,2);
      var minute_autoeval = time_autoeval.substring(3,5);
      $('#f_heure_autoeval').val(heure_autoeval);
      $('#f_minute_autoeval').val(minute_autoeval);
      // date fin auto-évaluation
      if(date_autoeval=='non')
      {
        $('#box_autoeval').prop('checked',true).next().show(0);
        $('#f_date_autoeval').val('00/00/0000').parent().hide(0);
      }
      else
      {
        $('#box_autoeval').prop('checked',false).next().hide(0);
        $('#f_date_autoeval').val(date_autoeval).parent().show(0);
      }
      // pour finir
      var h2 = (mode!='supprimer_pluriannuel') ? mode[0].toUpperCase() + mode.substring(1) + ' une évaluation' : 'Retirer une évaluation pluriannuelle' ;
      $('#form_gestion h2').html(h2);
      $('#p_duplication_multiple').hideshow( mode == 'dupliquer' );
      $('#gestion_delete_identite').html( escapeHtml(description) );
      $('#gestion_delete_identite_pluriannuel').html( escapeHtml(description) );
      $('#gestion_edit').hideshow( mode != 'supprimer' && mode != 'supprimer_pluriannuel' );
      $('#gestion_delete').hideshow( mode == 'supprimer' );
      $('#gestion_delete_pluriannuel').hideshow( mode == 'supprimer_pluriannuel' );
      $('#alerte_groupe').hide(0);
      $('#ajax_msg_gestion').removeAttr('class').html('');
      $('#form_gestion label[generated=true]').removeAttr('class').html('');
      $.fancybox( { href:'#form_gestion' , modal:true , minWidth:700 } );
      if(mode=='ajouter') { $('#f_description').focus(); }
    }

    /**
     * Ajouter une évaluation : mise en place du formulaire
     * @return void
     */
    var ajouter = function()
    {
      mode = $(this).attr('class');
      // Report des valeurs transmises via un formulaire depuis un tableau de synthèse bilan (1er affichage seulement)
      if(window.reception_todo)
      {
        window.reception_todo = false;
      }
      else
      {
        window.reception_users_texte = 'aucun';
        window.reception_items_texte = 'aucun';
        window.reception_users_liste = '';
        window.reception_items_liste = '';
      }
      var groupe_val = (window.TYPE=='groupe') ? $('#f_aff_classe option:selected').val() : '' ;
      // Afficher le formulaire
      afficher_form_gestion( mode , '' /*ref*/ , '' /*date_devoir*/ , 'toujours' /*date_devoir_visible*/ , 'toujours' /*date_saisie_visible*/ , 'non' /*date_autoeval*/ , '23:59' /*time_autoeval*/ , groupe_val , '' /*groupe_nom*/ , window.reception_users_texte /*eleve_nombre*/ , window.reception_users_liste /*eleve_liste*/ , '' /*eleves_ordre*/ , '' /*equipe*/ , window.remplacement_nombre /*prof_nombre*/ , window.remplacement_liste /*prof_liste*/ , '' /*description*/ , window.reception_items_texte /*compet_nombre*/ , window.reception_items_liste /*compet_liste*/ , 'non' /*diagnostic*/  , 'non' /*pluriannuel*/ , window.repartition_default , '' /*doc_sujet*/ , '' /*doc_corrige*/ , 0 /*sujets_nombre*/ , 0 /*corriges_nombre*/ , 0 /*copies_nombre*/ , '' /*fini*/ , window.USER_ID /*proprio_id*/ );
    };

    /**
     * Modifier | Dupliquer une évaluation : mise en place du formulaire
     * @return void
     */
    var modifier_dupliquer = function()
    {
      mode = $(this).attr('class');
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref                  = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir          = objet_tds.eq(i_col_date).html();
      var choix_devoir_visible = objet_tds.eq(i_col_devoir_visible).data('option');
      var date_devoir_visible  = (choix_devoir_visible!='perso') ? choix_devoir_visible : objet_tds.eq(i_col_devoir_visible).html() ;
      var choix_saisie_visible = objet_tds.eq(i_col_saisie_visible).data('option');
      var date_saisie_visible  = (choix_saisie_visible!='perso') ? choix_saisie_visible : objet_tds.eq(i_col_saisie_visible).html() ;
      var date_autoeval        = objet_tds.eq(i_col_autoeval).html();
      var time_autoeval        = objet_tds.eq(i_col_autoeval).data('time');
      if(window.TYPE=='groupe')
      {
        var groupe_nom    = objet_tds.eq(i_col_groupe).html();
        var eleve_nombre  = '';
        var eleve_liste   = '';
      }
      else
      {
        var groupe_nom    = '';
        var eleve_nombre  = objet_tds.eq(i_col_groupe).text().trim();
        var eleve_liste   = tab_eleves[ref];
      }
      var eleves_ordre    = objet_tds.eq(i_col_groupe).data('ordre');
      var equipe          = objet_tds.eq(i_col_groupe).data('equipe');
      var prof_nombre     = objet_tds.eq(i_col_profs).text().trim();
      var proprio_id      = objet_tds.eq(i_col_profs).data('proprio');
      var description     = objet_tds.eq(i_col_description).html();
      var compet_nombre   = objet_tds.eq(i_col_items).text().trim();
      var diagnostic      = objet_tds.eq(i_col_diagnostic).html();
      var pluriannuel     = objet_tds.eq(i_col_pluriannuel).html();
      var repartition     = objet_tds.eq(i_col_repartition).html();
      var sujets_nombre   = (mode=='dupliquer') ? 0 : objet_tds.eq(i_col_fichiers).children('span[data-objet=sujets]').data('nb') ;
      var corriges_nombre = (mode=='dupliquer') ? 0 : objet_tds.eq(i_col_fichiers).children('span[data-objet=corriges]').data('nb');
      var copies_nombre   = (mode=='dupliquer') ? 0 : objet_tds.eq(i_col_fichiers).children('span[data-objet=copies]').data('nb');
      var fini            =(objet_tds.eq(i_col_remplissage).find('span').text()=='terminé') ? 'oui' : 'non' ;
      // liste des profs et des items
      var prof_liste    = tab_profs[ref];
      var compet_liste  = tab_items[ref];
      // Afficher le formulaire
      afficher_form_gestion( mode , ref , date_devoir , date_devoir_visible , date_saisie_visible , date_autoeval , time_autoeval , '' /*groupe_val*/ , groupe_nom /* volontairement sans unescapeHtml() */ , eleve_nombre , eleve_liste , eleves_ordre , equipe , prof_nombre , prof_liste , unescapeHtml(description) , compet_nombre , compet_liste , diagnostic , pluriannuel , repartition , tab_sujet[ref] , tab_corrige[ref] , sujets_nombre , corriges_nombre , copies_nombre , fini , proprio_id );
    };

    /**
     * Supprimer une évaluation : mise en place du formulaire
     * @return void
     */
    var supprimer = function()
    {
      mode = $(this).attr('class');
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref           = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var groupe_nom    = objet_tds.eq(i_col_groupe).text().trim();
      var description   = objet_tds.eq(i_col_description).html();
      var pluriannuel   = objet_tds.eq(i_col_pluriannuel).html();
      if( (pluriannuel=='non') || (window.TYPE=='groupe') )
      {
        // Afficher le formulaire
        afficher_form_gestion( mode , ref , '' /*date_devoir*/ , 'toujours' /*date_devoir_visible*/ , 'toujours' /*date_saisie_visible*/ , '' /*date_autoeval*/ , '23:59' /*time_autoeval*/ , '' /*groupe_val*/ , '' /*groupe_nom*/ , '' /*eleve_nombre*/ , '' /*eleve_liste*/ , '' /*eleves_ordre*/ , '' /*equipe*/ , '' /*prof_nombre*/ , '' /*prof_liste*/ , unescapeHtml(description+' ('+groupe_nom+')') , '' /*compet_nombre*/ , '' /*compet_liste*/ , 'non' /*diagnostic*/ , pluriannuel , 'non' /*repartition*/ , '' /*doc_sujet*/ , '' /*doc_corrige*/ , 0 /*sujets_nombre*/ , 0 /*corriges_nombre*/ , 0 /*copies_nombre*/ , '' /*fini*/ , window.USER_ID /*proprio_id*/ );
      }
      else
      {
        $.prompt(
          'Vous avez demandé à supprimer une évaluation pluriannuelle.<br>&rArr; Ce peut être une évaluation créée cette année, que vous voulez supprimer classiquement comme une autre évaluation.<br>&rArr; Ou bien c’est une évaluation créée l’an dernier, que vous avez déclaré comme étant pluriannuelle par erreur, et vous ne voulez plus qu’elle apparaisse cette année.<br>Indiquez votre situation sans vous tromper !',
          {
            title   : 'Mode de retrait d’une évaluation pluriannuelle',
            buttons : {
              'Suppression classique' : true ,
              'Retrait avec remise aux dates de l’an dernier' : false
            },
            submit  : function(event, value, message, formVals) {
              if(!value)
              {
                mode = 'supprimer_pluriannuel';
              }
              // Afficher le formulaire
              afficher_form_gestion( mode , ref , '' /*date_devoir*/ , 'toujours' /*date_devoir_visible*/ , 'toujours' /*date_saisie_visible*/ , '' /*date_autoeval*/ , '23:59' /*time_autoeval*/ , '' /*groupe_val*/ , '' /*groupe_nom*/ , '' /*eleve_nombre*/ , '' /*eleve_liste*/ , '' /*eleves_ordre*/ , '' /*equipe*/ , '' /*prof_nombre*/ , '' /*prof_liste*/ , unescapeHtml(description+' ('+groupe_nom+')') , '' /*compet_nombre*/ , '' /*compet_liste*/ , 'non' /*diagnostic*/ , pluriannuel , 'non' /*repartition*/ , '' /*doc_sujet*/ , '' /*doc_corrige*/ , 0 /*sujets_nombre*/ , 0 /*corriges_nombre*/ , 0 /*copies_nombre*/ , '' /*fini*/ , window.USER_ID /*proprio_id*/ );
            }
          }
        );
      }
    };

    /**
     * Imprimer un cartouche d’une évaluation : mise en place du formulaire
     * @return void
     */
    var imprimer = function()
    {
      mode = $(this).attr('class');
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref           = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir   = objet_tds.eq(i_col_date).html();
      var groupe        = objet_tds.eq(i_col_groupe).text().trim();
      var eleves_ordre  = objet_tds.eq(i_col_groupe).data('ordre');
      var description   = objet_tds.eq(i_col_description).html();
      // Mettre les infos de côté
      $('#imprimer_ref').val(ref);
      $('#imprimer_date_devoir').val(date_devoir);
      $('#imprimer_groupe_nom').val(unescapeHtml(groupe));
      $('#imprimer_eleves_ordre').val(eleves_ordre);
      $('#imprimer_description').val(unescapeHtml(description));
      // Afficher la zone associée
      $('#titre_imprimer').html(groupe+' | '+date_devoir+' | '+description); // Pas de escapeHtml car chaines déjà échappées
      $('#box_all_eleves').prop('checked',true).next().show(0).next().html('');
      $('#ajax_msg_imprimer').removeAttr('class').html('');
      $('#zone_imprimer_retour').html('');
      $.fancybox( { href:'#zone_imprimer' , modal:true , minWidth:900 } );
    };

    /**
     * Annuler une action
     * @return void
     */
    var annuler = function()
    {
      $.fancybox.close();
      mode = false;
    };

    /**
     * Intercepter la touche entrée ou escape pour valider ou annuler les modifications
     * @return void
     */
    function intercepter(e)
    {
      if( (mode=='ajouter') || (mode=='dupliquer') || (mode=='modifier') || (mode=='supprimer') || (mode=='supprimer_pluriannuel') )
      {
        if(e.which==13)  // touche entrée
        {
          $('#bouton_valider').click();
        }
        else if(e.which==27)  // touche escape
        {
          $('#bouton_annuler').click();
        }
      }
    }

    /**
     * Saisir les items acquis par les élèves à une évaluation : chargement du formulaire
     * Voir   les items acquis par les élèves à une évaluation : chargement des données
     * @return void
     */
    var saisir_ou_voir = function()
    {
      // Afficher au chargement
      if(window.auto_voir_devoir_id && window.auto_voir_groupe_type && window.auto_voir_groupe_id)
      {
        mode = 'voir';
        var objet_tds = $('#devoir_'+window.auto_voir_devoir_id+'_'+window.auto_voir_groupe_type+window.auto_voir_groupe_id).parent().find('td');
        window.auto_voir_devoir_id = false;
        window.auto_voir_groupe_id = false;
      }
      else
      {
        mode = $(this).attr('class');
        var objet_tds     = $(this).parent().parent().find('td');
      }
      // Récupérer les informations de la ligne concernée
      var ref                  = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir          = objet_tds.eq(i_col_date).html();
      var choix_devoir_visible = objet_tds.eq(i_col_devoir_visible).data('option');
      var date_devoir_visible  = (choix_devoir_visible!='perso') ? choix_devoir_visible : objet_tds.eq(i_col_devoir_visible).html() ;
      var choix_saisie_visible = objet_tds.eq(i_col_saisie_visible).data('option');
      var date_saisie_visible  = (choix_saisie_visible!='perso') ? choix_saisie_visible : objet_tds.eq(i_col_saisie_visible).html() ;
      var groupe               = objet_tds.eq(i_col_groupe).text().trim();
      var eleves_ordre         = objet_tds.eq(i_col_groupe).data('ordre');
      var equipe               = objet_tds.eq(i_col_groupe).data('equipe');
      var description          = objet_tds.eq(i_col_description).html();
      var fini                 = (objet_tds.eq(i_col_remplissage).find('span').text()=='terminé') ? 'oui' : 'non' ;
      // Mettre les infos de côté
      $('#saisir_voir_ref'                 ).val(ref);
      $('#saisir_voir_date_devoir'         ).val(date_devoir);
      $('#saisir_voir_choix_devoir_visible').val(choix_devoir_visible);
      $('#saisir_voir_date_devoir_visible' ).val(date_devoir_visible);
      $('#saisir_voir_choix_saisie_visible').val(choix_saisie_visible);
      $('#saisir_voir_date_saisie_visible' ).val(date_saisie_visible);
      $('#saisir_voir_groupe_nom'          ).val(unescapeHtml(groupe));
      $('#saisir_voir_eleves_ordre'        ).val(eleves_ordre);
      $('#saisir_voir_equipe'              ).val(equipe);
      $('#saisir_voir_description'         ).val(unescapeHtml(description));
      $('#saisir_voir_fini'                ).val(fini);
      // pour finir
      $('#zone_saisir_voir h2').html(mode[0].toUpperCase() + mode.substring(1) + ' les résultats d’une évaluation');
      $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page='+window.PAGE,
          data : 'csrf='+window.CSRF+'&f_action='+mode+'&f_ref='+ref+'&f_eleves_ordre='+eleves_ordre+'&f_equipe='+equipe+'&f_description='+encodeURIComponent(description)+'&f_groupe_nom='+encodeURIComponent(groupe)+'&f_date_devoir='+encodeURIComponent(date_devoir),
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
            return false;
          },
          success : function(responseJSON)
          {
            initialiser_compteur();

            if(responseJSON['statut']==false)
            {
              $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
            }
            else
            {
              modification = false;
              $.fancybox.close();
              // Masquer le tableau ; Afficher la zone associée et remplir son contenu
              $('#form_prechoix , #table_action').hide('fast');
              $('#titre_saisir_voir').html(groupe+' | '+date_devoir+' | '+description); // Pas de escapeHtml car chaines déjà échappées
              $('#ajax_msg_saisir_voir').removeAttr('class').html('');
              obj_table_saisir_voir.html(responseJSON['table']);
              obj_plan_saisir_voir.html(responseJSON['plan']);
              if(mode=='saisir')
              {
                $('#valider_saisir').show();
                $('#para_report_note').show();
                colorer_cellules();
                $('#radio_'+memo_pilotage).click();
                $('#arrow_continue_'+memo_direction).click();
                // Attention : tab_equipe obtenu est un objet et non pas un tableau (donc par exemple la propriété length ne fonctionne pas)
                tab_equipe = JSON.parse(responseJSON['tab_equipe']);
              }
              else if(mode=='voir')
              {
                $('#valider_saisir').hide();
                $('#para_report_note').hide();
                obj_table_saisir_voir.find('tbody td').css({'background-color':'#DDF','text-align':'center','vertical-align':'middle','font-size':'110%'});
              }
              if( (memo_presentation=='tableau') || (isNaN(entier(eleves_ordre))) )
              {
                memo_presentation = 'tableau';
                $('#zone_saisie_tableau').show();
                $('#zone_plan_classe').hide();
                $('#basculer_presentation').html('Présentation plan de classe');
                $('#valider_saisir').hideshow( mode == 'saisir' );
              }
              else if( (memo_presentation=='plan') && (entier(eleves_ordre)>0) ) // forcément
              {
                $('#cadre_tactile').hide();
                $('#zone_plan_classe').show();
                $('#zone_saisie_tableau').hide();
                $('#basculer_presentation').html('Présentation en tableau');
                $('#valider_saisir').hide();
              }
              $('#cadre_photo').hideshow( (mode=='saisir') && (memo_presentation=='tableau') );
              if( $('#f_type').val() == 'selection' )
              {
                $('#basculer_presentation').hide();
              }
              else if(isNaN(entier(eleves_ordre)))
              {
                $('#basculer_presentation').prop('disabled',true);
              }
              else
              {
                $('#basculer_presentation').prop('disabled',false);
                if( (typeof(responseJSON['nb_colonnes'])!='undefined') && (typeof(responseJSON['nb_rangees'])!='undefined') )
                {
                  $('#ul_plan').css( 'grid-template-columns' , 'auto '.repeat(responseJSON['nb_colonnes']) );
                }
              }
              $('#zipper_copies_eleves').prop('disabled', !responseJSON['is_copie'] );
              nb_colonnes = obj_table_saisir_voir.find('thead th').length;
              nb_lignes   = obj_table_saisir_voir.find('tbody tr').length;
              $('#zone_saisir_voir').show();
              if(nb_lignes>nb_lignes_max)
              {
                obj_table_saisir_voir.stickyTableHeaders();
              }
              if( (mode=='saisir') && (memo_presentation=='tableau') )
              {
                if(memo_pilotage=='clavier')
                {
                  $('#C'+colonne+'L'+ligne).focus();
                  if(IsTouch)
                  {
                    $('#cadre_tactile').show();
                  }
                }
                else
                {
                  $('#arrow_continue').hide();
                }
              }
            }
          }
        }
      );
    };

    /**
     * Choisir les items associés à une évaluation : mise en place du formulaire
     * @return void
     */
    var choisir_compet = function()
    {
      // Ne pas changer ici la valeur de "mode" (qui est à "ajouter" ou "modifier" ou "dupliquer").
      $('#f_selection_items option:first').prop('selected',true);
      $('#f_liste_items_nom').val('');
      item_reste = cocher_matieres_items( $('#f_compet_liste').val() );
      $('#alerte_items').hideshow( mode == 'modifier' );
      $('#selection_id').val('');
      $('#action_modifier').prop('checked',false);
      $('#span_selection_modifier').hide(0);
      // En cas d’évaluation partagée où tous les profs ne sont pas tous reliés aux référentiels concernés
      $('#info_items').hideshow( item_reste.nombre );
      // Afficher la zone
      $.fancybox( { href:'#zone_matieres_items' , modal:true } );
      if( !IsTouch )
      {
        $(document).tooltip('destroy');display_infobulle(); // Sinon, bug avec l’infobulle contenu dans le fancybox qui ne disparait pas au clic...
      }
    };

    /**
     * Choisir les élèves associés à une évaluation : mise en place du formulaire (uniquement pour des élèves sélectionnés)
     * @return void
     */
    var choisir_eleve = function()
    {
      // Ne pas changer ici la valeur de "mode" (qui est à "ajouter" ou "modifier" ou "dupliquer").
      $('#zone_eleve q.date_calendrier').show();
      $('#zone_eleve li.li_m1 span.gradient_pourcent').html('');
      $('#msg_indiquer_eleves_deja').removeAttr('class').html('');
      cocher_eleves( $('#f_eleve_liste').val() );
      $('#alerte_eleves').hideshow( mode == 'modifier' );
      // Afficher la zone
      $.fancybox( { href:'#zone_eleve' , modal:true } );
      if( !IsTouch )
      {
        $(document).tooltip('destroy');display_infobulle(); // Sinon, bug avec l’infobulle contenu dans le fancybox qui ne disparait pas au clic...
      }
    };

    /**
     * Réordonner les items associés à une évaluation : mise en place du formulaire
     * @return void
     */
    var ordonner = function()
    {
      mode = $(this).attr('class');
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref           = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir   = objet_tds.eq(i_col_date).html();
      var groupe        = objet_tds.eq(i_col_groupe).text().trim();
      var description   = objet_tds.eq(i_col_description).html();
      // Mettre les infos de côté
      $('#ordre_ref').val(ref);
      // Afficher la zone associée après avoir chargé son contenu
      $('#titre_ordonner').html(groupe+' | '+date_devoir+' | '+description); // Pas de escapeHtml car chaines déjà échappées
      $('#ajax_msg_ordonner').removeAttr('class').html('');
      $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page='+window.PAGE,
          data : 'csrf='+window.CSRF+'&f_action='+mode+'&f_ref='+ref,
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
            return false;
          },
          success : function(responseJSON)
          {
            initialiser_compteur();
            if(responseJSON['statut']==false)
            {
              $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
            }
            else
            {
              modification = false;
              $('#sortable_v').html(responseJSON['value']).sortable( { cursor:'ns-resize' , update:function(event,ui){modif_ordre();} } );
              // Afficher la zone
              $.fancybox( { href:'#zone_ordonner' , modal:true } );
            }
          }
        }
      );
    };
    function modif_ordre()
    {
      if(modification==false)
      {
        $('#fermer_zone_ordonner').attr('class','annuler').html('Annuler / Retour');
        modification = true;
        $('#ajax_msg_ordonner').removeAttr('class').html('');
      }
    }

    /**
     * Voir les répartitions des élèves à une évaluation : chargement des données
     * @return void
     */
    function ajax_statistiques()
    {
      $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page='+window.PAGE,
          data : 'csrf='+window.CSRF+'&f_action='+mode+'&'+$('#zone_voir_repart').serialize(),
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
            return false;
          },
          success : function(responseJSON)
          {
            initialiser_compteur();
            if(responseJSON['statut']==false)
            {
              $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
            }
            else
            {
              // Afficher la zone
              $('#table_voir_repart_quantitative').html(responseJSON['quantitative']);
              $('#table_voir_repart_quantitative tbody td').css({'background-color':'#DDF','font-weight':'normal','text-align':'center'});
              $('#table_voir_repart_nominative').html(responseJSON['nominative']);
              $('#table_voir_repart_nominative tbody td').css({'background-color':'#DDF','font-weight':'normal','font-size':'85%'});
              $('#lien_repart_nominative').attr('href',responseJSON['href']);
              $('#ajax_msg_archiver_repart').removeAttr('class').html('');
              $.fancybox( { href:'#zone_voir_repart' } );
            }
          }
        }
      );
    };

    /**
     * Voir les répartitions des élèves à une évaluation : chargement des données
     * @return void
     */
    var voir_repart = function()
    {
      mode = $(this).attr('class');
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref           = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir   = objet_tds.eq(i_col_date).html();
      var groupe        = objet_tds.eq(i_col_groupe).text().trim();
      var eleves_ordre  = objet_tds.eq(i_col_groupe).data('ordre');
      var description   = objet_tds.eq(i_col_description).html();
      // Et aussi...
      var categorie_autre = ($('#f_categorie_autre').is(':checked')) ? 1 : 0 ;
      // Mettre les infos de côté
      $('#repart_ref').val(ref);
      $('#repart_date_devoir').val(date_devoir);
      $('#repart_groupe_nom').val(unescapeHtml(groupe));
      $('#repart_eleves_ordre').val(eleves_ordre);
      $('#repart_description').val(unescapeHtml(description));
      // Afficher la zone associée après avoir chargé son contenu
      $('#titre_voir_repart').html(groupe+' | '+date_devoir+' | '+description); // Pas de escapeHtml car chaines déjà échappées
      $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
      ajax_statistiques();
    };

    $('#f_categorie_autre , #f_ref_pourcentage').change
    (
      function()
      {
        ajax_statistiques();
      }
    );

    /**
     * Choisir les professeurs associés à une évaluation : mise en place du formulaire
     * @return void
     */
    var choisir_prof = function()
    {
      selectionner_profs_option( $('#f_prof_liste').val() );
      // Afficher la zone
      $.fancybox( { href:'#zone_profs' , modal:true , minWidth:700 } );
      if( !IsTouch )
      {
        $(document).tooltip('destroy');display_infobulle(); // Sinon, bug avec l’infobulle contenu dans le fancybox qui ne disparait pas au clic...
      }
    };

    /**
     * Uploader les documents associés à une évaluation : mise en place du formulaire
     * @return void
     */
    var uploader_doc = function()
    {
      mode = $(this).attr('class');
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref           = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir   = objet_tds.eq(i_col_date).html();
      var groupe        = objet_tds.eq(i_col_groupe).text().trim();
      var eleves_ordre  = objet_tds.eq(i_col_groupe).data('ordre');
      var description   = objet_tds.eq(i_col_description).html();
      // Sujet & Corrigé
      var img_sujet     = (tab_sujet[ref])   ? '<a href="'+tab_sujet[ref]+'" target="_blank" rel="noopener noreferrer" class="no_puce"><img alt="sujet" src="./_img/document/sujet_oui.png"'+infobulle('Sujet disponible.')+'></a>' : '<img alt="sujet" src="./_img/document/sujet_non.png">' ;
      var img_corrige   = (tab_corrige[ref]) ? '<a href="'+tab_corrige[ref]+'" target="_blank" rel="noopener noreferrer" class="no_puce"><img alt="corrigé" src="./_img/document/corrige_oui.png"'+infobulle('Corrigé disponible.')+'></a>' : '<img alt="corrigé" src="./_img/document/corrige_non.png">' ;
      // Renseigner les champs dynamique affichés
      $('#titre_upload').html(groupe+' | '+date_devoir+' | '+description); // Pas de escapeHtml car chaines déjà échappées
      $('#ajax_document_collectif_upload').removeAttr('class').html('');
      $('#span_sujet').html(img_sujet);
      $('#span_corrige').html(img_corrige);
      $('#uploader_ref').val(ref);
      activer_boutons_upload(ref);
      // Afficher la zone
      $.fancybox( { href:'#zone_upload' , minWidth:800 , modal:true } );
      // Charger le tableau pour les énoncés / corrigés individuels par élève
      $('#eleve_fichier').html('<p><label class="loader">'+'En cours&hellip;'+'</label></p>');
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page='+window.PAGE,
          data : 'csrf='+window.CSRF+'&f_action=voir_documents'+'&f_ref='+ref+'&f_eleves_ordre='+eleves_ordre,
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $('#eleve_fichier').html('<p><label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label></p>');
            return false;
          },
          success : function(responseJSON)
          {
            initialiser_compteur();
            if(responseJSON['statut']==false)
            {
              $('#eleve_fichier').html('<p><label class="alerte">'+responseJSON['value']+'</label></p>');
            }
            else
            {
              tab_sujet_perso   = JSON.parse(responseJSON['tab_sujet']);
              tab_corrige_perso = JSON.parse(responseJSON['tab_corrige']);
              $('#eleve_fichier').html(responseJSON['html']+'<div id="analyse_import" class="fg notnow"></div>');
            }
          }
        }
      );
    };

    /**
     * Générer des énoncés d’évaluation
     * @return void
     */
    var generer_enonces = function()
    {
      var objet_tds     = $(this).parent().parent().find('td');
      // Récupérer les informations de la ligne concernée
      var ref           = objet_tds.eq(i_col_icones).attr('id').substring(7); // "devoir_" + ref
      var date_devoir   = objet_tds.eq(i_col_date).html();
      var groupe        = objet_tds.eq(i_col_groupe).text().trim();
      var eleves_ordre  = objet_tds.eq(i_col_groupe).data('ordre');
      var description   = objet_tds.eq(i_col_description).html();
      $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page='+window.PAGE,
          data : 'csrf='+window.CSRF+'&f_action='+'generer_enonces'+'&f_ref='+ref+'&f_eleves_ordre='+eleves_ordre+'&f_description='+encodeURIComponent(description)+'&f_groupe_nom='+encodeURIComponent(groupe)+'&f_date_devoir='+encodeURIComponent(date_devoir),
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
            return false;
          },
          success : function(responseJSON)
          {
            initialiser_compteur();
            if(responseJSON['statut']==false)
            {
              $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
            }
            else
            {
              $.fancybox( { href:responseJSON['value'] , type:'iframe' } );
            }
          }
        }
      );
    };

    /**
     * Importer une évaluation depuis un module externe
     * @return void
     */
    var importer_evaluation = function()
    {
      $('#import_bilan').html('');
      $('#ajax_msg_importer_evaluation').removeAttr('class').html('');
      // Afficher la zone associée
      $.fancybox( { href:'#zone_importer' , modal:true , minWidth:800 } );
      $('#f_fichier').focus().val(window.reception_module_import);
      if( window.reception_module_import )
      {
        $('#valider_importer_evaluation').click();
        window.reception_module_import = '' ;
      }
    };

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Appel des fonctions en fonction des événements
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#table_action' ).on( 'click' , 'q.ajouter'         , ajouter );
    $('#table_action' ).on( 'click' , 'q.modifier'        , modifier_dupliquer );
    $('#table_action' ).on( 'click' , 'q.dupliquer'       , modifier_dupliquer );
    $('#table_action' ).on( 'click' , 'q.supprimer'       , supprimer );
    $('#table_action' ).on( 'click' , 'q.ordonner'        , ordonner );
    $('#table_action' ).on( 'click' , 'q.imprimer'        , imprimer );
    $('#table_action' ).on( 'click' , 'q.saisir'          , saisir_ou_voir );
    $('#table_action' ).on( 'click' , 'q.voir'            , saisir_ou_voir );
    $('#table_action' ).on( 'click' , 'q.voir_repart'     , voir_repart );
    $('#table_action' ).on( 'click' , 'q.uploader_doc'    , uploader_doc );
    $('#table_action' ).on( 'click' , 'q.module_envoyer'  , generer_enonces );
    $('#table_action' ).on( 'click' , 'q.module_recevoir' , importer_evaluation );

    $('#form_gestion' ).on( 'click'   , 'q.choisir_compet' , choisir_compet );
    $('#form_gestion' ).on( 'click'   , 'q.choisir_eleve'  , choisir_eleve );
    $('#form_gestion' ).on( 'click'   , 'q.choisir_prof'   , choisir_prof );
    $('#form_gestion' ).on( 'click'   , '#bouton_annuler'  , annuler );
    $('#form_gestion' ).on( 'click'   , '#bouton_valider'  , function(){formulaire.submit();} );
    $('#form_gestion' ).on( 'keydown' , 'input,select'     , function(e){intercepter(e);} );

    $('#zone_upload'  ).on( 'click' , '#fermer_zone_upload'   , annuler );
    $('#zone_upload'  ).on( 'click' , '#fermer_zone_uploads'  , annuler );
    $('#zone_ordonner').on( 'click' , '#fermer_zone_ordonner' , annuler );
    $('#zone_imprimer').on( 'click' , '#fermer_zone_imprimer' , annuler );
    $('#zone_importer').on( 'click' , '#fermer_zone_importer' , annuler );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Indiquer au survol une liste de profs associés à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#table_action').on
    (
      'mouseover',
      'td.bulle_profs',
      function()
      {
        var obj_td     = $(this);
        var ref        = obj_td.parent().children('td:last').attr('id').substring(7); // "devoir_" + ref
        var proprio_id = obj_td.data('proprio');
        var prof_liste = tab_profs[ref];
        var tab_texte  = [];
        if(prof_liste.length)
        {
          prof_liste += '_z'+proprio_id;
          var tab_id = prof_liste.split('_');
          var prof_nombre = tab_id.length;
          for(var i in tab_id)
          {
            if( (prof_nombre>=12) && (i>=10) )
            {
              var nombre_reste = prof_nombre - i;
              tab_texte[i] = '… et '+nombre_reste+' collègues supplémentaires';
              break;
            }
            var prof_id    = tab_id[i].substring(1);
            var input_id   = 'p'+'_'+prof_id;
            if($('#'+input_id).length)
            {
              tab_texte[i] = $('#'+input_id).next().next().text();
            }
            else
            {
              tab_texte[i] = 'collègue n°'+prof_id+'... ?';
            }
          }
          tab_texte.sort();
        }
        obj_td.attr( 'title' , tab_texte.join('<br>') );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Indiquer au survol une liste d’élèves associés à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#table_action').on
    (
      'mouseover',
      'td.bulle_eleves',
      function()
      {
        var obj_td      = $(this);
        var ref         = obj_td.parent().children('td:last').attr('id').substring(7); // "devoir_" + ref
        var eleve_liste = tab_eleves[ref];
        var tab_texte   = [];
        if(eleve_liste.length)
        {
          var tab_id = eleve_liste.split('_');
          var eleve_nombre = tab_id.length;
          for(var i in tab_id)
          {
            if( (eleve_nombre>=12) && (i>=10) )
            {
              var nombre_reste = eleve_nombre - i;
              tab_texte[i] = '… et '+nombre_reste+' élèves supplémentaires';
              break;
            }
            var id_debut = 'id_'+tab_id[i]+'_';
            if($('input[id^='+id_debut+']').length)
            {
              tab_texte[i] = $('input[id^='+id_debut+']').first().next().text();
            }
            else
            {
              tab_texte[i] = 'élève n°'+tab_id[i]+' (ne vous est pas affecté)';
            }
          }
          tab_texte.sort();
        }
        obj_td.attr( 'title' , tab_texte.join('<br>') );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Indiquer au survol une liste d’items associés à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#table_action').on
    (
      'mouseover',
      'td.bulle_items',
      function()
      {
        var obj_td      = $(this);
        var ref         = obj_td.parent().children('td:last').attr('id').substring(7); // "devoir_" + ref
        var item_liste  = tab_items[ref];
        var tab_id      = item_liste.split('_');
        var item_nombre = tab_id.length;
        var tab_texte   = [];
        for(var i in tab_id)
        {
          if( (item_nombre>=12) && (i>=10) )
          {
            var nombre_reste = item_nombre - i;
            tab_texte[i] = '… et '+nombre_reste+' items supplémentaires';
            break;
          }
          var input_id = 'item_'+tab_id[i];
          if($('#'+input_id).length)
          {
            tab_texte[i] = $('#'+input_id).parent().text().substring(4); // "[S] " ou "[-] "
          }
          else
          {
            tab_texte[i] = 'item n°'+tab_id[i]+' (ne vous est pas rattaché)';
          }
          tab_texte.sort();
        }
        obj_td.attr( 'title' , tab_texte.join('<br>') );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Indiquer au survol l’intitulé d’un item
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#table_saisir_voir').on
    (
      'mouseover',
      'b.bulle',
      function()
      {
        var obj_b = $(this);
        var texte = obj_b.next('div').text();
        obj_b.attr( 'title' , texte );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Récupération du listing des profs associés à un regroupement
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_groupe_profs').change
    (
      function()
      {
        var obj_option = $(this).find('option:selected');
        var prof_groupe_id = obj_option.val();
        var listing_profs_concernes = obj_option.data('listing');
        if( prof_groupe_id && (typeof(listing_profs_concernes)=='undefined') )
        {
          $('#appliquer_droit_prof_groupe').prop('disabled',true);
          $('#load_profs_groupe').attr('class','loader').html('Recherche&hellip;');
          var prof_groupe_type = obj_option.parent().attr('label');
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page=_maj_listing_professeurs',
              data : 'f_groupe_id='+prof_groupe_id+'&f_groupe_type='+prof_groupe_type,
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $('#appliquer_droit_prof_groupe').prop('disabled',false);
                $('#load_profs_groupe').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                if(responseJSON['statut']==true)
                {
                  obj_option.data('listing',responseJSON['value']);
                  $('#load_profs_groupe').removeAttr('class').html('');
                }
                else
                {
                  $('#load_profs_groupe').attr('class','alerte').html(responseJSON['value']);
                }
                $('#appliquer_droit_prof_groupe').prop('disabled',false);
              }
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Modification du choix du droit pour un lot de profs
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#appliquer_droit_prof_groupe').click
    (
      function()
      {
        var valeur = $('input[name=prof_check_all]:checked').val();
        if(typeof(valeur)=='undefined')
        {
          $('#load_profs_groupe').attr('class','erreur').html('Cocher un niveau de droit !');
          return false;
        }
        var listing_profs_concernes = $('#f_groupe_profs').find('option:selected').data('listing');
        if(typeof(listing_profs_concernes)=='undefined')
        {
          $('#load_profs_groupe').attr('class','erreur').html('Liste des collègues non récupérée !');
          return false;
        }
        var tab_profs_concernes = listing_profs_concernes.split(',');
        $('.prof_liste').find('select:enabled').each
        (
          function()
          {
            var prof_id = $(this).attr('id').substring(2); // "p_" + id
            var prof_valeur = ( tab_profs_concernes.indexOf(prof_id) == -1 ) ? 'x' : valeur ;
            $(this).find('option[value='+prof_valeur+']').prop('selected',true);
            $(this).next('span').attr('class','select_img droit_'+prof_valeur);
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Modification du choix du droit pour un prof
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#zone_profs').on
    (
      'change',
      'select',
      function()
      {
        var val_option = $(this).find('option:selected').val();
        $(this).next('span').attr('class','select_img droit_'+val_option);
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Modification du select pour choisir une date de visibilité
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_choix_devoir_visible').change
    (
      function()
      {
        if( $(this).val() == 'perso' )
        {
          $('#span_devoir_visible_perso').show(0).children('input').focus();
        }
        else
        {
          $('#span_devoir_visible_perso').hide(0);
        }
      }
    );

    $('#f_choix_saisie_visible').change
    (
      function()
      {
        if( $(this).val() == 'perso' )
        {
          $('#span_saisie_visible_perso').show(0).children('input').focus();
        }
        else
        {
          $('#span_saisie_visible_perso').hide(0);
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le checkbox pour choisir ou non les élèves d’un cartouche
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function maj_eleve()
    {
      var ref = $('#imprimer_ref').val();
      var tab_split = ref.split('_');
      var groupe = tab_split[1];
      var groupe_type = groupe.substring(0,1).toLowerCase(); // c | g | b | e
      var groupe_id   = groupe.substring(1);
      var eleves_ordre = $('#imprimer_eleves_ordre').val();
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page=_maj_select_eleves',
          data : 'f_groupe_id='+groupe_id+'&f_groupe_type='+groupe_type+'&f_eleves_ordre='+eleves_ordre+'&f_statut=1'+'&f_multiple=1'+'&f_filter=1'+'&f_selection=1',
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $('#ajax_eleves').html('<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>');
          },
          success : function(responseJSON)
          {
            initialiser_compteur();
            if(responseJSON['statut']==true)
            {
              $('#ajax_eleves').html(responseJSON['value']);
            }
            else
            {
              $('#ajax_eleves').html('<label class="alerte">'+responseJSON['value']+'</label>');
            }
          }
        }
      );
    }

    $('#box_all_eleves').click
    (
      function()
      {
        if($(this).is(':checked'))
        {
          $(this).next().show(0).next().html('');
        }
        else
        {
          $(this).next().hide(0).next().html('<label class="loader">Chargement&hellip;</label>');
          maj_eleve();
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le checkbox pour choisir ou non une date d’auto-évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#box_autoeval').click
    (
      function()
      {
        if($(this).is(':checked'))
        {
          $(this).next().show(0).next().hide(0).children('input:first').val('00/00/0000');
        }
        else
        {
          $(this).next().hide(0).next().show(0).children('input:first').focus().val(window.input_autoeval);
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le checkbox pour choisir ou non une évaluation diagnostique
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_diagnostic').click
    (
      function()
      {
        if($(this).is(':checked'))
        {
          $(this).next().hide(0).next().show(0);
        }
        else
        {
          $(this).next().show(0).next().hide(0);
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le checkbox pour choisir ou non une évaluation pluriannuelle
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_pluriannuel').click
    (
      function()
      {
        if($(this).is(':checked'))
        {
          $(this).next().hide(0).next().show(0);
        }
        else
        {
          $(this).next().show(0).next().hide(0);
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Alerte si modification de groupe d’une évaluation
    // Afficher / Masquer le mode de tri des élèves
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_groupe').change
    (
      function()
      {
        // Alerte si modification de groupe d’une évaluation
        if(mode=='modifier')
        {
          $('#alerte_groupe').show();
        }
        // Afficher / Masquer le mode de tri des élèves
        maj_choix_tri_eleves();
        // Indiquer période associée
        indication_periode();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Afficher / Masquer le mode d’évaluation par équipe
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_eleves_ordre').change
    (
      function()
      {
        $('#bloc_equipe').hideshow( $('#f_eleves_ordre option:selected').data('data') );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Vérification si modification de la date d’une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Indiquer période associée
    // input permet d’intercepter à la fois les saisies au clavier et les copier-coller à la souris (clic droit)
    $('#form_gestion').on( 'input' , '#f_date_devoir' , function() { indication_periode(); } );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour fermer le cadre des items associés à une évaluation (annuler / retour)
    // Clic sur le bouton pour fermer le cadre des élèves associés à une évaluation (annuler / retour) (uniquement pour des élèves sélectionnés)
    // Clic sur le bouton pour fermer le cadre des professeurs associés à une évaluation (annuler / retour)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#annuler_compet , #annuler_eleve , #annuler_profs').click
    (
      function()
      {
        $.fancybox( { href:'#form_gestion' , modal:true , minWidth:700 } );
        return false;
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour fermer le formulaire servant à saisir ou voir les résultats des élèves à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function fermer_zone_saisir_voir()
    {
      $('#titre_saisir_voir').html('');
      obj_table_saisir_voir.html('<tbody><tr><td></td></tr></tbody>');
      if(nb_lignes>nb_lignes_max)
      {
        obj_table_saisir_voir.stickyTableHeaders('destroy');
      }
      if( (mode=='saisir') && IsTouch )
      {
        $('#cadre_tactile').hide();
      }
      $('#zone_saisir_voir').hide();
      $('#form_prechoix , #table_action').show('fast');
      return false;
    }

    $('#fermer_zone_saisir_voir').click
    (
      function()
      {
        if( (mode=='voir') || !modification )
        {
          fermer_zone_saisir_voir();
        }
        else
        {
          $.fancybox( { href:'#zone_confirmer_fermer_saisir' , modal:true } );
          return false;
        }
      }
    );

    $('#confirmer_fermer_zone_saisir').click
    (
      function()
      {
        $.fancybox.close();
        fermer_zone_saisir_voir();
      }
    );

    $('#annuler_fermer_zone_saisir').click
    (
      function()
      {
        $.fancybox.close();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour valider le choix des items associés à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_compet').click
    (
      function()
      {
        var liste = '';
        var nombre = 0;
        $('#zone_matieres_items input[type=checkbox]:checked').each
        (
          function()
          {
            liste += $(this).val()+'_';
            nombre++;
          }
        );
        // En cas d’évaluation partagée où tous les profs ne sont pas tous reliés aux référentiels concernés
        if(item_reste.nombre)
        {
          liste += item_reste.liste+'_';
          nombre += item_reste.nombre;
        }
        var compet_liste  = liste.substring(0,liste.length-1);
        var compet_nombre = (nombre==0) ? 'aucun' : ( (nombre>1) ? nombre+' items' : nombre+' item' ) ;
        $('#f_compet_liste').val(compet_liste);
        $('#f_compet_nombre').val(compet_nombre);
        $('#annuler_compet').click();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour valider le choix des élèves associés à une évaluation (uniquement pour des élèves sélectionnés)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_eleve').click
    (
      function()
      {
        var liste = '';
        var nombre = 0;
        var test_doublon = [];
        $('#zone_eleve input[type=checkbox]:checked').each
        (
          function()
          {
            var eleve_id = $(this).val();
            if(typeof(test_doublon[eleve_id])=='undefined')
            {
              test_doublon[eleve_id] = true;
              liste += eleve_id+'_';
              nombre++;
            }
          }
        );
        var eleve_liste  = liste.substring(0,liste.length-1);
        var eleve_nombre = (nombre==0) ? 'aucun' : ( (nombre>1) ? nombre+' élèves' : nombre+' élève' ) ;
        $('#f_eleve_liste').val(eleve_liste);
        $('#f_eleve_nombre').val(eleve_nombre);
        $('#annuler_eleve').click();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour valider le choix des profs associés à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_profs').click
    (
      function()
      {
        var liste = '';
        var nombre = 0;
        $('.prof_liste').find('select').each
        (
          function()
          {
            var val_option = $(this).find('option:selected').val();
            if( (val_option!='x') && (val_option!='z') )
            {
              var tab_val = $(this).attr('id').split('_');
              var prof_id = tab_val[1];
              liste += val_option+prof_id+'_';
              nombre++;
            }
          }
        );
        liste  = (!nombre) ? '' : liste.substring(0,liste.length-1) ;
        nombre = (!nombre) ? 'non' : (nombre+1)+' profs' ;
        $('#f_prof_liste').val(liste);
        $('#f_prof_nombre').val(nombre);
        $('#annuler_profs').click();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Demande pour sélectionner d’une liste d’items mémorisés
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#f_selection_items').change
    (
      function()
      {
        item_reste = cocher_matieres_items( $('#f_selection_items').val() );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour mémoriser un choix d’items
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#zone_matieres_items' ).on(
      'keydown' , 'input' , function(e){
        if(e.which==13)  // touche entrée
        {
          $('#f_enregistrer_items').click();
          return false;
        }
      }
    );

    $('#f_enregistrer_items').click
    (
      function()
      {
        memoriser_selection_matieres_items( $('#f_liste_items_nom').val() );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Fonction pour colorer les cases du tableau de saisie des items déjà enregistrés
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function colorer_cellules()
    {
      obj_table_saisir_voir.find('tbody td input').each
      (
        function()
        {
          if( ($(this).val()!='X') && ($(this).val()!='PA') )
          {
            $(this).parent().css('background-color','#AAF');
          }
          else
          {
            $(this).parent().css('background-color','#EEF');
          }
        }
      );
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour basculer d’un mode de présentation à un autre (tableau / plan de classe)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#basculer_presentation').click
    (
      function()
      {
        if(!modification)
        {
          var eval_type = $('#f_type').val();
          var eleves_ordre = $('#saisir_voir_eleves_ordre').val();
          if( (memo_presentation=='tableau') && (entier(eleves_ordre)>0) && (eval_type=='groupe') )
          {
            memo_presentation = 'plan';
            $('#zone_plan_classe').show();
            $('#zone_saisie_tableau').hide();
            $('#basculer_presentation').html('Présentation en tableau');
            $('#valider_saisir').hide();
          }
          else if( (memo_presentation=='plan') || (isNaN(entier(eleves_ordre))) || (eval_type=='selection') ) // forcément
          {
            memo_presentation = 'tableau';
            $('#zone_saisie_tableau').show();
            $('#zone_plan_classe').hide();
            $('#basculer_presentation').html('Présentation plan de classe');
            $('#valider_saisir').hideshow( mode == 'saisir' );
          }
          if( (mode=='saisir') && (memo_presentation=='tableau') )
          {
            $('#cadre_photo').show(0);
            if(IsTouch)
            {
              $('#cadre_tactile').show(0);
            }
          }
          else if( (mode=='voir') || (memo_presentation=='plan') ) // forcément
          {
            $('#cadre_photo').hide(0);
            $('#cadre_tactile').hide(0);
          }
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Enregistrer la saisie : code commun à la présentation en tableau et celle en plan de classe
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function enregistrer_saisie()
    {
      var obj_bouton_validation = (memo_presentation=='tableau') ? $('#valider_saisir') : $('#zone_saisie_plan button') ;
      var obj_label_ajax_msg    = (memo_presentation=='tableau') ? $('#ajax_msg_saisir_voir') : $('#ajax_msg_enregistrement_saisie_plan') ;
      if(modification==false)
      {
        obj_label_ajax_msg.attr('class','alerte').html('Aucune modification effectuée !');
      }
      else
      {
        obj_bouton_validation.prop('disabled',true); // Pas tous les boutons à cause de #basculer_presentation qui a un état géré à part
        obj_label_ajax_msg.attr('class','loader').html('En cours&hellip;');
        // Grouper les saisies dans une variable unique afin d’éviter tout problème avec une limitation du module "suhosin" ou "max input vars" généralement fixé à 1000.
        var f_notes = [];
        obj_table_saisir_voir.find('tbody input').each
        (
          function()
          {
            var ids  = $(this).attr('name');
            var note = $(this).val();
            if(note)
            {
              f_notes.push( ids + '_' + note );
            }
          }
        );
        var ref = $('#saisir_voir_ref').val();
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=enregistrer_saisie'+'&f_ref='+ref+'&f_date_devoir='+$('#saisir_voir_date_devoir').val()+'&f_choix_devoir_visible='+$('#saisir_voir_choix_devoir_visible').val()+'&f_date_devoir_visible='+$('#saisir_voir_date_devoir_visible').val()+'&f_choix_saisie_visible='+$('#saisir_voir_choix_saisie_visible').val()+'&f_date_saisie_visible='+$('#saisir_voir_date_saisie_visible').val()+'&f_eleves_ordre='+$('#saisir_voir_eleves_ordre').val()+'&f_fini='+$('#saisir_voir_fini').val()+'&f_prof_liste='+tab_profs[ref]+'&f_notes='+f_notes+'&f_description='+encodeURIComponent($('#saisir_voir_description').val()),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              obj_bouton_validation.prop('disabled',false);
              obj_label_ajax_msg.attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              return false;
            },
            success : function(responseJSON)
            {
              modification = false; // Mis ici pour le cas "aucune modification détectée"
              $(window).off( 'beforeunload', confirmOnLeave );
              if( entier($('#saisir_voir_eleves_ordre').val()) > 0 )
              {
                $('#basculer_presentation').prop('disabled',false);
              }
              initialiser_compteur();
              obj_bouton_validation.prop('disabled',false);
              if(responseJSON['statut']==false)
              {
                obj_label_ajax_msg.attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                $('#devoir_'+ref).parent().addClass('new');
                if(memo_presentation=='tableau')
                {
                  $('#devoir_'+ref).prev().replaceWith(responseJSON['td']);
                  $('#fermer_zone_saisir_voir').attr('class','retourner').html('Retour');
                  $('#kbd_27').attr('class','img retourner');
                }
                else
                {
                  $('#ajax_msg_enregistrement_saisie_plan').attr('class','valide').html('Saisie enregistrée !');
                  $('#devoir_'+$('#saisir_voir_ref').val()).prev().replaceWith(responseJSON['td']);
                  if(nb_notes==1)
                  {
                    $.fancybox.close();
                  }
                }
                $('#ajax_msg_saisir_voir').attr('class','valide').html('Saisie enregistrée !');
                colorer_cellules();
              }
            }
          }
        );
      }
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Modifier les notes des équipiers
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function modifier_notes_eleve_et_equipiers(case_ref, note, style)
    {
      $('#'     +case_ref).val(note).attr('class',style);
      $('#plan_'+case_ref).val(note).attr('class',style);
      if( (memo_presentation=='tableau') && (memo_pilotage=='clavier') )
      {
        $('#'+case_ref).parent().css('background-color','#F6D');
      }
      var tab = case_ref.split('L');
      var eleve_id_colonne = tab[0].substring(1);
      if(typeof(tab_equipe[eleve_id_colonne])!='undefined')
      {
        for (var equipier_id_colonne in tab_equipe[eleve_id_colonne]) {
          var case_equipier = case_ref.replace('C'+eleve_id_colonne+'L','C'+equipier_id_colonne+'L');
          $('#plan_'+case_equipier).val(note).attr('class',style);
          $('#'+     case_equipier).val(note).attr('class',style);
          if(memo_presentation=='tableau')
          {
            $('#'+case_equipier).parent().css('background-color','#F6D');
          }
        };
      }
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Plan de classe : afficher le formulaire de saisie des notes (pour un élève donné)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#ul_plan').on
    (
      'click',
      'input',
      function()
      {
        var obj_div_notes = $(this).parent();
        var obj_div_case  = obj_div_notes.parent();
        var eleve_nom     = obj_div_case.find('span[data=nom]').text();
        var eleve_prenom  = obj_div_case.find('span[data=prenom]').text();
        var label_notes   = '';
        nb_notes = 0;
        obj_div_notes.find('input').each
        (
          function()
          {
            var obj_input = $(this);
            var case_ref  = obj_input.attr('id').substring(5); // plan_CiLi
            var comp_id   = obj_input.attr('name');
            var comp_val  = obj_input.val();
            var obj_th    = $('#L'+comp_id).children('th');
            var comp_ref  = obj_th.data('ref');
            var comp_txt  = obj_th.children('div').text();
            var find_label = 'for="note_'+comp_id+'_'+comp_val+'" class="note';
            var find_input = 'id="note_'+comp_id+'_'+comp_val+'"';
            var masque_label = new RegExp(find_label, 'g')
            var masque_input = new RegExp(find_input, 'g')
            label_notes += '<div data-case="'+case_ref+'"><label class="tab">'+comp_ref+' :</label>'+window.radio_boutons.replaceAll('note_', 'note_'+comp_id).replace(masque_label, find_label+' check').replace(masque_input, find_input+' checked')+' '+comp_txt+'</div>';
            nb_notes++;
          }
        );
        // obligatoirement le nom en premier car pas de tri par prénom vu que trié par plan de classe
        $('#report_eleve').html(eleve_nom+' '+eleve_prenom);
        $('#p_saisie_plan').html(label_notes);
        $('#ajax_msg_enregistrement_saisie_plan').removeAttr('class').html('');
        $.fancybox( { href:'#zone_saisie_plan' , modal:true , minWidth:800 } );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Plan de classe : indiquer visuellement la note cochée
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#p_saisie_plan').on
    (
      'click',
      'input[type=radio]',
      function()
      {
        $(this).parent().parent().find('label').removeClass('check');
        $(this).parent().addClass('check');
        if(modification==false)
        {
          modification = true;
          $(window).on('beforeunload', confirmOnLeave );
          // enregistrement automatique puis fermeture de la fenêtre pafin de gagner du temps en classe
          valider_saisie_plan();
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Plan de classe : annuler la saisie
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#fermer_zone_saisie_plan').click
    (
      function()
      {
        modification = false;
        $(window).off( 'beforeunload', confirmOnLeave );
        $.fancybox.close();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Plan de classe : enregistrer la saisie (la reporter sur les 2 interface visuelles + enregistrement)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function valider_saisie_plan()
    {
      // Report visuel dans les interfaces
      $('#p_saisie_plan').children('div').each
      (
        function()
        {
          var case_ref = $(this).data('case');
          var note = $(this).find('input:checked').val();
          if(typeof(note)=='undefined') // normalement impossible, sauf si par exemple on triche avec la barre d’outils Web Developer...
          {
            note = 'X';
          }
          var style = isNaN(note) ? note : 'N'+note ;
          modifier_notes_eleve_et_equipiers(case_ref,note,style);
          colorer_cellules();
        }
      );
      // Enregistrement
      enregistrer_saisie();
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Validation de la demande de génération d’un cartouche pour une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_imprimer').click
    (
      function()
      {
        if( !$('#box_all_eleves').is(':checked') && !$('#f_eleve input:checked:enabled').length )
        {
          $('#ajax_msg_imprimer').attr('class','erreur').html('Indiquer au moins un élève !');
          $('#zone_imprimer_retour').html('');
        }
        else
        {
          $('#zone_imprimer button').prop('disabled',true);
          $('#ajax_msg_imprimer').attr('class','loader').html('En cours&hellip;');
          $('#zone_imprimer_retour').html('');
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page='+window.PAGE,
              data : 'csrf='+window.CSRF+'&f_action=imprimer_cartouche'+'&'+$('#zone_imprimer').serialize(),
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $('#zone_imprimer button').prop('disabled',false);
                $('#ajax_msg_imprimer').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
                return false;
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                $('#zone_imprimer button').prop('disabled',false);
                if(responseJSON['statut']==false)
                {
                  $('#ajax_msg_imprimer').attr('class','alerte').html(responseJSON['value']);
                }
                else
                {
                  $('#ajax_msg_imprimer').attr('class','valide').html('Cartouches générés !');
                  $('#zone_imprimer_retour').html(responseJSON['value']);
                }
              }
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Validation de la demande de génération d’un PDF de répartition des scores
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#archiver_repart').click
    (
      function()
      {
        $('#archiver_repart').prop('disabled',true);
        $('#ajax_msg_archiver_repart').attr('class','loader').html('En cours&hellip;');
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=archiver_repart'+'&'+$('#zone_voir_repart').serialize(),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $('#archiver_repart').prop('disabled',false);
              $('#ajax_msg_archiver_repart').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              $('#archiver_repart').prop('disabled',false);
              if(responseJSON['statut']==false)
              {
                $('#ajax_msg_archiver_repart').attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                $('#ajax_msg_archiver_repart').removeAttr('class').html(responseJSON['value']);
              }
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour zipper l’ensemble des copies des élèves
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#zipper_copies_eleves').click
    (
      function()
      {
        $.fancybox( '<label class="loader">En cours&hellip;' );
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=zipper_copies_eleves'+'&f_ref='+$('#saisir_voir_ref').val()+'&f_description='+encodeURIComponent($('#saisir_voir_description').val())+'&f_groupe_nom='+encodeURIComponent($('#saisir_voir_groupe_nom').val()),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              if(responseJSON['statut']==false)
              {
                $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
              }
              else
              {
                $.fancybox( responseJSON['value'] , { minWidth:400 } );
              }
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le bouton pour afficher la zone "Saisie déportée & Archivage"
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#afficher_deport_archivage').click
    (
      function()
      {
        $('#ajax_msg_deport_archivage').removeAttr('class').html('');
        if(mode=='saisir')
        {
          $('#zone_deport_archivage').find('li.saisir').show();
          $('#zone_deport_archivage').find('li.voir').hide();
        }
        else if(mode=='voir')
        {
          $('#zone_deport_archivage').find('li.voir').show();
          $('#zone_deport_archivage').find('li.saisir').hide();
        }
        $.fancybox( { href:'#zone_deport_archivage' , minHeight:300 , minWidth:600 } );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur un bouton pour générer un CSV ou un PDF depuis la zone "Saisie déportée & Archivage"
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#zone_deport_archivage').on
    (
      'click',
      'button[id^=generer_tableau_scores]',
      function()
      {
        $('#f_archivage_action').val( $(this).attr('id') );
        $('#zone_deport_archivage button').prop('disabled',true);
        $('#ajax_msg_deport_archivage').attr('class','loader').html('En cours&hellip;');
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&'+$('#zone_deport_archivage').serialize(),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $('#zone_deport_archivage button').prop('disabled',false);
              $('#ajax_msg_deport_archivage').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              $('#zone_deport_archivage button').prop('disabled',false);
              if(responseJSON['statut']==false)
              {
                $('#ajax_msg_deport_archivage').attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                $('#ajax_msg_deport_archivage').removeAttr('class').html(responseJSON['value']);
              }
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Demande d’indiquer la liste des élèves associés à une évaluation de même nom (uniquement pour des élèves sélectionnés)
    // Reprise d’un développement initié par Alain Pottier <alain.pottier613@orange.fr>
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#indiquer_eleves_deja').click
    (
      function()
      {
        if(!$('#f_description').val())
        {
          $('#msg_indiquer_eleves_deja').attr('class','erreur').html('évaluation sans nom');
          return false;
        }
        var f_date_debut = $('#f_date_deja').val();
        if(!f_date_debut)
        {
          $('#msg_indiquer_eleves_deja').attr('class','erreur').html('date manquante');
          return false;
        }
        if(!test_dateITA(f_date_debut))
        {
          $('#msg_indiquer_eleves_deja').attr('class','erreur').html('date JJ/MM/AAAA incorrecte');
          return false;
        }
        $('button').prop('disabled',true);
        $('#msg_indiquer_eleves_deja').attr('class','loader').html('En cours&hellip;');
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=indiquer_eleves_deja'+'&f_description='+encodeURIComponent($('#f_description').val())+'&f_date_debut='+encodeURIComponent(f_date_debut),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $('button').prop('disabled',false);
              $('#msg_indiquer_eleves_deja').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              $('button').prop('disabled',false);
              if(responseJSON['statut']==false)
              {
                $('#msg_indiquer_eleves_deja').attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                // On récupère les associations élèves -> dates
                var tab_dates   = [];
                var tab_groupes = [];
                var memo_groupe_id = 0;
                for(var i in responseJSON)
                {
                  if( i != 'statut' )
                  {
                    var tab = responseJSON[i].split('_');
                    tab_dates[tab[0]] = tab[1];
                  }
                }
                // Passer en revue les lignes élève
                $('#zone_eleve input[type=checkbox]').each
                (
                  function()
                  {
                    var tab_ids = $(this).attr('id').split('_');
                    var eleve_id  = tab_ids[1];
                    var groupe_id = tab_ids[2];
                    var eleve_date = tab_dates[eleve_id];
                    if(groupe_id!=memo_groupe_id)
                    {
                      memo_groupe_id = groupe_id;
                      tab_groupes[groupe_id] = new Array(0,0);
                    }
                    $(this).next('label').removeAttr('class').next('span').html('');
                    if(typeof(eleve_date)=='undefined')
                    {
                      tab_groupes[groupe_id][0]++;
                    }
                    else
                    {
                      $(this).next('label').addClass('deja grey').next('span').html('<span>'+eleve_date+'</span>');
                      tab_groupes[groupe_id][1]++;
                    }
                  }
                );
                // Passer en revue les bilans par groupe
                for(var groupe_id in tab_groupes)
                {
                  var nb_eleves = tab_groupes[groupe_id][0]+tab_groupes[groupe_id][1];
                  var pourcentage = (nb_eleves) ? (100*tab_groupes[groupe_id][1]/nb_eleves).toFixed(0) : 0 ;
                  switch (pourcentage)
                  {
                    case '0'   : var couleur = '#C00';break;
                    case '100' : var couleur = '#080';break;
                    default    : var couleur = '#333';break;
                  }
                  $('#groupe_'+groupe_id).css('color',couleur).html('<span class="gradient_outer"><span class="gradient_inner" style="width:'+pourcentage+'px"></span></span>'+pourcentage+'%');
                }
                $('#msg_indiquer_eleves_deja').attr('class','valide').html('Affichage actualisé.');
              }
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Choix du mode de pilotage pour la saisie des résultats
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    obj_table_saisir_voir.on
    (
      'click',
      'input[name=mode_saisie]',
      function()
      {
        memo_pilotage = $(this).val();
        if(memo_pilotage=='clavier')
        {
          $('#arrow_continue').show(0);
          $('#C'+colonne+'L'+ligne).focus();
          if(IsTouch)
          {
            $('#cadre_tactile').show();
          }
        }
        else
        {
          $('#arrow_continue').hide(0);
          if(IsTouch)
          {
            $('#cadre_tactile').hide();
          }
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Choix du sens de parcours pour la saisie des résultats (si pilotage au clavier)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    obj_table_saisir_voir.on
    (
      'click',
      'input[name=arrow_continue]',
      function()
      {
        memo_direction = $(this).val();
        $('#C'+colonne+'L'+ligne).focus();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Choix de rétrécir ou pas les colonnes sur #table_saisir_voir
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    obj_table_saisir_voir.on
    (
      'click',
      '#check_largeur',
      function()
      {
        var condense = ($(this).is(':checked')) ? 'v' : 'h' ; // 'h' ou 'v' pour horizontal (non condensé) ou vertical (condensé)
        obj_table_saisir_voir.find('thead').find('dfn').each
        (
          function()
          {
            var nom    = $(this).data('nom');
            var prenom = $(this).data('prenom');
            if(condense=='v')
            {
              var identite = ( $('#saisir_voir_eleves_ordre').val()!='prenom' ) ? nom+' '+prenom : prenom+' '+nom ;
              $(this).removeClass('double').html(identite);
            }
            else
            {
              var identite = ( $('#saisir_voir_eleves_ordre').val()!='prenom' ) ? nom+'<br>'+prenom : prenom+'<br>'+nom ;
              $(this).addClass('double').html(identite);
            }
          }
        );
        // Le descriptif du PPRE en infobulle ne survit pas à cette manipulation
        obj_table_saisir_voir.find('tfoot').find('dfn').each
        (
          function()
          {
            var dispositifs = $(this).data('dispositifs');
            if(condense=='v')
            {
              $(this).removeClass('double').html( dispositifs.replaceAll(',',' - ') );
            }
            else
            {
              $(this).addClass('double').html( dispositifs.replaceAll(',','<br>') );
            }
          }
        );
        if(mode=='saisir')
        {
          obj_table_saisir_voir.find('tbody').attr('class',condense);
        }
        if(mode=='voir')
        {
          obj_table_saisir_voir.find('tbody tr td img').each
          (
            function()
            {
              var img_src_old = $(this).attr('src');
              var img_src_new = (condense=='v') ? img_src_old.replace('/h/','/v/').replace('/h_','/v_') : img_src_old.replace('/v/','/h/').replace('/v_','/h_') ;
              $(this).attr('src',img_src_new);
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Choix de rétrécir ou pas les lignes sur #table_saisir_voir
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    obj_table_saisir_voir.on
    (
      'click',
      '#check_hauteur',
      function()
      {
        if($(this).is(':checked'))
        {
          obj_table_saisir_voir.find('div[data-mode=complet]').css('display','none');       // .hide(0) s’avère bcp plus lent dans FF et pose pb si bcp élèves / items ...
          if(!IsTouch)
          {
            obj_table_saisir_voir.find('b').attr('class','bulle');
          }
        }
        else
        {
          obj_table_saisir_voir.find('b').removeClass('bulle').removeAttr('title');
          obj_table_saisir_voir.find('div[data-mode=complet]').css('display','block'); // .show(0) s’avère bcp plus lent dans FF et pose pb si bcp élèves / items ...
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Gérer la mise en valeur des entêtes de ligne et de colonne, que ce soit au clavier ou à la souris
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function valoriser_th(input_id)
    {
      colonne = entier( input_id.substring(1,input_id.indexOf('L')) );
      ligne   = entier( input_id.substring(input_id.indexOf('L')+1) );
      obj_table_saisir_voir.find('th').removeClass('highlight');
      obj_table_saisir_voir.find('thead').find('tr').children('th').eq(colonne-1).addClass('highlight');
      obj_table_saisir_voir.find('tbody').children('tr').eq(ligne-1).find('th').addClass('highlight');
    }

    obj_table_saisir_voir.on
    (
      'mouseover',
      'tbody td',
      function()
      {
        if(mode=='saisir')
        {
          var input_id  = $(this).children('input').attr('id');
          valoriser_th(input_id);
        }
      }
    );

    obj_table_saisir_voir.on
    (
      'mouseout',
      'tbody',
      function()
      {
        if(mode=='saisir')
        {
          obj_table_saisir_voir.find('th').removeClass('highlight');
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Gérer la saisie des résultats au clavier ou avec un dispositif tactile dans le tableau principal
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function focus_cellule_suivante_en_evitant_sortie_tableau()
    {
      if(colonne==0)
      {
        colonne = nb_colonnes;
        ligne = (ligne!=1) ? ligne-1 : nb_lignes ;
      }
      else if(colonne>nb_colonnes)
      {
        colonne = 1;
        ligne = (ligne!=nb_lignes) ? ligne+1 : 1 ;
      }
      else if(ligne==0)
      {
        ligne = nb_lignes;
        colonne = (colonne!=1) ? colonne-1 : nb_colonnes ;
        if(nb_lignes>nb_lignes_max)
        {
          window.scrollTo(0,10000); /* jQuery TH Float Plugin */
        }
      }
      else if(ligne>nb_lignes)
      {
        ligne = 1;
        colonne = (colonne!=nb_colonnes) ? colonne+1 : 1 ;
        if(nb_lignes>nb_lignes_max)
        {
          window.scrollTo(0,150); /* jQuery TH Float Plugin */
        }
      }
      var new_id = 'C'+colonne+'L'+ligne;
      $('#'+new_id).focus();
      valoriser_th(new_id);
      // photo
      var tab = $('#'+new_id).attr('name').split('x');
      if( tab[1] != memo_eleve )
      {
        memo_eleve = tab[1];
        if($('#voir_photo').length==0)
        {
          charger_photo_eleve(memo_eleve,'maj');
        }
      }
    }

    $('#cadre_tactile').on
    (
      'click',
      'span',
      function()
      {
        var code = entier( $(this).attr('id').substring(4) ); // "kbd_" + ref
        navigation_clavier_tableau_principal(code);
      }
    );

    obj_table_saisir_voir.on
    (
      'click',
      'tbody td input',
      function()
      {
        var input_id = $(this).attr('id');
        colonne = entier( input_id.substring(1,input_id.indexOf('L')) );
        ligne   = entier( input_id.substring(input_id.indexOf('L')+1) );
        // photo
        var tab = $(this).attr('name').split('x');
        if( tab[1] != memo_eleve )
        {
          memo_eleve = tab[1];
          if($('#voir_photo').length==0)
          {
            charger_photo_eleve(memo_eleve,'maj');
          }
        }
      }
    );

    obj_table_saisir_voir.on
    (
      'keydown',  // keydown au lieu de keyup permet de laisser appuyer sur la touche pour répéter une action
      'tbody td input',
      function(e)
      {
        if(memo_pilotage=='clavier')
        {
          var input_id = $(this).attr('id');
          colonne = entier( input_id.substring(1,input_id.indexOf('L')) );
          ligne   = entier( input_id.substring(input_id.indexOf('L')+1) );
          navigation_clavier_tableau_principal(e.which);
        }
      }
    );

    function navigation_clavier_tableau_principal(touche_code)
    {
      var findme = '.'+touche_code+'.';
      var endroit_report_note = 'cellule';
      if( window.keycode_search.indexOf(findme) != -1 )
      {
        // Une touche d’item a été pressée
        switch (touche_code)
        {
          case   8: var note = 'X' ; var style = note; break; // backspace
          case  46: var note = 'X' ; var style = note; break; // suppr
          case  65: var note = 'AB'; var style = note; break; // A
          case  68: var note = 'DI'; var style = note; break; // D
          case  78: var note = 'NN'; var style = note; break; // N
          case  69: var note = 'NE'; var style = note; break; // E
          case  70: var note = 'NF'; var style = note; break; // F
          case  82: var note = 'NR'; var style = note; break; // R
          case  80: var note = 'PA'; var style = note; break; // P
          default : var note = window.tab_keycode_note[touche_code]; var style = 'N'+note; break
        }
        endroit_report_note = $('input[name=f_endroit_report_note]:checked').val();
        if( (typeof(endroit_report_note)=='undefined') || (endroit_report_note=='cellule') )
        {
          // pour une seule case
          var case_ref = 'C'+colonne+'L'+ligne;
          modifier_notes_eleve_et_equipiers(case_ref,note,style);
          if(memo_direction=='down')
          {
            ligne++;
          }
          else
          {
            colonne++;
          }
        }
        else if(endroit_report_note=='tableau')
        {
          // pour toutes les cases vides du tableau
          obj_table_saisir_voir.find('tbody td input').each
          (
            function()
            {
              if($(this).val()=='X')
              {
                $(this).val(note).attr('class',style);
                $(this).parent().css('background-color','#F6D');
                var case_ref = $(this).attr('id');
                $('#plan_'+case_ref).val(note).attr('class',style);
                // modifier_notes_eleve_et_equipiers() non justifié ici
              }
            }
          );
        }
        else if(endroit_report_note=='colonne')
        {
          // pour toutes les cases vides d’une colonne
          obj_table_saisir_voir.find('tbody td input[id^=C'+colonne+'L]').each
          (
            function()
            {
              if($(this).val()=='X')
              {
                $(this).val(note).attr('class',style);
                $(this).parent().css('background-color','#F6D');
                var case_ref = $(this).attr('id');
                $('#plan_'+case_ref).val(note).attr('class',style);
                // modifier_notes_eleve_et_equipiers() moins justifié ici
              }
            }
          );
          colonne++;
        }
        else if(endroit_report_note=='ligne')
        {
          // pour toutes les cases vides d’une ligne
          obj_table_saisir_voir.find('tbody td input[id$=L'+ligne+']').each
          (
            function()
            {
              if($(this).val()=='X')
              {
                $(this).val(note).attr('class',style);
                $(this).parent().css('background-color','#F6D');
                var case_ref = $(this).attr('id');
                $('#plan_'+case_ref).val(note).attr('class',style);
                // modifier_notes_eleve_et_equipiers() non justifié ici
              }
            }
          );
          ligne++;
        }
        if(modification==false)
        {
          $('#fermer_zone_saisir_voir').attr('class','annuler').html('Annuler / Retour');
          $('#kbd_27').attr('class','img annuler');
          modification = true;
          $(window).on('beforeunload', confirmOnLeave );
          $('#basculer_presentation').prop('disabled',true);
        }
        $('#ajax_msg_saisir_voir').removeAttr('class').html('');
        focus_cellule_suivante_en_evitant_sortie_tableau();
        endroit_report_note = 'cellule';
      }
      else if('.37.38.39.40.'.indexOf(findme)!=-1)
      {
        // Une flèche a été pressée
        switch (touche_code)
        {
          case 37: colonne--; break; // flèche gauche
          case 38: ligne--;   break; // flèche haut
          case 39: colonne++; break; // flèche droite
          case 40: ligne++;   break; // flèche bas
        }
        focus_cellule_suivante_en_evitant_sortie_tableau();
      }
      else if(touche_code==13)  // touche entrée
      {
        // La touche entrée a été pressée
        $('#valider_saisir').click();
      }
      else if(touche_code==27)
      {
        // La touche escape a été pressée
        $('#fermer_zone_saisir_voir').click();
      }
      else if('.67.76.84.'.indexOf(findme)!=-1)
      {
        // Une touche de préparation de modification par lot a été pressée
        switch (touche_code)
        {
          case 67: endroit_report_note = 'colonne'; break; // C
          case 76: endroit_report_note = 'ligne';   break; // L
          case 84: endroit_report_note = 'tableau'; break; // T
        }
      }
      else if('.16.17.18.20.144.'.indexOf(findme)!=-1)
      {
        // Une touche Shift / Ctrl / Alt / CapsLock / VerrNum [*] a été pressée
        // [*] 144 est aussi un signal particulier envoyé par un clavier étendu en parallèle à chaque appui sur une touche du pavé numérique pour signaler qu’il est actif
        endroit_report_note = $('input[name=f_endroit_report_note]:checked').val();
      }
      $('#f_report_'+endroit_report_note).prop('checked',true);
      return false; // Evite notamment qu’IE fasse "page précédente" si on appuie sur backspace.
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Gérer la saisie des résultats à la souris dans le tableau principal
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Remplacer la cellule par les images de choix
    obj_table_saisir_voir.on
    (
      'mouseover',
      'tbody td.td_clavier',
      function()
      {
        if(memo_pilotage=='souris')
        {
          // Test si un précédent td n’a pas été remis en place (js a du mal à suivre le mouseleave sinon)
          if(memo_input_id)
          {
            $('td#td_'+memo_input_id).attr('class','td_clavier').children('div').remove();
            $('input#'+memo_input_id).show();
            memo_input_id = false;
            if(nb_lignes>nb_lignes_max)
            {
              obj_table_saisir_voir.stickyTableHeaders('destroy');
            }
          }
          else
          {
            var objet_td    = $(this);
            var objet_input = objet_td.children('input');
            // Récupérer les infos associées
            memo_input_id = objet_input.attr('id');
            colonne = entier( memo_input_id.substring(1,memo_input_id.indexOf('L')) );
            ligne   = entier( memo_input_id.substring(memo_input_id.indexOf('L')+1) );
            var valeur = objet_input.val();
            objet_input.hide();
            objet_td.attr('class','td_souris').append( $('#td_souris_container').html() ).find('img[alt='+valeur+']').addClass('on');
            if(nb_lignes>nb_lignes_max)
            {
              obj_table_saisir_voir.stickyTableHeaders();
            }
            // photo
            var tab = objet_input.attr('name').split('x');
            if( tab[1] != memo_eleve )
            {
              memo_eleve = tab[1];
              if($('#voir_photo').length==0)
              {
                charger_photo_eleve(memo_eleve,'maj');
              }
            }
          }
        }
      }
    );

    // Revenir à la cellule initiale ; mouseout ne fonctionne pas à cause des éléments contenus dans le div ; mouseleave est mieux, mais pb qd même avec les select du calendrier
    obj_table_saisir_voir.on
    (
      'mouseleave',
      'tbody td',
      function()
      {
        if(memo_pilotage=='souris')
        {
          if(memo_input_id)
          {
            $('td#td_'+memo_input_id).attr('class','td_clavier').children('div').remove();
            $('input#'+memo_input_id).show();
            memo_input_id = false;
          }
        }
      }
    );

    // Renvoyer l’information dans la ou les cellule(s)
    obj_table_saisir_voir.on
    (
      'click',
      'div.td_souris img',
      function()
      {
        var note = $(this).attr('alt');
        var style = isNaN(note) ? note : 'N'+note ;
        var endroit_report_note = $('input[name=f_endroit_report_note]:checked').val();
        if( (typeof(endroit_report_note)=='undefined') || (endroit_report_note=='cellule') )
        {
          // pour une seule case
          modifier_notes_eleve_et_equipiers(memo_input_id,note,style);
          $(this).parent().children('img').removeAttr('class');
          $(this).addClass('on').parent().parent().css('background-color','#F6D');
        }
        else
        {
          if(endroit_report_note=='tableau')
          {
            // pour toutes les cases vides du tableau
            obj_table_saisir_voir.find('tbody td input').each
            (
              function()
              {
                if($(this).val()=='X')
                {
                  $(this).val(note).attr('class',style);
                  $(this).parent().css('background-color','#F6D');
                  var case_ref = $(this).attr('id');
                  $('#plan_'+case_ref).val(note).attr('class',style);
                  // modifier_notes_eleve_et_equipiers() non justifié ici
                }
              }
            );
          }
          else if(endroit_report_note=='colonne')
          {
            // pour toutes les cases vides d’une colonne
            obj_table_saisir_voir.find('tbody td input[id^=C'+colonne+'L]').each
            (
              function()
              {
                if($(this).val()=='X')
                {
                  $(this).val(note).attr('class',style);
                  $(this).parent().css('background-color','#F6D');
                  var case_ref = $(this).attr('id');
                  $('#plan_'+case_ref).val(note).attr('class',style);
                  // modifier_notes_eleve_et_equipiers() moins justifié ici
                }
              }
            );
          }
          else if(endroit_report_note=='ligne')
          {
            // pour toutes les cases vides d’une ligne
            obj_table_saisir_voir.find('tbody td input[id$=L'+ligne+']').each
            (
              function()
              {
                if($(this).val()=='X')
                {
                  $(this).val(note).attr('class',style);
                  $(this).parent().css('background-color','#F6D');
                  var case_ref = $(this).attr('id');
                  $('#plan_'+case_ref).val(note).attr('class',style);
                  // modifier_notes_eleve_et_equipiers() non justifié ici
                }
              }
            );
          }
        }
        if(modification==false)
        {
          $('#fermer_zone_saisir_voir').attr('class','annuler').html('Annuler / Retour');
          $('#kbd_27').attr('class','img annuler');
          modification = true;
          $(window).on('beforeunload', confirmOnLeave );
          $('#basculer_presentation').prop('disabled',true);
        }
        $('#ajax_msg_saisir_voir').removeAttr('class').html('');
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur le lien pour mettre à jour l’ordre des items d’une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_ordre').click
    (
      function()
      {
        if(modification==false)
        {
          $('#ajax_msg_ordonner').attr('class','alerte').html('Aucune modification effectuée !');
        }
        else
        {
          // On récupère la liste des items dans l’ordre de la page
          var tab_id = [];
          $('#sortable_v').children('li').each
          (
            function()
            {
              var test_id = $(this).attr('id');
              if(typeof(test_id)!='undefined')
              {
                tab_id.push(test_id.substring(1));
              }
            }
          );
          $('#zone_ordonner button').prop('disabled',true);
          $('#ajax_msg_ordonner').attr('class','loader').html('En cours&hellip;');
          var ref = $('#ordre_ref').val();
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page='+window.PAGE,
              data : 'csrf='+window.CSRF+'&f_action=enregistrer_ordre'+'&f_ref='+ref+'&f_prof_liste='+tab_profs[ref]+'&tab_id='+tab_id,
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $('#zone_ordonner button').prop('disabled',false);
                $('#ajax_msg_ordonner').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
                return false;
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                $('#zone_ordonner button').prop('disabled',false);
                if(responseJSON['statut']==false)
                {
                  $('#ajax_msg_ordonner').attr('class','alerte').html(responseJSON['value']);
                }
                else
                {
                  modification = false;
                  $('#devoir_'+ref).parent().addClass('new');
                  $('#ajax_msg_ordonner').attr('class','valide').html('Ordre enregistré !');
                  $('#fermer_zone_ordonner').attr('class','retourner').html('Retour');
                }
              }
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur le bouton pour mettre à jour les résultats des élèves à une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_saisir').click
    (
      function()
      {
        enregistrer_saisie();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du formulaire principal
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Le formulaire qui va être analysé et traité en AJAX
    var formulaire = $('#form_gestion');

    // Vérifier la validité du formulaire (avec jquery.validate.js)
    var validation = formulaire.validate
    (
      {
        rules :
        {
          f_choix_devoir_visible : { required:true },
          f_choix_saisie_visible : { required:true },
          f_date_devoir          : { required:true , dateITA:true },
          f_date_devoir_visible  : { required:function(){return $('#f_choix_devoir_visible').val()=='perso';} , dateITA:true },
          f_date_saisie_visible  : { required:function(){return $('#f_choix_saisie_visible').val()=='perso';} , dateITA:true },
          f_date_autoeval        : { required:function(){return !$('#box_autoeval').is(':checked');} , dateITA:true },
          f_heure_autoeval       : { required:function(){return !$('#box_autoeval').is(':checked');} , digits:true , range:[0,23] },
          f_minute_autoeval      : { required:function(){return !$('#box_autoeval').is(':checked');} , digits:true , range:[0,59] },
          f_voir_repartition     : { required:true },
          f_groupe               : { required:true },
          f_eleve_liste          : { required:true },
          f_eleves_ordre         : { required:true },
          f_equipe               : { required:false },
          f_description          : { required:true , maxlength:60 },
          f_diagnostic           : { required:false },
          f_pluriannuel          : { required:false },
          f_prof_liste           : { required:false },
          f_compet_liste         : { required:true },
          f_mode_discret         : { required:false },
          f_doc_sujet            : { required:false , url:true },
          f_doc_corrige          : { required:false , url:true },
          f_sujets_nombre        : { required:false },
          f_corriges_nombre      : { required:false },
          f_copies_nombre        : { required:false }
        },
        messages :
        {
          f_choix_devoir_visible : { required:'choix manquant' },
          f_choix_saisie_visible : { required:'choix manquant' },
          f_date_devoir          : { required:'date manquante' , dateITA:'format JJ/MM/AAAA non respecté' },
          f_date_devoir_visible  : { required:'date manquante' , dateITA:'format JJ/MM/AAAA non respecté' },
          f_date_saisie_visible  : { required:'date manquante' , dateITA:'format JJ/MM/AAAA non respecté' },
          f_date_autoeval        : { required:'date manquante' , dateITA:'format JJ/MM/AAAA non respecté' },
          f_heure_autoeval       : { required:function(){return !$('#box_autoeval').is(':checked');} , digits:'heure incorrecte' , range:'heure incorrecte' },
          f_minute_autoeval      : { required:function(){return !$('#box_autoeval').is(':checked');} , digits:'minutes incorrectes' , range:'minutes incorrectes' },
          f_voir_repartition     : { required:'choix manquant' },
          f_groupe               : { required:'groupe manquant' },
          f_eleve_liste          : { required:'élève(s) manquant(s)' },
          f_eleves_ordre         : { required:'ordre manquant' },
          f_equipe               : { },
          f_description          : { required:'nom manquant' , maxlength:'60 caractères maximum' },
          f_diagnostic           : { },
          f_pluriannuel          : { },
          f_prof_liste           : { },
          f_compet_liste         : { required:'item(s) manquant(s)' },
          f_mode_discret         : { },
          f_doc_sujet            : { url:' URL sujet invalide' },
          f_doc_corrige          : { url:' URL corrigé invalide' },
          f_sujets_nombre        : { },
          f_corriges_nombre      : { },
          f_copies_nombre        : { }
        },
        errorElement : 'label',
        errorClass : 'erreur',
        errorPlacement : function(error,element)
        {
          if( '.f_date_devoir.f_date_devoir_visible.f_date_saisie_visible.f_date_autoeval.'.indexOf('.'+element.attr('id')+'.') !== -1 ) { element.next().after(error); }
          else if(element.attr('type')=='radio') {element.parent().parent().append(error);}
          else {element.after(error);}
        }
      }
    );

    // Options d’envoi du formulaire (avec jquery.form.js)
    var ajaxOptions =
    {
      url : 'ajax.php?page='+window.PAGE+'&csrf='+window.CSRF,
      type : 'POST',
      dataType : 'json',
      clearForm : false,
      resetForm : false,
      target : '#ajax_msg_gestion',
      beforeSerialize : action_form_avant_serialize,
      beforeSubmit : test_form_avant_envoi,
      error : retour_form_erreur,
      success : retour_form_valide
    };

    // Envoi du formulaire (avec jquery.form.js)
    formulaire.submit
    (
      function()
      {
        if (!please_wait)
        {
          $(this).ajaxSubmit(ajaxOptions);
          return false;
        }
        else
        {
          return false;
        }
      }
    );

    // Fonction précédent le traitement du formulaire (avec jquery.form.js)
    function action_form_avant_serialize(jqForm, options)
    {
      if($('#box_autoeval').is(':checked'))
      {
        $('#f_date_autoeval').val('00/00/0000');
      }
    }

    // Fonction précédant l’envoi du formulaire (avec jquery.form.js)
    function test_form_avant_envoi(formData, jqForm, options)
    {
      $('#ajax_msg_gestion').removeAttr('class').html('');
      var readytogo = validation.form();
      if(readytogo)
      {
        if( $('#f_diagnostic').is(':checked') && $('#f_pluriannuel').is(':checked') )
        {
          $('#ajax_msg_gestion').attr('class','erreur').html('Une évaluation ne peut pas être diagnostique et pluriannuelle.');
          return false;
        }
        else
        {
          please_wait = true;
          $('#form_gestion button').prop('disabled',true);
          $('#ajax_msg_gestion').attr('class','loader').html('En cours&hellip;');
        }
      }
      return readytogo;
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_erreur(jqXHR, textStatus, errorThrown)
    {
      please_wait = false;
      $('#form_gestion button').prop('disabled',false);
      $('#ajax_msg_gestion').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_valide(responseJSON)
    {
      initialiser_compteur();
      please_wait = false;
      $('#form_gestion button').prop('disabled',false);
      if(responseJSON['statut']==false)
      {
        $('#ajax_msg_gestion').attr('class','alerte').html(responseJSON['value']).show();
      }
      else
      {
        $('#ajax_msg_gestion').attr('class','valide').html('Demande réalisée !');
        switch (mode)
        {
          case 'ajouter':
            $('#table_action tbody tr.vide').remove(); // En cas de tableau avec une ligne vide pour la conformité XHTML
          case 'dupliquer':
            var new_tds = responseJSON['html'];
            if(window.TYPE=='groupe')
            {
              var groupe_id = $('#f_groupe option:selected').val();
              var new_tds = new_tds.replace('>{{GROUPE_NOM}}<','>'+window.tab_groupe[groupe_id]+'<'); // on ne prend pas '<td>' en entier car il y a un attribut class
            }
            var new_tr = '<tr class="new">'+new_tds+'</tr>';
            $('#table_action tbody').prepend(new_tr);
            var ref = responseJSON['ref'];
            tab_items[ref]   = responseJSON['items'];
            tab_profs[ref]   = responseJSON['profs'];
            tab_sujet[ref]   = responseJSON['sujet'];
            tab_corrige[ref] = responseJSON['corrige'];
            tab_eleves[ref]  = responseJSON['eleves'];
            break;
          case 'modifier':
            var new_tds = responseJSON['html'];
            if(window.TYPE=='groupe')
            {
              var groupe_id = $('#f_groupe option:selected').val();
              var new_tds = new_tds.replace('>{{GROUPE_NOM}}<','>'+window.tab_groupe[groupe_id]+'<'); // on ne prend pas '<td>' en entier car il y a un attribut class
            }
            var ref = responseJSON['ref'];
            $('#devoir_'+ref).parent().addClass('new').html(new_tds);
            tab_items[ref]   = responseJSON['items'];
            tab_profs[ref]   = responseJSON['profs'];
            tab_sujet[ref]   = responseJSON['sujet'];
            tab_corrige[ref] = responseJSON['corrige'];
            tab_eleves[ref]  = responseJSON['eleves'];
            break;
          case 'supprimer':
          case 'supprimer_pluriannuel':
            $('#devoir_'+$('#f_ref').val()).parent().remove();
            break;
        }
        tableau_maj();
        if( (mode!='dupliquer') || !$('#f_duplication_multiple').is(':checked') )
        {
          $.fancybox.close();
          mode = false;
        }
      }
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur le bouton pour importer une évaluation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#valider_importer_evaluation').click
    (
      function()
      {
        var f_fichier = $('#f_fichier').val();
        if(!f_fichier)
        {
          $('#ajax_msg_importer_evaluation').attr('class','erreur').html('Renseigner le nom du fichier !');
          $('#f_fichier').focus();
          return false;
        }
        else
        {
          $('#zone_importer button').prop('disabled',true);
          $('#ajax_msg_importer_evaluation').attr('class','loader').html('En cours&hellip;');
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page='+window.PAGE,
              data : 'csrf='+window.CSRF+'&f_action=importer_evaluation'+'&f_fichier='+encodeURIComponent(f_fichier),
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $('#zone_importer button').prop('disabled',false);
                $('#ajax_msg_importer_evaluation').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
                return false;
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                $('#zone_importer button').prop('disabled',false);
                if(responseJSON['statut']==false)
                {
                  $('#ajax_msg_importer_evaluation').attr('class','alerte').html(responseJSON['value']);
                }
                else
                {
                  // retour de la création d'évaluation
                  $('#table_action tbody tr.vide').remove(); // En cas de tableau avec une ligne vide pour la conformité XHTML
                  var new_td = responseJSON['html'];
                  var new_tr = '<tr class="new">'+new_td+'</tr>';
                  $('#table_action tbody').prepend(new_tr);
                  tab_items   = JSON.parse(responseJSON['tab_items']);
                  tab_profs   = JSON.parse(responseJSON['tab_profs']);
                  tab_sujet   = JSON.parse(responseJSON['tab_sujet']);
                  tab_corrige = JSON.parse(responseJSON['tab_corrige']);
                  tab_eleves  = JSON.parse(responseJSON['tab_eleves']);
                  // retour de la saisie de notes
                  $('#devoir_'+responseJSON['ref']).prev().replaceWith(responseJSON['td']);
                  // terminé !
                  $('#ajax_msg_importer_evaluation').attr('class','valide').html('Évaluation importée !');
                  $('#fermer_zone_importer').attr('class','retourner').html('Retour');
                }
              }
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur le bouton pour envoyer un import csv (saisie déportée, formulaire #zone_deport_archivage)
    // Upload d’un fichier (avec jquery.form.js)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Le formulaire qui va être analysé et traité en AJAX
    var formulaire_importer_scores = $('#zone_deport_archivage');

    // Options d’envoi du formulaire (avec jquery.form.js)
    var ajaxOptions_importer_scores =
    {
      url : 'ajax.php?page='+window.PAGE+'&csrf='+window.CSRF,
      type : 'POST',
      dataType : 'json',
      clearForm : false,
      resetForm : false,
      target : '#ajax_msg_deport_archivage',
      error : retour_form_erreur_importer_scores,
      success : retour_form_valide_importer_scores
    };

    // Vérifications précédant l’envoi du formulaire, déclenchées au choix d’un fichier
    $('#f_importer_scores').change
    (
      function()
      {
        var file = this.files[0];
        if( typeof(file) == 'undefined' )
        {
          $('#ajax_msg_deport_archivage').removeAttr('class').html('');
          return false;
        }
        else
        {
          var fichier_nom = file.name;
          var fichier_ext = fichier_nom.split('.').pop().toLowerCase();
          if( '.csv.txt.'.indexOf('.'+fichier_ext+'.') == -1 )
          {
            $('#ajax_msg_deport_archivage').attr('class','erreur').html('Le fichier "'+escapeHtml(fichier_nom)+'" n’a pas l’extension "csv" ou "txt".');
            return false;
          }
          else
          {
            $('#f_archivage_action').val('importer_saisie_csv');
            $('#zone_deport_archivage button').prop('disabled',true);
            $('#ajax_msg_deport_archivage').attr('class','loader').html('En cours&hellip;');
            formulaire_importer_scores.submit();
          }
        }
      }
    );

    // Envoi du formulaire (avec jquery.form.js)
    formulaire_importer_scores.submit
    (
      function()
      {
        $(this).ajaxSubmit(ajaxOptions_importer_scores);
        return false;
      }
    );

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_erreur_importer_scores(jqXHR, textStatus, errorThrown)
    {
      $('#f_importer_scores').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      $('#zone_deport_archivage button').prop('disabled',false);
      $('#ajax_msg_deport_archivage').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_valide_importer_scores(responseJSON)
    {
      $('#f_importer_scores').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      $('#zone_deport_archivage button').prop('disabled',false);
      if(responseJSON['statut']==false)
      {
        $('#ajax_msg_deport_archivage').attr('class','alerte').html(responseJSON['value']);
      }
      else
      {
        initialiser_compteur();
        var nb_notes_remontees = 0;
        var nb_notes_reportees = 0;
        for(var i in responseJSON)
        {
          if( i != 'statut' )
          {
            var tab_valeur = responseJSON[i].split('.');
            if(tab_valeur.length==3)
            {
              nb_notes_remontees++;
              var eleve_id = tab_valeur[0];
              var item_id  = tab_valeur[1];
              var score    = tab_valeur[2];
              var champ = obj_table_saisir_voir.find('input[name='+item_id+'x'+eleve_id+']');
              if(champ.length)
              {
                nb_notes_reportees++;
                switch (score)
                {
                  case 'A': champ.val('AB').attr('class','AB'); break;
                  case 'D': champ.val('DI').attr('class','DI'); break;
                  case 'N': champ.val('NN').attr('class','NN'); break;
                  case 'E': champ.val('NE').attr('class','NE'); break;
                  case 'F': champ.val('NF').attr('class','NF'); break;
                  case 'R': champ.val('NR').attr('class','NR'); break;
                  case 'P': champ.val('PA').attr('class','PA'); break;
                  default : champ.val(score).attr('class','N'+score); break;
                }
                champ.parent().css('background-color','#F6D');
              }
              if(modification==false)
              {
                modification = true;
                $(window).on('beforeunload', confirmOnLeave );
                $('#basculer_presentation').prop('disabled',true);
              }
            }
          }
        }
        var s_remontees = (nb_notes_remontees>1) ? 's' : '' ;
        var s_reportees = (nb_notes_remontees>1) ? 's' : '' ;
        $('#ajax_msg_deport_archivage').attr('class','valide').html(nb_notes_remontees+' saisie'+s_remontees+' trouvée'+s_remontees+' dans le fichier ; '+nb_notes_reportees+' note'+s_reportees+' reportée'+s_reportees+' dans le tableau.<br>N’oubliez pas d’enregistrer !');
      }
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du formulaire zone_upload
    // Traitement du clic sur un bouton pour envoyer un sujet ou un corrigé de devoir pour la classe
    // Upload d’un fichier (avec jquery.form.js)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Le formulaire qui va être analysé et traité en AJAX
    var formulaire_document_collectif = $('#zone_upload');

    // Options d’envoi du formulaire (avec jquery.form.js)
    var ajaxOptions_document_collectif =
    {
      url : 'ajax.php?page='+window.PAGE+'&csrf='+window.CSRF,
      type : 'POST',
      dataType : 'json',
      clearForm : false,
      resetForm : false,
      target : '#ajax_document_collectif_upload',
      error : retour_form_erreur_document_collectif,
      success : retour_form_valide_document_collectif
    };

    // Vérifications précédant l’envoi du formulaire, déclenchées au choix d’un fichier
    $('#f_uploader_sujet , #f_uploader_corrige').change
    (
      function()
      {
        var file = this.files[0];
        if( typeof(file) == 'undefined' )
        {
          $('#ajax_document_collectif_upload').removeAttr('class').html('');
          return false;
        }
        else
        {
          var fichier_nom = file.name;
          var fichier_ext = fichier_nom.split('.').pop().toLowerCase();
          var chaine_extensions = ('.'+window.extensions_interdites+'.').replaceAll('|','.');
          if( chaine_extensions.indexOf('.'+fichier_ext+'.') !== -1 )
          {
            $('#ajax_document_collectif_upload').attr('class','erreur').html('Format de fichier "'+fichier_ext+'" interdit.');
            return false;
          }
          else
          {
            var doc_objet = $(this).attr('id').substring(11); // f_uploader_*
            $('#f_doc_objet').val(doc_objet);
            $('#zone_upload button').prop('disabled',true);
            $('#ajax_document_collectif_upload').attr('class','loader').html('En cours&hellip;');
            formulaire_document_collectif.submit();
          }
        }
      }
    );

    // Envoi du formulaire (avec jquery.form.js)
    formulaire_document_collectif.submit
    (
      function()
      {
        $(this).ajaxSubmit(ajaxOptions_document_collectif);
        return false;
      }
    );

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_erreur_document_collectif(jqXHR, textStatus, errorThrown)
    {
      $('#f_uploader_sujet').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      $('#f_uploader_corrige').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      activer_boutons_upload( $('#uploader_ref').val() );
      $('#ajax_document_collectif_upload').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_valide_document_collectif(responseJSON)
    {
      $('#f_uploader_sujet').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      $('#f_uploader_corrige').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      if(responseJSON['statut']==false)
      {
        $('#ajax_document_collectif_upload').attr('class','alerte').html(responseJSON['value']);
      }
      else
      {
        initialiser_compteur();
        $('#ajax_document_collectif_upload').attr('class','valide').html('Document enregistré.');
        var ref   = responseJSON['ref'];
        var objet = responseJSON['objet'];
        var url   = responseJSON['url'];
        var ext   = url.split('.').pop().toLowerCase();
        if(objet=='sujet') { var alt='sujet';   var title='Sujet';   tab_sujet[ref]   = url; }
        else               { var alt='corrigé'; var title='Corrigé'; tab_corrige[ref] = url; }
        var lien = '<a href="'+url+'" target="_blank" rel="noopener noreferrer" class="no_puce"><img alt="'+alt+'" src="./_img/document/'+objet+'_oui.png"'+infobulle(title+' commun.')+'></a>';
        $('#span_'+objet).html(lien);
        $('#devoir_'+ref).parent().addClass('new');
        $('#devoir_'+ref).prev().prev().children('span[data-objet='+objet+']').html(lien);
        if ( '.doc.docx.odg.odp.ods.odt.ppt.pptx.rtf.sxc.sxd.sxi.sxw.xls.xlsx.'.indexOf('.'+ext+'.') !== -1 )
        {
          $.prompt(
            'Votre fichier a bien été joint au devoir.<br>Néanmoins, pour être consulté, il nécessite un ordinateur équipé d’une suite bureautique adaptée.<br>Pour une meilleure accessibilité, il serait préférable de le convertir au format PDF.',
            {
              title  : 'Information'
            }
          );
        }
      }
      activer_boutons_upload( $('#uploader_ref').val() );
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur un bouton pour retirer un sujet ou un corrigé de devoir pour la classe
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#bouton_supprimer_sujet , #bouton_supprimer_corrige').click
    (
      function()
      {
        $('#zone_upload button').prop('disabled',true);
        $('#ajax_document_collectif_upload').attr('class','loader').html('En cours&hellip;');
        var objet = $(this).attr('id').substring(17); // bouton_supprimer_*
        var ref   = $('#uploader_ref').val();
        var url   = (objet=='sujet') ? tab_sujet[ref] : tab_corrige[ref] ;
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=retirer_document'+'&f_doc_objet='+objet+'&f_ref='+ref+'&f_doc_url='+encodeURIComponent(url),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $('#ajax_document_collectif_upload').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              activer_boutons_upload(ref);
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              if(responseJSON['statut']==false)
              {
                $('#ajax_document_collectif_upload').attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                $('#ajax_document_collectif_upload').attr('class','valide').html('Document retiré.');
                if(objet=='sujet') { var alt='sujet';   tab_sujet[ref] = ''; }
                else               { var alt='corrigé'; tab_corrige[ref] = ''; }
                var lien = '<img alt="'+alt+'" src="./_img/document/'+objet+'_non.png">';
                $('#span_'+objet).html(lien);
                $('#devoir_'+ref).parent().addClass('new');
                $('#devoir_'+ref).prev().prev().children('span[data-objet='+objet+']').html('');
              }
              activer_boutons_upload(ref);
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur un bouton pour référencer un lien de sujet ou corrigé de devoir pour la classe
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#bouton_referencer_sujet , #bouton_referencer_corrige').click
    (
      function()
      {
        var objet = $(this).attr('id').substring(18);
        var ref   = $('#uploader_ref').val();
        var url   = $('#f_adresse_'+objet).val();
        if(url == '')
        {
          $('#ajax_document_collectif_upload').attr('class','erreur').html('Adresse manquante !');
          $('#f_adresse_'+objet).focus();
          return false;
        }
        else if(!testURL(url))
        {
          $('#ajax_document_collectif_upload').attr('class','erreur').html('Adresse incorrecte !');
          $('#f_adresse_'+objet).focus();
          return false;
        }
        else
        {
          $('#zone_upload button').prop('disabled',true);
          $('#ajax_document_collectif_upload').attr('class','loader').html('En cours&hellip;');
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page='+window.PAGE,
              data : 'csrf='+window.CSRF+'&f_action=referencer_document'+'&f_doc_objet='+objet+'&f_ref='+ref+'&f_doc_url='+encodeURIComponent(url),
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $('#ajax_document_collectif_upload').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
                activer_boutons_upload(ref);
                return false;
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                if(responseJSON['statut']==false)
                {
                  $('#ajax_document_collectif_upload').attr('class','alerte').html(responseJSON['value']);
                }
                else
                {
                  $('#ajax_document_collectif_upload').attr('class','valide').html('Document référencé.');
                  if(objet=='sujet') { var alt='sujet';   var title='Sujet';   tab_sujet[ref] = url; }
                  else               { var alt='corrigé'; var title='Corrigé'; tab_corrige[ref] = url; }
                  var lien        = '<a href="'+url+'" target="_blank" rel="noopener noreferrer" class="no_puce"><img alt="'+alt+'" src="./_img/document/'+objet+'_oui.png"'+infobulle(title+' commun.')+'></a>';
                  $('#span_'+objet).html(lien);
                  $('#devoir_'+ref).parent().addClass('new');
                  $('#devoir_'+ref).prev().prev().children('span[data-objet='+objet+']').html(lien);
                }
                activer_boutons_upload(ref);
              }
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur un bouton pour retirer un sujet ou un corrigé de devoir individuel pour un élève
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#eleve_fichier').on
    (
      'click',
      'button[id^=bouton_supprimer_eleve_]',
      function()
      {
        $('#analyse_import').html('');
        $('#eleve_fichier button').prop('disabled',true);
        $('#ajax_fichier_individuel_upload').attr('class','loader').html('En cours&hellip;');
        var tab_id    = $(this).attr('id').split('_');
        var doc_objet = tab_id[3];
        var eleve_id  = tab_id[4];
        var ref       = $('#uploader_ref').val();
        var indice    = ref+'_'+eleve_id;
        var url       = (doc_objet=='sujet') ? tab_sujet_perso[indice] : tab_corrige_perso[indice] ;
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=retirer_document'+'&f_doc_objet='+doc_objet+'&f_ref='+ref+'&f_eleve_id='+eleve_id+'&f_doc_url='+encodeURIComponent(url),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $('#ajax_fichier_individuel_upload').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              $('#eleve_fichier button').prop('disabled',false);
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              $('#eleve_fichier button').prop('disabled',false);
              if(responseJSON['statut']==false)
              {
                $('#ajax_fichier_individuel_upload').attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                $('#ajax_fichier_individuel_upload').attr('class','valide').html('Document retiré.');
                if(doc_objet=='sujet') { var alt='sujet';   tab_sujet_perso[indice] = ''; }
                else                   { var alt='corrigé'; tab_corrige_perso[indice] = ''; }
                var lien = '<img alt="'+alt+'" src="./_img/document/'+doc_objet+'_non.png">';
                $('#'+doc_objet+'_'+eleve_id).html(lien+' <button id="bouton_ajouter_eleve_'+doc_objet+'_'+eleve_id+'" type="button" class="ajouter">Ajouter</button>');
                // actualisation du nb de docs dans le tableau principal
                $('#devoir_'+ref).parent().addClass('new');
                var obj_span = $('#devoir_'+ref).prev().prev().children('span[data-objet='+doc_objet+'s]');
                var docs_nombre = entier(obj_span.data('nb')) - 1;
                obj_span.data('nb',docs_nombre);
                if(docs_nombre == 0)
                {
                  obj_span.html('');
                }
                else
                {
                  var s = (docs_nombre>1) ? 's' : '' ;
                  obj_span.html('<img alt="'+alt+'" src="./_img/document/'+doc_objet+'_multi.png"'+infobulle(docs_nombre+' '+alt+s+' individuel'+s)+'>');
                }
              }
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur un bouton pour ajouter un sujet ou un corrigé de devoir individuel pour un élève
    // Traitement du formulaire #form_upload_individuel : upload d’un fichier (avec jquery.form.js)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#eleve_fichier').on
    (
      'click',
      'button[id^=bouton_ajouter_eleve_]',
      function()
      {
        var tab_id   = $(this).attr('id').split('_');
        var objet    = tab_id[3];
        var eleve_id = tab_id[4];
        var ref      = $('#uploader_ref').val();
        var indice   = ref+'_'+eleve_id;
        // var url      = (objet=='sujet') ? tab_sujet_perso[indice] : tab_corrige_perso[indice] ;
        $('#f_upload_individuel_ref').val(ref);
        $('#f_upload_individuel_eleve_id').val(eleve_id);
        $('#f_upload_individuel_doc_objet').val(objet);
        $('#f_upload_individuel').click();
      }
    );

    // Le formulaire qui va être analysé et traité en AJAX
    var formulaire_document_individuel = $('#form_upload_individuel');

    // Options d’envoi du formulaire (avec jquery.form.js)
    var ajaxOptions_document_individuel =
    {
      url : 'ajax.php?page='+window.PAGE+'&csrf='+window.CSRF,
      type : 'POST',
      dataType : 'json',
      clearForm : false,
      resetForm : false,
      target : '#ajax_fichier_individuel_upload',
      error : retour_form_erreur_document_individuel,
      success : retour_form_valide_document_individuel
    };

    // Vérifications précédant l’envoi du formulaire, déclenchées au choix d’un fichier
    $('#f_upload_individuel').change
    (
      function()
      {
        var file = this.files[0];
        if( typeof(file) == 'undefined' )
        {
          $('#ajax_fichier_individuel_upload').removeAttr('class').html('');
          return false;
        }
        else
        {
          var fichier_nom = file.name;
          var fichier_ext = fichier_nom.split('.').pop().toLowerCase();
          var chaine_extensions = ('.'+window.extensions_interdites+'.').replaceAll('|','.');
          if( chaine_extensions.indexOf('.'+fichier_ext+'.') !== -1 )
          {
            $('#ajax_fichier_individuel_upload').attr('class','erreur').html('Format de fichier "'+fichier_ext+'" interdit.');
            return false;
          }
          else
          {
            $('#eleve_fichier button').prop('disabled',true);
            $('#ajax_fichier_individuel_upload').attr('class','loader').html('En cours&hellip;');
            formulaire_document_individuel.submit();
          }
        }
      }
    );

    // Envoi du formulaire (avec jquery.form.js)
    formulaire_document_individuel.submit
    (
      function()
      {
        $(this).ajaxSubmit(ajaxOptions_document_individuel);
        return false;
      }
    );

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_erreur_document_individuel(jqXHR, textStatus, errorThrown)
    {
      $('#f_upload_individuel').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      $('#eleve_fichier button').prop('disabled',false);
      $('#ajax_fichier_individuel_upload').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_valide_document_individuel(responseJSON)
    {
      $('#f_upload_individuel').clearFields(); // Sinon si on fournit de nouveau un fichier de même nom alors l’événement change() ne se déclenche pas
      if(responseJSON['statut']==false)
      {
        $('#ajax_fichier_individuel_upload').attr('class','alerte').html(responseJSON['value']);
      }
      else
      {
        initialiser_compteur();
        $('#ajax_fichier_individuel_upload').attr('class','valide').html('Document enregistré.');
        $('#'+responseJSON['td_id']).html(responseJSON['cell']);
        var doc_objet = $('#f_upload_individuel_doc_objet').val();
        if(doc_objet=='sujet')
          tab_sujet_perso[responseJSON['doc_ref']] = responseJSON['doc_url'];
        else
          tab_corrige_perso[responseJSON['doc_ref']] = responseJSON['doc_url'];
        // actualisation du nb de docs dans le tableau principal
        var ref = $('#f_upload_individuel_ref').val();
        $('#devoir_'+ref).parent().addClass('new');
        var obj_span = $('#devoir_'+ref).prev().prev().children('span[data-objet='+doc_objet+'s]');
        var docs_nombre = entier(obj_span.data('nb')) + 1;
        obj_span.data('nb',docs_nombre);
        var alt = (doc_objet=='sujet') ? 'sujet' : 'corrigé' ;
        var s = (docs_nombre>1) ? 's' : '' ;
        obj_span.html('<img alt="'+alt+'" src="./_img/document/'+doc_objet+'_multi.png"'+infobulle(docs_nombre+' '+alt+s+' individuel'+s)+'>');
      }
      $('#eleve_fichier button').prop('disabled',false);
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Vérifier si le masque saisi est correct
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function test_masque()
    {
      var masque = $('#f_masque').val();
      // Curieusement, besoin d’échapper l’échappement... (en PHP un échappement simple suffit)
      var reg_filename  = new RegExp('\\[(sconet_id|sconet_num|reference|nom|prenom|login|ent_id)\\]','g');
      var reg_extension = new RegExp('\\.('+window.extensions_interdites+')$','g');
      return( reg_filename.test(masque) && !reg_extension.test(masque) );
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Upload de sujets ou corrigés individuels par glisser-deposer (avec jQuery Ajax File Uploader Widget)
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    var count_success = -1;
    
    $('#zone_drop').dmUploader({
      url : 'ajax.php?page='+window.PAGE,
      dataType : 'json',
      extraData : { 'csrf' : window.CSRF , 'f_action' : 'envoyer_fichier' },
      fieldName : 'userfile',
      maxFileSize : window.FICHIER_TAILLE_MAX,
      onDragEnter: function(){this.addClass('hover');},
      onDragLeave: function(){this.removeClass('hover');},
      onNewFile: function(id, file){
        if(count_success<0)
        {
          if( !test_masque() )
          {
            $('#ajax_fichier_individuel_upload').attr('class','erreur').html('Indiquer correctement la forme des noms des fichiers.');
            $('#f_masque').focus();
            return false;
          }
          else if( !$('#f_nature_sujet').is(':checked') && !$('#f_nature_corrige').is(':checked') )
          {
            $('#ajax_fichier_individuel_upload').attr('class','erreur').html('Indiquer s’il s’agit d’énoncés ou de corrigés.');
            return false;
          }
          else
          {
            $('#ajax_fichier_individuel_upload').removeAttr('class').html('');
            count_success++; // le passer à zéro
            $('#analyse_import').html('<ul id="multi_upload" class="puce"></ul>');
          }
        }
        $('#multi_upload').prepend('<li>'+file.name+' <label id="label_'+id+'" class="loader">En attente...</label></li>');
      },
      onBeforeUpload: function(id){$('#label_'+id).html('Démarrage...');},
      onUploadProgress: function(id, percent){$('#label_'+id).html('En cours '+percent+'% ...');},
      onUploadSuccess: function(id, responseJSON){
        if(responseJSON['statut']==false)
        {
          $('#label_'+id).attr('class','erreur').html(responseJSON['value']);
        }
        else
        {
          initialiser_compteur();
          $('#label_'+id).attr('class','valide').html('Upload terminé.');
          count_success++;
        }
      },
      onUploadError: function(id, xhr, status, jqXHR, textStatus, errorThrown){
        $('#label_'+id).attr('style','color:red').html(afficher_json_message_erreur(jqXHR,textStatus));
      },
      onFallbackMode: function(){
        $('#ajax_fichier_individuel_upload').attr('class','alerte').html('Navigateur incompatible (trop ancien ?) avec cette fonctionnalité.</label>');
      },
      onFileSizeError: function(file){
        if(count_success<0)
        {
          count_success++; // le passer à zéro
          $('#analyse_import').html('<ul id="multi_upload" class="puce"></ul>');
        }
        $('#multi_upload').prepend('<li>'+file.name+' <label class="alerte">Taille &gt; '+window.FICHIER_TAILLE_MAX+' !</label></li>');
      },
      onComplete: function(){
        if(count_success)
        {
          $('#multi_upload').prepend('<li>Traitement des fichiers reçus <label id="label_ajax" class="loader">En cours&hellip;</label></li>');
          var masque    = $('#f_masque').val();
          var ref       = $('#uploader_ref').val();
          var doc_objet = $('input[name=f_nature]:checked').val();
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page='+window.PAGE,
              data : 'csrf='+window.CSRF+'&f_action=traiter_fichiers'+'&f_ref='+ref+'&f_doc_objet='+doc_objet+'&f_masque='+encodeURIComponent(masque),
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $('#label_ajax').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                if(responseJSON['statut']==false)
                {
                  $('#label_ajax').attr('class','alerte').html(responseJSON['value']);
                }
                else
                {
                  $('#label_ajax').parent().remove();
                  $('<ul class="puce">'+responseJSON['html']+'</ul><hr>').insertBefore('#multi_upload');
                  tab_cell          = JSON.parse(responseJSON['tab_cell']);
                  tab_sujet_perso   = JSON.parse(responseJSON['tab_sujet']);
                  tab_corrige_perso = JSON.parse(responseJSON['tab_corrige']);
                  for(var user_id in tab_cell)
                  {
                    $('#'+doc_objet+'_'+user_id).html(tab_cell[user_id]);
                  }
                  // actualisation du nb de docs dans le tableau principal
                  $('#devoir_'+ref).parent().addClass('new');
                  var obj_span = $('#devoir_'+ref).prev().prev().children('span[data-objet='+doc_objet+'s]');
                  var docs_nombre = $('#eleve_fichier').find('button[id^=bouton_supprimer_eleve_'+doc_objet+']').length;
                  obj_span.data('nb',docs_nombre);
                  if(docs_nombre == 0)
                  {
                    obj_span.html('');
                  }
                  else
                  {
                    var alt = (doc_objet=='sujet') ? 'sujet' : 'corrigé' ;
                    var s = (docs_nombre>1) ? 's' : '' ;
                    obj_span.html('<img alt="'+alt+'" src="./_img/document/'+doc_objet+'_multi.png"'+infobulle(docs_nombre+' '+alt+s+' individuel'+s)+'>');
                  }
                }
              }
            }
          );
        }
        count_success = -1;
        // $('#zone_drop').dmUploader('reset'); // retiré car sinon redéclenche onComplete et avec count_success > 0 ! mystère...
      }
    });

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du clic sur un checkbox pour déclarer (ou pas) une évaluation complète en saisie
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#table_action').on
    (
      'click',
      'a.fini',
      function()
      {
        var obj_lien = $(this);
        var txt_span = obj_lien.children('span').text();
        var txt_i    = obj_lien.children('i').text();
        var fini     = (txt_i=='terminé') ? 'oui' : 'non' ;
        var ref      = obj_lien.parent().next().attr('id').substring(7); // "devoir_" + ref
        $.ajax
        (
          {
            type : 'POST',
            url  : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=maj_fini'+'&f_fini='+fini+'&f_ref='+ref,
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+' Veuillez recommencer.'+'</label>' );
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              if(responseJSON['statut']==false)
              {
                $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
              }
              else
              {
                $('#devoir_'+ref).parent().addClass('new');
                if(fini=='oui') { obj_lien.html('<span>'+txt_i+'</span><i>'+txt_span+'</i>').parent().addClass('bf'); }
                else            { obj_lien.html('<span>'+txt_i+'</span><i>'+txt_span+'</i>').parent().removeClass('bf'); }
              }
              return false;
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Fonctions pour le traitement audio
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API/Using_the_MediaStream_Recording_API
     */

    var IsInitAudioContext = false;

    function initAudioContext()
    {
      try {
        log('log','Mise en place du contexte audio.');
        if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia)
        {
          log('log','Méthode mediaDevices.getUserMedia disponible.');
          $('#ajax_msg_enregistrer_audio').attr('class','alerte').html('Veuillez autoriser l’utilisation du microphone (voir en haut de la fenêtre)&hellip;');
          var MediaStreamConstraints = { audio: true };
          var MediaStreamOptions = { audioBitsPerSecond: 64000 }; // 128 bps par défaut mais 64 bps bien suffisants pour une voie parlée
          var audioChunks = [];
          var TimerRecordAudio = false;

          var MediaStreamOnSuccess = function (stream) {
            var mediaRecorder = new MediaRecorder(stream, MediaStreamOptions);
            log('log','Enregistreur initialisé.');
            $('#record_start').show();
            $('#ajax_msg_enregistrer_audio').removeAttr('class').html('');
            IsInitAudioContext = true;
      
            // ////////////////////////////////////////////////////////////////////////////////////////////////////
            // Fonctions gérant le décompte restant pour un enregistrement audio
            // ////////////////////////////////////////////////////////////////////////////////////////////////////

            function audio_compteur_play()
            {
              audio_duree_restante--;
              if(audio_duree_restante>0)
              {
                $('#ajax_msg_enregistrer_audio').attr('class','valide').html('Enregistrement en cours&hellip; Encore '+audio_duree_restante+'s maximum.');
              }
              else
              {
                $('#audio_enregistrer_stop').click();
              }
            }

            // ////////////////////////////////////////////////////////////////////////////////////////////////////
            // Actions sur les boutons audio
            // ////////////////////////////////////////////////////////////////////////////////////////////////////

            $('#audio_enregistrer_start').click
            (
              function()
              {
                $('#record_start , #record_play , #record_delete').hide();
                $('#fermer_enregistrer_audio').prop('disabled',true);
                $('#record_stop').show();
                mediaRecorder.start();
                log('log','Enregistrement en cours (statut "'+mediaRecorder.state+'")...');
                audio_duree_restante = window.AUDIO_DUREE_MAX;
                audio_compteur_play();
                TimerRecordAudio = setInterval( audio_compteur_play, 1000);
              }
            );

            $('#audio_enregistrer_stop').click
            (
              function()
              {
                clearInterval(TimerRecordAudio);
                $('#audio_enregistrer_stop').prop('disabled',true);
                $('#ajax_msg_enregistrer_audio').attr('class','loader').html('Traitement en cours&hellip;');
                mediaRecorder.stop();
              }
            );

            function uploadAudio(mp3Data){
              var reader = new FileReader();
              reader.onload = function(event){
                $('#enregistrer_audio_msg_data').val(event.target.result);
                $('#ajax_msg_enregistrer_audio').html('Transfert des données vers le serveur&hellip;');
                valider_enregistrer_audio(true);
              };
              reader.readAsDataURL(mp3Data);
            }
        
            mediaRecorder.onstop = function (e) {
              log('log','Enregistrement arrêté (statut "'+mediaRecorder.state+'").');
              var audioBlob = new Blob(audioChunks, {type: mediaRecorder.mimeType});
              $('#enregistrer_audio_mime_type').val(mediaRecorder.mimeType);
              log('log','Format de sortie : '+mediaRecorder.mimeType+'.');
              audioChunks = [];
              uploadAudio(audioBlob);
              var audioURL = window.URL.createObjectURL(audioBlob);
              $('#audio_lecture').attr('src',audioURL);
              $('#record_play, #record_delete').show();
            }

            mediaRecorder.ondataavailable = function (e) {
              audioChunks.push(e.data);
            };
          };

          var MediaStreamOnError = function (e) {
            log('error','Pas d’entrée audio en direct : ' + e);
            $('#ajax_msg_enregistrer_audio').attr('class','erreur').html('Utilisation du microphone rejetée&hellip; Veuillez l’autoriser puis recharger la page.');
            $('#record_start').hide();
          };

          navigator.mediaDevices.getUserMedia(MediaStreamConstraints).then(MediaStreamOnSuccess, MediaStreamOnError);
        }
        else
        {
          log('warn','Méthode mediaDevices.getUserMedia indisponible !');
          $('#ajax_msg_enregistrer_audio').attr('class','erreur').html('Ce navigateur ou son contexte ne gère pas l’enregistrement audio !');
        }
      } catch (e) {
        log('error','Ce navigateur ne gère pas l’enregistrement audio !');
        $('#ajax_msg_enregistrer_audio').attr('class','erreur').html('Ce navigateur ou son contexte ne gère pas l’enregistrement audio !');
        $('#record_start').hide();
      }
    };

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Clic sur une image pour ajouter ou modifier un commentaire audio ou texte
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function afficher_zone_enregistrer( msg_objet , user_id , msg_url , msg_data )
    {
      $('#enregistrer_'+msg_objet+'_msg_url').val( msg_url );
      if(msg_objet=='audio')
      {
        if(msg_data)
        {
          $('#audio_lecture').attr('src',msg_data);
          $('#record_play, #record_delete').show();
        }
        else
        {
          $('#record_play, #record_delete').hide();
        }
        $('#record_stop').hide();
        IsInitAudioContext || initAudioContext();
        $('#fermer_enregistrer_audio').prop('disabled',false);
      }
      else
      {
        $('#catalogue_f_msg_texte option:first').prop('selected',true);
      }
      // Afficher la zone
      $.fancybox( { href:'#zone_enregistrer_'+msg_objet , minWidth:800 , modal:true } );
      if(msg_objet=='texte')
      {
        $('#f_msg_texte').focus().val(msg_data);
        afficher_textarea_reste( $('#f_msg_texte') , nb_caracteres_max );
      }
      memo_eleve = user_id;
      // Déplacer le cadre photo
      $('#cadre_photo').prependTo('#zone_enregistrer_'+msg_objet);
      if($('#voir_photo').length==0)
      {
        charger_photo_eleve(memo_eleve,'maj');
      }
    }

    obj_table_saisir_voir.on
    (
      'click',
      'q',
      function()
      {
        var classe = $(this).attr('class');
        if( (classe=='texte_consulter_non') || (classe=='audio_ecouter_non') )
        {
          return false;
        }
        // Récupérer les informations
        var tab_infos = $(this).parent().attr('id').split('_');
        var msg_objet = tab_infos[0]; // texte | audio
        var user_id   = tab_infos[1];
        var dfn_user  = $('#dfn_'+user_id);
        var identite  = ( $('#saisir_voir_eleves_ordre').val()!='prenom' ) ? dfn_user.data('nom')+' '+dfn_user.data('prenom') : dfn_user.data('prenom')+' '+dfn_user.data('nom') ;
        var obj_autre = (msg_objet=='texte') ? 'audio' : 'texte' ;
        var msg_autre = ( $('#'+obj_autre+'_'+user_id).hasClass('off') ) ? 'oui' : 'non' ;
        var autoeval  = $('#autoeval_'+user_id).data('json');
        // Les reporter
        $('#titre_voir_commentaires').html( escapeHtml(identite) );
        $('#titre_enregistrer_'+msg_objet).html( escapeHtml(identite) );
        $('#enregistrer_'+msg_objet+'_ref').val( $('#saisir_voir_ref').val() );
        $('#enregistrer_'+msg_objet+'_eleve_id').val( user_id );
        $('#enregistrer_'+msg_objet+'_msg_autre').val( msg_autre );
        // Récupérer les items et les notes pour les avoir sous les yeux
        if(mode=='saisir')
        {
          catalogue_prenom = dfn_user.data('prenom');
          var tab_report = [];
          // Récupérer les données des items
          tab_report['item'] = [];
          obj_table_saisir_voir.find('tbody th').each
          (
            function()
            {
              tab_report['item'].push( $(this).children('b').text()+' '+$(this).children('div').text() );
            }
          );
          // Récupérer les saisies de l’élève
          tab_report['eleve'] = [];
          var id_colonne = $(this).attr('id').substring(5); // texteCiL | audioCiL
          obj_table_saisir_voir.find('tbody td input[id^='+id_colonne+']').each
          (
            function()
            {
              var obj_input = $(this);
              var obj_id    = obj_input.attr('id');
              var obj_class = obj_input.attr('class');
              var obj_name  = obj_input.attr('name');
              var obj_val   = obj_input.val();
              tab_report['eleve'].push( '<input type="text" class="'+obj_class+'" value="'+obj_val+'" id="copy_'+obj_id+'" data-id="'+obj_id+'" name="copy_'+obj_name+'" readonly>' );
            }
          );
          // On concatène tout ça
          var table_report = '<table class="scor_eval"><tbody class="h">';
          var i;
          for( i=0 ; i<tab_report['eleve'].length ; i+=1 )
          {
            var td_autoeval = (typeof(autoeval)=='undefined') ? '' : '<td'+infobulle('auto-évaluation')+'><input type="text" class="'+autoeval[i]+'" readonly disabled></td>' ;
            table_report += '<tr>'+td_autoeval+'<td>'+tab_report['eleve'][i]+'</td><th>'+tab_report['item'][i]+'</th></tr>';
          }
          table_report += '</tbody></table>';
          $('#report_tableau_'+msg_objet).html(table_report);
        }
        else
        {
          $('#report_tableau_'+msg_objet).html('');
        }
        // Récupérer (si besoin) le texte ou l’audio actuellement enregistré
        if(mode=='saisir')
        {
          if( $(this).parent().hasClass('off') )
          {
            $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
            $.ajax
            (
              {
                type : 'POST',
                url : 'ajax.php?page='+window.PAGE,
                data : 'csrf='+window.CSRF+'&f_action='+'recuperer_message'+'&f_ref='+$('#saisir_voir_ref').val()+'&f_eleve_id='+user_id+'&f_msg_objet='+msg_objet,
                dataType : 'json',
                error : function(jqXHR, textStatus, errorThrown)
                {
                  $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
                  return false;
                },
                success : function(responseJSON)
                {
                  initialiser_compteur();
                  if(responseJSON['statut']==false)
                  {
                    $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
                  }
                  else
                  {
                    afficher_zone_enregistrer( msg_objet , user_id , responseJSON['msg_url'] , responseJSON['msg_data'] );
                  }
                }
              }
            );
          }
          else
          {
            afficher_zone_enregistrer( msg_objet , user_id , '' /*msg_url*/ , '' /*msg_data*/ );
          }
        }
        else if(mode=='voir')
        {
          // Récupérer le texte ou l’audio actuellement enregistré
          $.fancybox( '<label class="loader">'+'En cours&hellip;'+'</label>' );
          $.ajax
          (
            {
              type : 'POST',
              url : 'ajax.php?page='+window.PAGE,
              data : 'csrf='+window.CSRF+'&f_action='+'recuperer_message'+'&f_ref='+$('#saisir_voir_ref').val()+'&f_eleve_id='+user_id+'&f_msg_objet='+msg_objet,
              dataType : 'json',
              error : function(jqXHR, textStatus, errorThrown)
              {
                $.fancybox( '<label class="alerte">'+afficher_json_message_erreur(jqXHR,textStatus)+'</label>' );
                return false;
              },
              success : function(responseJSON)
              {
                initialiser_compteur();
                if(responseJSON['statut']==false)
                {
                  $.fancybox( '<label class="alerte">'+responseJSON['value']+'</label>' );
                }
                else
                {
                  if(msg_objet=='texte')
                  {
                    $('#f_voir_texte').val(responseJSON['msg_data']);
                    $('#report_texte').show();
                    $('#report_audio').hide();
                  }
                  else
                  {
                    $('#f_ecouter_audio').attr('src',responseJSON['msg_data']);
                    $('#report_audio').show();
                    $('#report_texte').hide();
                  }
                  // Afficher la zone
                  $.fancybox( { href:'#zone_voir_commentaires' } );
                  if(msg_objet=='audio')
                  {
                    document.getElementById('f_ecouter_audio').play();
                  }
                }
              }
            }
          );
        }
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Gérer la saisie des résultats au clavier dans la fenêtre modale de saisie d’un commentaire
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#report_tableau_texte, #report_tableau_audio').on
    (
      'click',
      'tbody td input',
      function()
      {
        var input_id = $(this).data('id');
        colonne = entier( input_id.substring(1,input_id.indexOf('L')) );
        ligne   = entier( input_id.substring(input_id.indexOf('L')+1) );
      }
    );

    $('#report_tableau_texte, #report_tableau_audio').on
    (
      'keydown',  // keydown au lieu de keyup permet de laisser appuyer sur la touche pour répéter une action
      'tbody td input',
      function(e)
      {
        var input_id = $(this).data('id');
        colonne = entier( input_id.substring(1,input_id.indexOf('L')) );
        ligne   = entier( input_id.substring(input_id.indexOf('L')+1) );
        navigation_clavier_tableau_commentaire(e.which);
      }
    );

    function navigation_clavier_tableau_commentaire(touche_code)
    {
      var findme = '.'+touche_code+'.';
      if( window.keycode_search.indexOf(findme) != -1 )
      {
        // Une touche d’item a été pressée
        switch (touche_code)
        {
          case   8: var note = 'X' ; var style = note; break; // backspace
          case  46: var note = 'X' ; var style = note; break; // suppr
          case  65: var note = 'AB'; var style = note; break; // A
          case  68: var note = 'DI'; var style = note; break; // D
          case  78: var note = 'NN'; var style = note; break; // N
          case  69: var note = 'NE'; var style = note; break; // E
          case  70: var note = 'NF'; var style = note; break; // F
          case  82: var note = 'NR'; var style = note; break; // R
          case  80: var note = 'PA'; var style = note; break; // P
          default : var note = window.tab_keycode_note[touche_code]; var style = 'N'+note; break
        }
        // pour une seule case
        var case_ref = 'C'+colonne+'L'+ligne;
        $('#'+     case_ref).val(note).attr('class',style);
        $('#plan_'+case_ref).val(note).attr('class',style);
        $('#copy_'+case_ref).val(note).attr('class',style);
        $('#'+case_ref).parent().css('background-color','#F6D');
        if(modification==false)
        {
          $('#fermer_zone_saisir_voir').attr('class','annuler').html('Annuler / Retour');
          $('#kbd_27').attr('class','img annuler');
          modification = true;
          $(window).on('beforeunload', confirmOnLeave );
          $('#basculer_presentation').prop('disabled',true);
        }
        $('#ajax_msg_saisir_voir').removeAttr('class').html('');
        // cellule suivante
        ligne++;
        focus_cellule_suivante_tableau_commentaire();
      }
      else if('.37.38.39.40.'.indexOf(findme)!=-1)
      {
        // Une flèche a été pressée
        switch (touche_code)
        {
          case 37: ligne--; break; // flèche gauche
          case 38: ligne--; break; // flèche haut
          case 39: ligne++; break; // flèche droit
          case 40: ligne++; break; // flèche bas
        }
        focus_cellule_suivante_tableau_commentaire();
      }
      return false; // Evite notamment qu’IE fasse "page précédente" si on appuie sur backspace.
    }

    function focus_cellule_suivante_tableau_commentaire()
    {
      if(ligne==0)
      {
        ligne = nb_lignes;
      }
      else if(ligne>nb_lignes)
      {
        ligne = 1;
      }
      var new_id = 'C'+colonne+'L'+ligne;
      $('#copy_'+new_id).focus();
      valoriser_th(new_id);
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Indiquer le nombre de caractères restants autorisés dans le textarea
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // input permet d’intercepter à la fois les saisies au clavier et les copier-coller à la souris (clic droit)
    $('#zone_enregistrer_texte').on( 'input' , '#f_msg_texte' , function() { afficher_textarea_reste( $(this) , nb_caracteres_max ); } );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Valider ou Annuler la saisie d’un commentaire texte, ou passer à l’élève précédent / suivant
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function fermer_zone_enregistrer_texte(id_bouton)
    {
      $('#titre_enregistrer_texte').html('');
      $('#ajax_msg_enregistrer_texte').removeAttr('class').html('');
      var reg_avant = new RegExp('precedent$','g');
      var reg_apres = new RegExp('suivant$','g');
      var is_find_avant = reg_avant.test(id_bouton);
      var is_find_apres = reg_apres.test(id_bouton);
      if( is_find_avant || is_find_apres )
      {
        var eleve_id = $('#enregistrer_texte_eleve_id').val();
        var obj_td = $('#texte_'+eleve_id);
        if( is_find_apres )
        {
          var new_obj_td = obj_td.next('td');
          if( !new_obj_td.length )
          {
            var new_obj_td = obj_td.parent().children('td:first');
          }
        }
        else if( is_find_avant ) // forcément
        {
          var new_obj_td = obj_td.prev('td');
          if( !new_obj_td.length )
          {
            var new_obj_td = obj_td.parent().children('td:last');
          }
        }
        new_obj_td.children('q').click();
        return false;
      }
      // Déplacer le cadre photo
      $('#cadre_photo').prependTo('#zone_saisir_voir');
      $.fancybox.close();
    }

    $('#annuler_enregistrer_texte').click
    (
      function()
      {
        fermer_zone_enregistrer_texte('annuler_enregistrer_texte');
      }
    );

    $('#valider_enregistrer_texte , #valider_enregistrer_texte_precedent , #valider_enregistrer_texte_suivant').click
    (
      function()
      {
        var id_bouton = $(this).attr('id');
        var ref = $('#enregistrer_texte_ref').val();
        $('#zone_enregistrer_texte button').prop('disabled',true);
        $('#ajax_msg_enregistrer_texte').attr('class','loader').html('En cours&hellip;');
        $.ajax
        (
          {
            type : 'POST',
            url : 'ajax.php?page='+window.PAGE,
            data : 'csrf='+window.CSRF+'&f_action=enregistrer_texte'+'&f_prof_liste='+tab_profs[ref]+'&f_date_devoir='+$('#saisir_voir_date_devoir').val()+'&f_choix_saisie_visible='+$('#saisir_voir_choix_saisie_visible').val()+'&f_date_saisie_visible='+$('#saisir_voir_date_saisie_visible').val()+'&f_description='+encodeURIComponent($('#saisir_voir_description').val())+'&'+$('#zone_enregistrer_texte').serialize(),
            dataType : 'json',
            error : function(jqXHR, textStatus, errorThrown)
            {
              $('#zone_enregistrer_texte button').prop('disabled',false);
              $('#ajax_msg_enregistrer_texte').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
              return false;
            },
            success : function(responseJSON)
            {
              initialiser_compteur();
              $('#zone_enregistrer_texte button').prop('disabled',false);
              if(responseJSON['statut']==false)
              {
                $('#ajax_msg_enregistrer_texte').attr('class','alerte').html(responseJSON['value']);
              }
              else
              {
                $('#ajax_msg_enregistrer_texte').attr('class','valide').html('Commentaire enregistré !');
                var eleve_id = $('#enregistrer_texte_eleve_id').val();
                if(responseJSON['value']=='supprimé')
                {
                  $('#texte_'+eleve_id).removeAttr('class').children('q').attr('title','Saisir un commentaire écrit.');
                }
                else
                {
                  $('#enregistrer_texte_msg_url').val(responseJSON['value']);
                  $('#texte_'+eleve_id).addClass('off').children('q').attr('title','Modifier le commentaire écrit.');
                }
                fermer_zone_enregistrer_texte(id_bouton);
              }
            }
          }
        );
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Envoyer un commentaire audio
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    function valider_enregistrer_audio(is_audio)
    {
      var ref = $('#enregistrer_audio_ref').val();
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page='+window.PAGE,
          data : 'csrf='+window.CSRF+'&f_action=enregistrer_audio'+'&f_prof_liste='+tab_profs[ref]+'&f_date_devoir='+$('#saisir_voir_date_devoir').val()+'&f_choix_devoir_visible='+$('#saisir_voir_choix_devoir_visible').val()+'&f_date_devoir_visible='+$('#saisir_voir_date_devoir_visible').val()+'&f_choix_saisie_visible='+$('#saisir_voir_choix_saisie_visible').val()+'&f_date_saisie_visible='+$('#saisir_voir_date_saisie_visible').val()+'&f_description='+encodeURIComponent($('#saisir_voir_description').val())+'&'+$('#zone_enregistrer_audio').serialize(),
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $('#ajax_msg_enregistrer_audio').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
            $('#fermer_enregistrer_audio').prop('disabled',false);
            if(is_audio)
            {
              $('#audio_enregistrer_stop').prop('disabled',false);
              $('#record_stop').hide();
              $('#record_start').show();
            }
            else
            {
              $('#record_start , #record_play, #record_delete').show();
            }
            return false;
          },
          success : function(responseJSON)
          {
            initialiser_compteur();
            $('#fermer_enregistrer_audio').prop('disabled',false);
            if(responseJSON['statut']==false)
            {
              $('#ajax_msg_enregistrer_audio').attr('class','alerte').html(responseJSON['value']);
              if(is_audio)
              {
                $('#audio_enregistrer_stop').prop('disabled',false);
                $('#record_stop').hide();
                $('#record_start').show();
              }
              else
              {
                $('#record_start , #record_play, #record_delete').show();
              }
            }
            else
            {
              var eleve_id = $('#enregistrer_audio_eleve_id').val();
             if(responseJSON['value']=='supprimé')
              {
                $('#audio_'+eleve_id).removeAttr('class').children('q').attr('title','Enregistrer un commentaire audio.');
                $('#ajax_msg_enregistrer_audio').attr('class','valide').html('Commentaire supprimé !');
                $('#record_start').show();
              }
              else
              {
                $('#enregistrer_audio_msg_url').val(responseJSON['value']);
                $('#audio_'+eleve_id).addClass('off').children('q').attr('title','Modifier le commentaire audio.');
                $('#ajax_msg_enregistrer_audio').attr('class','valide').html('Commentaire enregistré !');
                $('#audio_enregistrer_stop').prop('disabled',false);
                $('#record_stop').hide();
                $('#record_start , #record_play, #record_delete').show();
              }
            }
          }
        }
      );
    }

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Supprimer un commentaire audio
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#audio_enregistrer_supprimer').click
    (
      function()
      {
        $('#enregistrer_audio_msg_data').val('');
        $('#record_start , #record_play, #record_delete').hide();
        $('#ajax_msg_enregistrer_audio').attr('class','loader').html('Suppression en cours&hellip;');
        valider_enregistrer_audio(false);
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Fermer la zone de gestion audio, ou passer à l’élève précédent / suivant
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $('#fermer_enregistrer_audio , #go_audio_precedent , #go_audio_suivant').click
    (
      function()
      {
        $('#titre_enregistrer_audio').html('');
        $('#ajax_msg_enregistrer_audio').removeAttr('class').html('');
        var id_bouton = $(this).attr('id');
        var reg_avant = new RegExp('precedent$','g');
        var reg_apres = new RegExp('suivant$','g');
        var is_find_avant = reg_avant.test(id_bouton);
        var is_find_apres = reg_apres.test(id_bouton);
        if( is_find_avant || is_find_apres )
        {
          var eleve_id = $('#enregistrer_audio_eleve_id').val();
          var obj_td = $('#audio_'+eleve_id);
          if( is_find_apres )
          {
            var new_obj_td = obj_td.next('td');
            if( !new_obj_td.length )
            {
              var new_obj_td = obj_td.parent().children('td:first');
            }
          }
          else if( is_find_avant ) // forcément
          {
            var new_obj_td = obj_td.prev('td');
            if( !new_obj_td.length )
            {
              var new_obj_td = obj_td.parent().children('td:last');
            }
          }
          new_obj_td.children('q').click();
          return false;
        }
        // Déplacer le cadre photo
        $('#cadre_photo').prependTo('#zone_saisir_voir');
        $.fancybox.close();
      }
    );

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Traitement du premier formulaire pour afficher le tableau avec la liste des évaluations
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Afficher / masquer des options de la grille (uniquement pour un groupe)

    var autoperiode = true; // Tant qu’on ne modifie pas manuellement le choix des périodes, modification automatique du formulaire

    function view_dates_perso()
    {
      var periode_val = $('#f_aff_periode').val();
      if(periode_val!=0)
      {
        $('#dates_perso').attr('class','hide');
      }
      else
      {
        $('#dates_perso').attr('class','show');
      }
    }

    $('#f_aff_periode').change
    (
      function()
      {
        view_dates_perso();
        autoperiode = false;
        // Soumettre le formulaire
        formulaire_prechoix.submit();
      }
    );

    // Changement de groupe (uniquement pour un groupe)
    // -> desactiver les périodes prédéfinies en cas de groupe de besoin
    // -> choisir automatiquement la meilleure période et chercher les évaluations si un changement manuel de période n’a jamais été effectué

    function modifier_periodes()
    {
      var groupe_type = $('#f_aff_classe option:selected').parent().attr('label');
      $('#f_aff_periode option').each
      (
        function()
        {
          var periode_id = $(this).val();
          // La période personnalisée est tout le temps accessible
          if(periode_id!=0)
          {
            // groupe de besoin -> desactiver les périodes prédéfinies
            if( (typeof(groupe_type)=='undefined') || (groupe_type=='Besoins') )
            {
              $(this).prop('disabled',true);
            }
            // classe ou groupe classique -> toutes périodes accessibles
            else
            {
              $(this).prop('disabled',false);
            }
          }
        }
      );
      // Sélectionner si besoin la période personnalisée
      if( (typeof(groupe_type)=='undefined') || (groupe_type=='Besoins') )
      {
        $('#f_aff_periode option[value=0]').prop('selected',true);
        $('#dates_perso').attr('class','show');
      }
      // Modification automatique du formulaire
      if( (groupe_type=='Classes') || (groupe_type=='Groupes') )
      {
        if(autoperiode)
        {
          // Rechercher automatiquement la meilleure période
          var id_classe = $('#f_aff_classe option:selected').val().substring(1);
          if(typeof(window.tab_groupe_periode[id_classe])!='undefined')
          {
            for(var id_periode in window.tab_groupe_periode[id_classe]) // Parcourir un tableau associatif...
            {
              var tab_split = window.tab_groupe_periode[id_classe][id_periode].split('_');
              if( (window.TODAY_SQL>=tab_split[0]) && (window.TODAY_SQL<=tab_split[1]) )
              {
                $('#f_aff_periode option[value='+id_periode+']').prop('selected',true);
                view_dates_perso();
                break;
              }
            }
          }
        }
      }
      // Soumettre le formulaire
      formulaire_prechoix.submit();
    }

    $('#f_eval_restriction_fini , #f_eval_restriction_proprio').change
    (
      function()
      {
        formulaire_prechoix.submit();
      }
    );

    $('#f_aff_classe').change
    (
      function()
      {
        modifier_periodes();
      }
    );

    // Le formulaire qui va être analysé et traité en AJAX
    var formulaire_prechoix = $('#form_prechoix');

    // Ajout d’une méthode pour valider les dates de la forme jj/mm/aaaa (trouvé dans le zip du plugin, corrige en plus un bug avec Safari)
    // méthode dateITA déjà ajoutée

    // Vérifier la validité du formulaire (avec jquery.validate.js)
    var validation_prechoix = formulaire_prechoix.validate
    (
      {
        rules :
        {
          f_aff_classe      : { required:true },
          f_date_debut      : { required:function(){return (window.TYPE=='selection') || $('#f_aff_periode').val()==0;} , dateITA:true },
          f_date_fin        : { required:function(){return (window.TYPE=='selection') || $('#f_aff_periode').val()==0;} , dateITA:true },
          f_aff_restriction : { required:true }
        },
        messages :
        {
          f_aff_classe      : { required:'classe / groupe manquant' },
          f_date_debut      : { required:'date manquante' , dateITA:'date JJ/MM/AAAA incorrecte' },
          f_date_fin        : { required:'date manquante' , dateITA:'date JJ/MM/AAAA incorrecte' },
          f_aff_restriction : { required:'choix manquant' }
        },
        errorElement : 'label',
        errorClass : 'erreur',
        errorPlacement : function(error,element)
        {
          if(element.is('select')) {element.after(error);}
          else if(element.attr('type')=='text') {element.next().after(error);}
        }
      }
    );

    // Options d’envoi du formulaire (avec jquery.form.js)
    var ajaxOptions_prechoix =
    {
      url : 'ajax.php?page='+window.PAGE+'&csrf='+window.CSRF,
      type : 'POST',
      dataType : 'json',
      clearForm : false,
      resetForm : false,
      target : '#ajax_msg_prechoix',
      beforeSubmit : test_form_avant_envoi_prechoix,
      error : retour_form_erreur_prechoix,
      success : retour_form_valide_prechoix
    };

    // Envoi du formulaire (avec jquery.form.js)
    formulaire_prechoix.submit
    (
      function()
      {
        $(this).ajaxSubmit(ajaxOptions_prechoix);
        return false;
      }
    );

    // Fonction précédant l’envoi du formulaire (avec jquery.form.js)
    function test_form_avant_envoi_prechoix(formData, jqForm, options)
    {
      $('#ajax_msg_prechoix').removeAttr('class').html('');
      var readytogo = validation_prechoix.form();
      if(readytogo)
      {
        $('#ajax_msg_prechoix').attr('class','loader').html('En cours&hellip;');
      }
      return readytogo;
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_erreur_prechoix(jqXHR, textStatus, errorThrown)
    {
      $('#ajax_msg_prechoix').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
    }

    // Fonction suivant l’envoi du formulaire (avec jquery.form.js)
    function retour_form_valide_prechoix(responseJSON)
    {
      initialiser_compteur();
      if(responseJSON['statut']==false)
      {
        $('#ajax_msg_prechoix').attr('class','alerte').html(responseJSON['value']);
      }
      else
      {
        $('#ajax_msg_prechoix').attr('class','valide').html('Demande réalisée !').fadeOut(3000,function(){$(this).removeAttr('class').html('').show();});
        $('#table_action tbody').html( responseJSON['html'] );
        tab_items   = JSON.parse(responseJSON['tab_items']);
        tab_profs   = JSON.parse(responseJSON['tab_profs']);
        tab_sujet   = JSON.parse(responseJSON['tab_sujet']);
        tab_corrige = JSON.parse(responseJSON['tab_corrige']);
        tab_eleves  = JSON.parse(responseJSON['tab_eleves']);
        tableau_maj();
        if( window.reception_todo )
        {
          $('q.ajouter').click();
        }
        if( window.reception_module_import )
        {
          $('q.module_recevoir').click();
        }
        // Afficher des résultats au chargement
        if(window.auto_voir_devoir_id && window.auto_voir_groupe_type && window.auto_voir_groupe_id)
        {
          if( $('#devoir_'+window.auto_voir_devoir_id+'_'+window.auto_voir_groupe_type+window.auto_voir_groupe_id).length )
          {
            saisir_ou_voir();
          }
          else
          {
            window.auto_voir_devoir_id = false;
            window.auto_voir_groupe_id = false;
          }
        }
      }
    }

    // N’afficher les éléments qu’une fois le js bien chargé...
    $('#form_prechoix , #table_action').show('fast');

    // Et charger par défaut les dernières évaluations du prof.
    $('#form_prechoix').submit();

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Élement saisissable / déplaçable
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    $( '#cadre_tactile' ).draggable({cursor:'move'});

    // ////////////////////////////////////////////////////////////////////////////////////////////////////
    // Initialisation
    // ////////////////////////////////////////////////////////////////////////////////////////////////////

    // Récupéré après le chargement de la page car potentiellement lourd pour les directeurs et les PP (bloque l’affichage plusieurs secondes)
    if( (window.PROFIL_TYPE=='professeur') || (window.PROFIL_TYPE=='directeur') )
    {
      $.ajax
      (
        {
          type : 'POST',
          url : 'ajax.php?page=_load_arborescence',
          data : 'f_objet=referentiels'+'&f_item_comm=1'+'&f_all_if_pp=0',
          dataType : 'json',
          error : function(jqXHR, textStatus, errorThrown)
          {
            $('#arborescence label').attr('class','alerte').html(afficher_json_message_erreur(jqXHR,textStatus));
            return false;
          },
          success : function(responseJSON)
          {
            $('#arborescence').replaceWith(responseJSON['value']);
          }
        }
      );
    }

  }
);
